diff --git a/src/submissions/backend/db/models/kits.py b/src/submissions/backend/db/models/kits.py index 12b577b..b8e14d7 100644 --- a/src/submissions/backend/db/models/kits.py +++ b/src/submissions/backend/db/models/kits.py @@ -1520,6 +1520,9 @@ class Process(BaseClass): class TipRole(BaseClass): + """ + An abstract role that a tip fills during a process + """ id = Column(INTEGER, primary_key=True) #: primary key name = Column(String(64)) #: name of reagent type instances = relationship("Tips", back_populates="role", @@ -1539,6 +1542,9 @@ class TipRole(BaseClass): class Tips(BaseClass): + """ + A concrete instance of tips. + """ id = Column(INTEGER, primary_key=True) #: primary key role = relationship("TipRole", back_populates="instances", secondary=tiproles_tips) #: joined parent reagent type @@ -1560,7 +1566,18 @@ class Tips(BaseClass): return f"" @classmethod - def query(cls, name: str | None = None, lot: str | None = None, limit: int = 0, **kwargs) -> Any | List[Any]: + def query(cls, name: str | None = None, lot: str | None = None, limit: int = 0, **kwargs) -> Tips | List[Tips]: + """ + Lookup tips + + Args: + name (str | None, optional): Informal name of tips. Defaults to None. + lot (str | None, optional): Lot number. Defaults to None. + limit (int, optional): Maximum number of results to return (0=all). Defaults to 0. + + Returns: + Tips | List[Tips]: Tips matching criteria + """ query = cls.__database_session__.query(cls) match name: case str(): @@ -1595,6 +1612,9 @@ class SubmissionTypeTipRoleAssociation(BaseClass): class SubmissionTipsAssociation(BaseClass): + """ + Association between a concrete submission instance and concrete tips + """ tip_id = Column(INTEGER, ForeignKey("_tips.id"), primary_key=True) #: id of associated equipment submission_id = Column(INTEGER, ForeignKey("_basicsubmission.id"), primary_key=True) #: id of associated submission submission = relationship("BasicSubmission", @@ -1605,5 +1625,11 @@ class SubmissionTipsAssociation(BaseClass): # role = relationship(TipRole) - def to_sub_dict(self): + def to_sub_dict(self) -> dict: + """ + This item as a dictionary + + Returns: + dict: Values of this object + """ return dict(role=self.role_name, name=self.tips.name, lot=self.tips.lot) diff --git a/src/submissions/backend/db/models/submissions.py b/src/submissions/backend/db/models/submissions.py index ecd45c5..33daa01 100644 --- a/src/submissions/backend/db/models/submissions.py +++ b/src/submissions/backend/db/models/submissions.py @@ -2576,6 +2576,10 @@ class SubmissionSampleAssociation(BaseClass): class WastewaterAssociation(SubmissionSampleAssociation): + """ + table containing wastewater specific submission/sample associations + DOC: https://docs.sqlalchemy.org/en/14/orm/extensions/associationproxy.html + """ id = Column(INTEGER, ForeignKey("_submissionsampleassociation.id"), primary_key=True) ct_n1 = Column(FLOAT(2)) #: AKA ct for N1 ct_n2 = Column(FLOAT(2)) #: AKA ct for N2 @@ -2635,7 +2639,10 @@ class WastewaterAssociation(SubmissionSampleAssociation): class WastewaterArticAssociation(SubmissionSampleAssociation): - + """ + table containing wastewater artic specific submission/sample associations + DOC: https://docs.sqlalchemy.org/en/14/orm/extensions/associationproxy.html + """ id = Column(INTEGER, ForeignKey("_submissionsampleassociation.id"), primary_key=True) source_plate = Column(String(16)) source_plate_number = Column(INTEGER) diff --git a/src/submissions/backend/excel/parser.py b/src/submissions/backend/excel/parser.py index 86f07da..001a89d 100644 --- a/src/submissions/backend/excel/parser.py +++ b/src/submissions/backend/excel/parser.py @@ -68,7 +68,6 @@ class SheetParser(object): parser = InfoParser(xl=self.xl, submission_type=self.submission_type, sub_object=self.sub_object) info = parser.parse_info() self.info_map = parser.map - # exclude_from_info = BasicSubmission.find_polymorphic_subclass(polymorphic_identity=self.sub['submission_type']).exclude_from_info_parser() for k, v in info.items(): match k: case "sample": @@ -96,7 +95,6 @@ class SheetParser(object): """ parser = SampleParser(xl=self.xl, submission_type=self.submission_type) self.sub['samples'] = parser.reconcile_samples() - # self.plate_map = parser.plate_map def parse_equipment(self): parser = EquipmentParser(xl=self.xl, submission_type=self.submission_type) @@ -126,8 +124,6 @@ class SheetParser(object): """ Run custom final validations of data for submission subclasses. """ - # finisher = BasicSubmission.find_polymorphic_subclass( - # polymorphic_identity=self.sub['submission_type']).finalize_parse self.sub = self.sub_object.finalize_parse(input_dict=self.sub, xl=self.xl, info_map=self.info_map) def to_pydantic(self) -> PydSubmission: @@ -264,16 +260,15 @@ class ReagentParser(object): if isinstance(extraction_kit, dict): extraction_kit = extraction_kit['value'] self.kit_object = KitType.query(name=extraction_kit) - self.map = self.fetch_kit_info_map(extraction_kit=extraction_kit, submission_type=submission_type) + self.map = self.fetch_kit_info_map(submission_type=submission_type) # logger.debug(f"Reagent Parser map: {self.map}") self.xl = xl - def fetch_kit_info_map(self, extraction_kit: dict, submission_type: str) -> dict: + def fetch_kit_info_map(self, submission_type: str) -> dict: """ Gets location of kit reagents from database Args: - extraction_kit (dict): Relevant kit information. submission_type (str): Name of submission type. Returns: @@ -388,47 +383,6 @@ class SampleParser(object): sample_info_map = sample_map return sample_info_map - # def construct_plate_map(self, plate_map_location: dict) -> pd.DataFrame: - # """ - # Gets location of samples from plate map grid in excel sheet. - # - # Args: - # plate_map_location (dict): sheet name, start/end row/column - # - # Returns: - # pd.DataFrame: Plate map grid - # """ - # logger.debug(f"Plate map location: {plate_map_location}") - # df = self.xl.parse(plate_map_location['sheet'], header=None, dtype=object) - # df = df.iloc[plate_map_location['start_row'] - 1:plate_map_location['end_row'], - # plate_map_location['start_column'] - 1:plate_map_location['end_column']] - # df = pd.DataFrame(df.values[1:], columns=df.iloc[0]) - # df = df.set_index(df.columns[0]) - # logger.debug(f"Vanilla platemap: {df}") - # # custom_mapper = BasicSubmission.find_polymorphic_subclass(polymorphic_identity=self.submission_type) - # df = self.sub_object.custom_platemap(self.xl, df) - # # logger.debug(f"Custom platemap:\n{df}") - # return df - # - # def construct_lookup_table(self, lookup_table_location: dict) -> pd.DataFrame: - # """ - # Gets table of misc information from excel book - # - # Args: - # lookup_table_location (dict): sheet name, start/end row - # - # Returns: - # pd.DataFrame: _description_ - # """ - # try: - # df = self.xl.parse(lookup_table_location['sheet'], header=None, dtype=object) - # except KeyError: - # return None - # df = df.iloc[lookup_table_location['start_row'] - 1:lookup_table_location['end_row']] - # df = pd.DataFrame(df.values[1:], columns=df.iloc[0]) - # df = df.reset_index(drop=True) - # return df - def parse_plate_map(self): """ Parse sample location/name from plate map @@ -614,6 +568,8 @@ class EquipmentParser(object): asset = self.get_asset_number(input=asset) logger.debug(f"asset: {asset}") eq = Equipment.query(asset_number=asset) + if eq is None: + eq = Equipment.query(name=asset) process = ws.cell(row=v['process']['row'], column=v['process']['column']).value try: output.append( @@ -674,7 +630,6 @@ class TipParser(object): previous_asset = asset logger.debug(f"asset: {asset}") eq = Tips.query(lot=lot, name=asset, limit=1) - # process = ws.cell(row=v['process']['row'], column=v['process']['column']).value try: output.append( dict(name=eq.name, role=k, lot=lot)) @@ -705,7 +660,7 @@ class PCRParser(object): logger.error(f'Incorrect value: {e}') self.xl = None except PermissionError: - logger.error(f'Couldn\'t get permissions for {filepath.__str__()}. Operation might have been cancelled.') + logger.error(f"Couldn't get permissions for {filepath.__str__()}. Operation might have been cancelled.") return None if submission is None: self.submission_obj = Wastewater diff --git a/src/submissions/frontend/widgets/equipment_usage.py b/src/submissions/frontend/widgets/equipment_usage.py index 68e95e3..3570cf2 100644 --- a/src/submissions/frontend/widgets/equipment_usage.py +++ b/src/submissions/frontend/widgets/equipment_usage.py @@ -128,7 +128,9 @@ class RoleComboBox(QWidget): self.process.addItems([item for item in equip2.processes if item in self.role.processes]) def update_tips(self): - + """ + Changes what tips are available when process is changed + """ process = self.process.currentText() logger.debug(f"Checking process: {process}") process = Process.query(name=process)