From 6fc159fc213fffc71a2c0bce2beccd6ed700425c Mon Sep 17 00:00:00 2001 From: Dominique Date: Tue, 2 Apr 2024 13:36:18 +0200 Subject: [PATCH] Dom fix controls (#160) * fixed #158 and #159 --- ptmd/lib/validator/core.py | 30 ++++++++++- tests/test_lib/test_validator/test_core.py | 58 ++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/ptmd/lib/validator/core.py b/ptmd/lib/validator/core.py index 37ec967..90bc61d 100644 --- a/ptmd/lib/validator/core.py +++ b/ptmd/lib/validator/core.py @@ -170,7 +170,7 @@ class VerticalValidator: def __init__(self, definitions: dict, validator: ExcelValidator) -> None: """ The validator constructor. """ - self.controls_keys: list[str] = ['CONTROL (DMSO)', 'CONTROL (WATER)'] + self.controls_keys: list[str] = ['CONTROL (DMSO)', 'CONTROL (Water)'] self.validator: ExcelValidator = validator self.timepoints: list = definitions['timepoints'] self.replicates: int = definitions['replicates'] @@ -263,6 +263,10 @@ def validate(self) -> None: if compound_name == 'EXTRACTION BLANK': break + if compound_name in self.controls_keys: + self.validate_controls(compound_val) + break + for timepoint in compound_val['replicates']: if timepoint in self.timepoints: replicate: int = compound_val['replicates'][timepoint] @@ -283,3 +287,27 @@ def validate(self) -> None: elif timepoint < len(self.timepoints): message = f"Timepoint {replicate} is missing {len(self.timepoints) - timepoint} replicate(s)." self.validator.add_error(compound_name, message, 'replicates') + + def validate_controls(self, compound_values: dict) -> None: + """ Validates the controls points against the general information. Verify the number of replicates and + timepoints. + + :param compound_values: The compound values to validate. + """ + message: str + for timepoint, replicate in compound_values['replicates'].items(): + if replicate < self.controls: + message = f"Control at timepoint {timepoint} is missing {self.controls - replicate} replicate(s)." + self.validator.add_error('Control', message, 'replicates') + elif replicate > self.controls: + message = f"Control at timepoint {timepoint} has too many replicates ({replicate})." + self.validator.add_error('Control', message, 'replicates') + + for replicate, timepoint in compound_values['timepoints'].items(): + if timepoint > len(self.timepoints): + message = f"Timepoint {replicate} has greater number of controls {timepoint} " \ + f"than expected ({self.controls})." + self.validator.add_error('Control', message, 'timepoints') + elif timepoint < len(self.timepoints): + message = f"Timepoint {replicate} is missing {len(self.timepoints) - timepoint} control(s)." + self.validator.add_error('Control', message, 'timepoints') diff --git a/tests/test_lib/test_validator/test_core.py b/tests/test_lib/test_validator/test_core.py index 2944d9c..f5cfac9 100644 --- a/tests/test_lib/test_validator/test_core.py +++ b/tests/test_lib/test_validator/test_core.py @@ -287,3 +287,61 @@ def test_validate_failed_box_id(self): } self.assertFalse(validator.report['valid']) self.assertEqual(validator.report['errors'], expected_error) + + def test_validate_failed_too_many_controls(self): + validator = MockValidator() + self.general_information['controls'] = 1 + self.general_information['timepoints'] = [4] + vertical_validator = VerticalValidator(self.general_information, validator) + vertical_validator.add_node({ + 'data': { + 'compound_name': 'CONTROL (Water)', + 'replicate': 1, + 'timepoint_(hours)': 4, + 'dose_code': 0, + 'box_id': 'Box1', + 'box_column': 1, + 'box_row': 'A', + 'collection_order': 1 + }, + 'label': 'CP1' + }) + vertical_validator.add_node({ + 'data': { + 'compound_name': 'CONTROL (Water)', + 'replicate': 2, + 'timepoint_(hours)': 4, + 'dose_code': 0, + 'box_id': 'Box1', + 'box_column': 1, + 'box_row': 'B', + 'collection_order': 2 + }, + 'label': 'CP2' + }) + vertical_validator.validate() + errors = validator.report['errors'] + self.assertEqual(errors['CP2'][0]['message'], 'Control 2 is greater than the number of controls 1.') + self.assertEqual(errors['Control'][0]['message'], 'Control at timepoint 4 has too many replicates (2).') + + def test_validate_failed_not_enough_controls(self): + validator = MockValidator() + self.general_information['controls'] = 1 + self.general_information['timepoints'] = [4, 12] + vertical_validator = VerticalValidator(self.general_information, validator) + vertical_validator.add_node({ + 'data': { + 'compound_name': 'CONTROL (Water)', + 'replicate': 1, + 'timepoint_(hours)': 4, + 'dose_code': 0, + 'box_id': 'Box1', + 'box_column': 1, + 'box_row': 'A', + 'collection_order': 1 + }, + 'label': 'CP1' + }) + vertical_validator.validate() + errors = validator.report['errors'] + self.assertEqual(errors['Control'][0]['message'], 'Timepoint 1 is missing 1 control(s).')