-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add balsamic sample sex validation (#3665)
- Loading branch information
Showing
9 changed files
with
163 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
cg/services/order_validation_service/workflows/balsamic/rules/case_sample/rules.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from cg.services.order_validation_service.errors.case_sample_errors import SexSubjectIdError | ||
from cg.services.order_validation_service.workflows.balsamic.models.order import BalsamicOrder | ||
from cg.services.order_validation_service.workflows.balsamic.rules.case_sample.utils import ( | ||
has_sex_and_subject, | ||
) | ||
from cg.store.store import Store | ||
|
||
|
||
def validate_subject_sex_consistency( | ||
order: BalsamicOrder, | ||
store: Store, | ||
) -> list[SexSubjectIdError]: | ||
errors: list[SexSubjectIdError] = [] | ||
|
||
for case_index, case in order.enumerated_new_cases: | ||
for sample_index, sample in case.enumerated_new_samples: | ||
if not has_sex_and_subject(sample): | ||
continue | ||
|
||
if store.sample_exists_with_different_sex( | ||
customer_internal_id=order.customer, | ||
subject_id=sample.subject_id, | ||
sex=sample.sex, | ||
): | ||
error = SexSubjectIdError( | ||
case_index=case_index, | ||
sample_index=sample_index, | ||
) | ||
errors.append(error) | ||
return errors |
8 changes: 8 additions & 0 deletions
8
cg/services/order_validation_service/workflows/balsamic/rules/case_sample/utils.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from cg.models.orders.sample_base import SexEnum | ||
from cg.services.order_validation_service.workflows.balsamic.models.sample import ( | ||
BalsamicSample, | ||
) | ||
|
||
|
||
def has_sex_and_subject(sample: BalsamicSample) -> bool: | ||
return bool(sample.subject_id and sample.sex != SexEnum.unknown) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
55 changes: 55 additions & 0 deletions
55
tests/services/order_validation_service/workflows/balsamic/conftest.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import pytest | ||
|
||
from cg.constants.constants import GenomeVersion, Workflow | ||
from cg.models.orders.sample_base import ContainerEnum, ControlEnum, SexEnum, StatusEnum | ||
from cg.services.order_validation_service.constants import MINIMUM_VOLUME | ||
from cg.services.order_validation_service.workflows.balsamic.constants import BalsamicDeliveryType | ||
from cg.services.order_validation_service.workflows.balsamic.models.case import BalsamicCase | ||
from cg.services.order_validation_service.workflows.balsamic.models.order import BalsamicOrder | ||
from cg.services.order_validation_service.workflows.balsamic.models.sample import BalsamicSample | ||
|
||
|
||
def create_sample(id: int) -> BalsamicSample: | ||
return BalsamicSample( | ||
name=f"name{id}", | ||
application="PANKTTR020", | ||
container=ContainerEnum.plate, | ||
container_name="ContainerName", | ||
control=ControlEnum.not_control, | ||
require_qc_ok=True, | ||
reference_genome=GenomeVersion.HG19, | ||
sex=SexEnum.female, | ||
source="source", | ||
status=StatusEnum.affected, | ||
subject_id=f"subject{id}", | ||
well_position=f"A:{id}", | ||
volume=MINIMUM_VOLUME, | ||
is_tumour=False, | ||
) | ||
|
||
|
||
def create_case(samples: list[BalsamicSample]) -> BalsamicCase: | ||
return BalsamicCase( | ||
name="name", | ||
samples=samples, | ||
) | ||
|
||
|
||
def create_order(cases: list[BalsamicCase]) -> BalsamicOrder: | ||
return BalsamicOrder( | ||
connect_to_ticket=True, | ||
delivery_type=BalsamicDeliveryType.FASTQ_ANALYSIS, | ||
name="order_name", | ||
ticket_number="#12345", | ||
workflow=Workflow.BALSAMIC, | ||
user_id=1, | ||
customer="cust000", | ||
cases=cases, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def valid_order() -> BalsamicOrder: | ||
sample = create_sample(1) | ||
case = create_case([sample]) | ||
return create_order([case]) |
32 changes: 32 additions & 0 deletions
32
tests/services/order_validation_service/workflows/balsamic/test_case_sample_rules.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from cg.models.orders.sample_base import SexEnum | ||
from cg.services.order_validation_service.errors.case_sample_errors import SexSubjectIdError | ||
from cg.services.order_validation_service.workflows.balsamic.models.order import BalsamicOrder | ||
from cg.services.order_validation_service.workflows.balsamic.rules.case_sample.rules import ( | ||
validate_subject_sex_consistency, | ||
) | ||
from cg.store.models import Sample | ||
from cg.store.store import Store | ||
|
||
|
||
def test_validate_sex_subject_id_clash(valid_order: BalsamicOrder, sample_store: Store): | ||
# GIVEN an existing sample | ||
sample = sample_store.session.query(Sample).first() | ||
|
||
# GIVEN an order and sample with the same customer and subject id | ||
valid_order.customer = sample.customer.internal_id | ||
valid_order.cases[0].samples[0].subject_id = "subject" | ||
sample.subject_id = "subject" | ||
|
||
# GIVEN a sample in the order that has a different sex | ||
valid_order.cases[0].samples[0].sex = SexEnum.female | ||
sample.sex = SexEnum.male | ||
|
||
# WHEN validating the order | ||
errors = validate_subject_sex_consistency( | ||
order=valid_order, | ||
store=sample_store, | ||
) | ||
|
||
# THEN an error should be given for the clash | ||
assert errors | ||
assert isinstance(errors[0], SexSubjectIdError) |