diff --git a/cg/models/lims/sample.py b/cg/models/lims/sample.py index 41569e804f..328b016ff7 100644 --- a/cg/models/lims/sample.py +++ b/cg/models/lims/sample.py @@ -1,4 +1,5 @@ -from pydantic.v1 import BaseModel, validator +from pydantic import BaseModel, field_validator +from pydantic_core.core_schema import ValidationInfo from typing_extensions import Literal from cg.constants import Priority @@ -8,69 +9,70 @@ class Udf(BaseModel): application: str - capture_kit: str | None - collection_date: str | None - comment: str | None - concentration: str | None - concentration_sample: str | None - concentration_ng_ul: str | None + capture_kit: str | None = None + collection_date: str | None = None + comment: str | None = None + concentration: float | None = None + concentration_ng_ul: str | None = None + concentration_sample: float | None = None + control: str | None = None customer: str - control: str | None - data_analysis: str | None - data_delivery: str | None - elution_buffer: str | None - extraction_method: str | None + data_analysis: str | None = None + data_delivery: str | None = None + elution_buffer: str | None = None + extraction_method: str | None = None family_name: str | None = "NA" - formalin_fixation_time: str | None - index: str | None - index_number: str | None - lab_code: str | None - organism: str | None - organism_other: str | None - original_lab: str | None - original_lab_address: str | None - pool: str | None - post_formalin_fixation_time: str | None - pre_processing_method: str | None - primer: str | None + formalin_fixation_time: float | None = None + index: str | None = None + index_number: str | None = None + lab_code: str | None = None + organism: str | None = None + organism_other: str | None = None + original_lab: str | None = None + original_lab_address: str | None = None + pool: str | None = None + post_formalin_fixation_time: float | None = None + pre_processing_method: str | None = None + primer: str | None = None priority: str = Priority.standard.name - quantity: str | None - reference_genome: str | None - region: str | None - region_code: str | None + quantity: float | None = None + reference_genome: str | None = None + region: str | None = None + region_code: str | None = None require_qc_ok: bool = False - rml_plate_name: str | None - selection_criteria: str | None + rml_plate_name: str | None = None + selection_criteria: str | None = None sex: Literal["M", "F", "unknown"] = "unknown" skip_reception_control: bool | None = None source: str = "NA" - tissue_block_size: str | None + tissue_block_size: str | None = None tumour: bool | None = False - tumour_purity: str | None - volume: str | None - well_position_rml: str | None - verified_organism: bool | None + tumour_purity: float | None = None + verified_organism: bool | None = None + volume: str | None = None + well_position_rml: str | None = None - @validator("sex", pre=True) + @field_validator("sex", mode="before") + @classmethod def validate_sex(cls, value: str): return SEX_MAP.get(value, "unknown") class LimsSample(BaseModel): - name: str container: str = "Tube" - container_name: str | None - well_position: str | None - index_sequence: str | None - udfs: Udf | None + container_name: str | None = None + index_sequence: str | None = None + name: str + udfs: Udf | None = None + well_position: str | None = None - @validator("well_position", pre=False) - def reset_well_positions_for_tubes(cls, value: str, values: dict[str, str]): - return None if values["container"] == "Tube" else value + @field_validator("well_position", mode="before") + def reset_well_positions_for_tubes(cls, value: str, info: ValidationInfo): + return None if info.data.get("container") == "Tube" else value @classmethod def parse_obj(cls, obj: dict): - parsed_obj: LimsSample = super().parse_obj(obj) - udf: Udf = Udf.parse_obj(obj) - parsed_obj.udfs = udf - return parsed_obj + lims_sample: LimsSample = super().model_validate(obj) + udf: Udf = Udf.model_validate(obj) + lims_sample.udfs = udf + return lims_sample diff --git a/tests/fixtures/cgweb_orders/balsamic.json b/tests/fixtures/cgweb_orders/balsamic.json index 17179dde03..cf3808e7df 100644 --- a/tests/fixtures/cgweb_orders/balsamic.json +++ b/tests/fixtures/cgweb_orders/balsamic.json @@ -18,7 +18,7 @@ "data_delivery": "fastq-analysis-scout", "elution_buffer": "Other (specify in 'Comments')", "family_name": "family1", - "formalin_fixation_time": "1", + "formalin_fixation_time": 1, "name": "s1", "phenotype_groups": [ "" @@ -26,7 +26,7 @@ "phenotype_terms": [ "" ], - "post_formalin_fixation_time": "2", + "post_formalin_fixation_time": 2, "priority": "standard", "quantity": "2", "sex": "male", @@ -35,7 +35,7 @@ "synopsis": "", "tissue_block_size": "small", "tumour": true, - "tumour_purity": "75", + "tumour_purity": 75, "volume": "1", "well_position": "A:1" } diff --git a/tests/services/orders/order_lims_service/test_order_lims_service.py b/tests/services/orders/order_lims_service/test_order_lims_service.py index c22499242b..03bbd6a7d0 100644 --- a/tests/services/orders/order_lims_service/test_order_lims_service.py +++ b/tests/services/orders/order_lims_service/test_order_lims_service.py @@ -1,3 +1,5 @@ +import math + import pytest from cg.constants import Workflow @@ -32,7 +34,7 @@ def test_to_lims_mip(mip_order_to_submit): assert first_sample.udfs.priority == "standard" assert first_sample.udfs.application == "WGSPCFC030" assert first_sample.udfs.source == "tissue (fresh frozen)" - assert first_sample.udfs.quantity == "220" + assert first_sample.udfs.quantity == 220 assert first_sample.udfs.customer == "cust003" assert first_sample.udfs.volume == "1.0" @@ -74,7 +76,7 @@ def test_to_lims_rml(rml_order_to_submit): first_sample = samples[0] assert first_sample.udfs.pool == "pool-1" assert first_sample.udfs.volume == "30" - assert first_sample.udfs.concentration == "5.0" + assert math.isclose(first_sample.udfs.concentration, 5.0, rel_tol=1e-09, abs_tol=1e-09) assert first_sample.udfs.index == "IDT DupSeq 10 bp Set B" assert first_sample.udfs.index_number == "1" @@ -151,7 +153,7 @@ def test_to_lims_balsamic(balsamic_order_to_submit, project): # ... and pick out relevant UDFs first_sample = samples[0].dict() assert first_sample["name"] == "s1" - assert {sample.container for sample in samples} == set(["96 well plate"]) + assert {sample.container for sample in samples} == {"96 well plate"} assert first_sample["udfs"]["data_analysis"] in [ Workflow.BALSAMIC, Workflow.BALSAMIC_QC, @@ -165,15 +167,15 @@ def test_to_lims_balsamic(balsamic_order_to_submit, project): assert first_sample["udfs"]["volume"] == "1.0" assert first_sample["udfs"]["priority"] == "standard" - assert container_names == set(["p1"]) + assert container_names == {"p1"} assert first_sample["well_position"] == "A:1" assert first_sample["udfs"]["tumour"] is True assert first_sample["udfs"]["capture_kit"] == "other" - assert first_sample["udfs"]["tumour_purity"] == "75" + assert first_sample["udfs"]["tumour_purity"] == 75 - assert first_sample["udfs"]["formalin_fixation_time"] == "1" - assert first_sample["udfs"]["post_formalin_fixation_time"] == "2" + assert first_sample["udfs"]["formalin_fixation_time"] == 1 + assert first_sample["udfs"]["post_formalin_fixation_time"] == 2 assert first_sample["udfs"]["tissue_block_size"] == "small" - assert first_sample["udfs"]["quantity"] == "2" + assert first_sample["udfs"]["quantity"] == 2 assert first_sample["udfs"]["comment"] == "other Elution buffer"