Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(update): Pydantic model #3828

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 50 additions & 48 deletions cg/models/lims/sample.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value will populate the text UDF "Quantity" in LIMS. It could be good to test that it doesn't break something

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
6 changes: 3 additions & 3 deletions tests/fixtures/cgweb_orders/balsamic.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
"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": [
""
],
"phenotype_terms": [
""
],
"post_formalin_fixation_time": "2",
"post_formalin_fixation_time": 2,
"priority": "standard",
"quantity": "2",
"sex": "male",
Expand All @@ -35,7 +35,7 @@
"synopsis": "",
"tissue_block_size": "small",
"tumour": true,
"tumour_purity": "75",
"tumour_purity": 75,
"volume": "1",
"well_position": "A:1"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import math

import pytest

from cg.constants import Workflow
Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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,
Expand All @@ -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"
Loading