From d844211e1b528f1edc8f9382683518b3feef5994 Mon Sep 17 00:00:00 2001 From: lwark Date: Wed, 26 Mar 2025 14:19:13 -0500 Subject: [PATCH] Post code-cleanup, moments before disaster. --- TODO.md | 5 +- src/submissions/backend/db/models/__init__.py | 9 ++ src/submissions/backend/db/models/controls.py | 52 ++++--- src/submissions/backend/db/models/kits.py | 144 +++++++----------- .../backend/db/models/organizations.py | 10 +- .../backend/db/models/submissions.py | 3 +- src/submissions/backend/excel/parser.py | 37 ----- .../backend/validators/__init__.py | 36 +++-- .../backend/validators/omni_gui_objects.py | 21 +-- src/submissions/backend/validators/pydant.py | 36 ++--- .../frontend/visualizations/irida_charts.py | 4 - .../frontend/visualizations/pcr_charts.py | 8 +- .../visualizations/turnaround_chart.py | 4 +- src/submissions/frontend/widgets/app.py | 6 +- .../frontend/widgets/controls_chart.py | 4 - .../frontend/widgets/omni_add_edit.py | 15 +- .../frontend/widgets/omni_manager.py | 17 --- .../frontend/widgets/omni_manager_pydant.py | 9 -- .../frontend/widgets/omni_search.py | 3 - .../frontend/widgets/submission_widget.py | 6 - src/submissions/tools/__init__.py | 39 +++-- 21 files changed, 183 insertions(+), 285 deletions(-) diff --git a/TODO.md b/TODO.md index af25dc9..57f916a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,7 @@ -- [ ] Can my "to_dict", "to_sub_dict", "to_pydantic" methods be rewritten as properties? +- [ ] Change "Manage Organizations" to the Pydantic version. +- [x] Can my "to_dict", "to_sub_dict", "to_pydantic" methods be rewritten as properties? - [ ] Stop displacing date on Irida controls and just do what Turnaround time does. -- [ ] Get Manager window working for KitType, maybe SubmissionType +- [x] Get Manager window working for KitType, maybe SubmissionType - [x] Find a way to merge AddEdit with ReagentAdder - [x] Find a way to merge omni_search and sample_search - [x] Allow parsing of custom fields to a json 'custom' field in _basicsubmissions diff --git a/src/submissions/backend/db/models/__init__.py b/src/submissions/backend/db/models/__init__.py index 4f95261..a7ad4ec 100644 --- a/src/submissions/backend/db/models/__init__.py +++ b/src/submissions/backend/db/models/__init__.py @@ -56,6 +56,12 @@ class BaseClass(Base): omni_inheritable = [] searchables = [] + def __repr__(self) -> str: + try: + return f"<{self.__class__.__name__}({self.name})>" + except AttributeError: + return f"<{self.__class__.__name__}({self.__name__})>" + # @classproperty # def skip_on_edit(cls): # if "association" in cls.__name__.lower() or cls.__name__.lower() == "discount": @@ -444,6 +450,9 @@ class BaseClass(Base): else: return super().__setattr__(key, value) + def delete(self): + logger.error(f"Delete has not been implemented for {self.__class__.__name__}") + class ConfigItem(BaseClass): """ diff --git a/src/submissions/backend/db/models/controls.py b/src/submissions/backend/db/models/controls.py index ff1b057..cf2fcfa 100644 --- a/src/submissions/backend/db/models/controls.py +++ b/src/submissions/backend/db/models/controls.py @@ -2,6 +2,8 @@ All control related models. """ from __future__ import annotations + +import itertools from pprint import pformat from PyQt6.QtWidgets import QWidget, QCheckBox, QLabel from pandas import DataFrame @@ -16,7 +18,6 @@ from typing import List, Literal, Tuple, Generator from dateutil.parser import parse from re import Pattern - logger = logging.getLogger(f"submissions.{__name__}") @@ -29,8 +30,8 @@ class ControlType(BaseClass): targets = Column(JSON) #: organisms checked for instances = relationship("Control", back_populates="controltype") #: control samples created of this type. - def __repr__(self) -> str: - return f"" + # def __repr__(self) -> str: + # return f"" @classmethod @setup_lookup @@ -88,7 +89,7 @@ class ControlType(BaseClass): Returns: Control: Associated Control class - """ + """ return Control.find_polymorphic_subclass(polymorphic_identity=self.name) @classmethod @@ -103,7 +104,7 @@ class ControlType(BaseClass): return (k for k, v in ct.items() if v) @classmethod - def build_positive_regex(cls, control_type:str) -> Pattern: + def build_positive_regex(cls, control_type: str) -> Pattern: """ Creates a re.Pattern that will look for positive control types @@ -305,10 +306,10 @@ class PCRControl(Control): id = Column(INTEGER, ForeignKey('_control.id'), primary_key=True) subtype = Column(String(16)) #: PC or NC target = Column(String(16)) #: N1, N2, etc. - ct = Column(FLOAT) #: PCR result + ct = Column(FLOAT) #: PCR result reagent_lot = Column(String(64), ForeignKey("_reagent.lot", ondelete="SET NULL", name="fk_reagent_lot")) - reagent = relationship("Reagent", foreign_keys=reagent_lot) #: reagent used for this control + reagent = relationship("Reagent", foreign_keys=reagent_lot) #: reagent used for this control __mapper_args__ = dict(polymorphic_identity="PCR Control", polymorphic_load="inline", @@ -320,7 +321,7 @@ class PCRControl(Control): Returns: dict: Output dict of name, ct, subtype, target, reagent_lot and submitted_date - """ + """ return dict( name=self.name, ct=self.ct, @@ -343,7 +344,7 @@ class PCRControl(Control): Returns: Tuple[Report, "PCRFigure"]: Report of status and resulting figure. - """ + """ from frontend.visualizations.pcr_charts import PCRFigure parent.mode_typer.clear() parent.mode_typer.setEnabled(False) @@ -352,6 +353,7 @@ class PCRControl(Control): end_date=chart_settings['end_date']) data = [control.to_sub_dict() for control in controls] df = DataFrame.from_records(data) + # NOTE: Get all PCR controls with ct over 0 try: df = df[df.ct > 0.0] except AttributeError: @@ -361,11 +363,11 @@ class PCRControl(Control): def to_pydantic(self): from backend.validators import PydPCRControl - return PydPCRControl(**self.to_sub_dict(), controltype_name=self.controltype_name, submission_id=self.submission_id) + return PydPCRControl(**self.to_sub_dict(), controltype_name=self.controltype_name, + submission_id=self.submission_id) class IridaControl(Control): - subtyping_allowed = ['kraken'] id = Column(INTEGER, ForeignKey('_control.id'), primary_key=True) @@ -379,11 +381,19 @@ class IridaControl(Control): sample = relationship("BacterialCultureSample", back_populates="control") #: This control's submission sample sample_id = Column(INTEGER, ForeignKey("_basicsample.id", ondelete="SET NULL", name="cont_BCS_id")) #: sample id key - + __mapper_args__ = dict(polymorphic_identity="Irida Control", polymorphic_load="inline", inherit_condition=(id == Control.id)) + @property + def targets(self): + if self.controltype.targets: + return list(itertools.chain.from_iterable([value for key, value in self.controltype.targets.items() + if key == self.subtype])) + else: + return ["None"] + @validates("subtype") def enforce_subtype_literals(self, key: str, value: str) -> str: """ @@ -398,7 +408,7 @@ class IridaControl(Control): Returns: str: Validated string. - """ + """ acceptables = ['ATCC49226', 'ATCC49619', 'EN-NOS', "EN-SSTI", "MCS-NOS", "MCS-SSTI", "SN-NOS", "SN-SSTI"] if value.upper() not in acceptables: raise KeyError(f"Sub-type must be in {acceptables}") @@ -416,19 +426,15 @@ class IridaControl(Control): except TypeError: kraken = {} kraken_cnt_total = sum([item['kraken_count'] for item in kraken.values()]) - new_kraken = [dict(name=item, kraken_count=kraken[item]['kraken_count'], - kraken_percent=f"{kraken[item]['kraken_count'] / kraken_cnt_total:0.2%}", - target=item in self.controltype.targets) - for item in kraken] + new_kraken = [dict(name=key, kraken_count=value['kraken_count'], + kraken_percent=f"{value['kraken_count'] / kraken_cnt_total:0.2%}", + target=key in self.controltype.targets) + for key, value in kraken.items()] new_kraken = sorted(new_kraken, key=itemgetter('kraken_count'), reverse=True) - if self.controltype.targets: - targets = self.controltype.targets - else: - targets = ["None"] output = dict( name=self.name, type=self.controltype.name, - targets=", ".join(targets), + targets=", ".join(self.targets), kraken=new_kraken[0:10] ) return output @@ -521,7 +527,7 @@ class IridaControl(Control): Returns: Tuple[Report, "IridaFigure"]: Report of status and resulting figure. - """ + """ from frontend.visualizations import IridaFigure try: checker = parent.findChild(QCheckBox, name="irida_check") diff --git a/src/submissions/backend/db/models/kits.py b/src/submissions/backend/db/models/kits.py index df1577c..a7c0e1f 100644 --- a/src/submissions/backend/db/models/kits.py +++ b/src/submissions/backend/db/models/kits.py @@ -16,7 +16,6 @@ from pandas import ExcelFile from pathlib import Path from . import Base, BaseClass, Organization, LogMixin from io import BytesIO -from inspect import getouterframes, currentframe logger = logging.getLogger(f'submissions.{__name__}') @@ -98,7 +97,6 @@ class KitType(BaseClass): Base of kits used in submission processing """ - # query_alias = "kit_type" omni_sort = BaseClass.omni_sort + ["kit_submissiontype_associations", "kit_reagentrole_associations", "processes"] id = Column(INTEGER, primary_key=True) #: primary key @@ -128,13 +126,6 @@ class KitType(BaseClass): creator=lambda ST: SubmissionTypeKitTypeAssociation( submission_type=ST)) #: Association proxy to SubmissionTypeKitTypeAssociation - def __repr__(self) -> str: - """ - Returns: - str: A representation of the object. - """ - return f"" - @classproperty def aliases(cls): return super().aliases + [cls.query_alias, "kit_types", "kit_type"] @@ -187,9 +178,7 @@ class KitType(BaseClass): # NOTE: Account for submission_type variable type. match submission_type: case str(): - # assocs = [item for item in self.kit_reagentrole_associations if - # item.submission_type.name == submission_type] - logger.debug(f"Query for {submission_type}") + # logger.debug(f"Query for {submission_type}") submission_type = SubmissionType.query(name=submission_type) case SubmissionType(): pass @@ -213,18 +202,12 @@ class KitType(BaseClass): ) if dlg.exec(): dlg_result = dlg.parse_form() - logger.debug(f"Dialog result: {dlg_result}") + # logger.debug(f"Dialog result: {dlg_result}") new_kit = self.__class__.query(name=dlg_result) - logger.debug(f"Query result: {new_kit}") - # return new_kit.construct_xl_map_for_use(submission_type=submission_type) + # logger.debug(f"Query result: {new_kit}") else: return None, new_kit assocs = [item for item in new_kit.kit_reagentrole_associations if item.submission_type == submission_type] - # for assoc in assocs: - # try: - # yield assoc.reagent_role.name, assoc.uses - # except TypeError: - # continue output = {assoc.reagent_role.name: assoc.uses for assoc in assocs} # logger.debug(f"Output: {output}") return output, new_kit @@ -232,7 +215,6 @@ class KitType(BaseClass): @classmethod def query_or_create(cls, **kwargs) -> Tuple[KitType, bool]: from backend.validators.pydant import PydKitType - from backend.validators.omni_gui_objects import BaseOmni new = False disallowed = ['expiry'] sanitized_kwargs = {k: v for k, v in kwargs.items() if k not in disallowed} @@ -248,7 +230,7 @@ class KitType(BaseClass): @setup_lookup def query(cls, name: str = None, - used_for: str | SubmissionType | None = None, + submissiontype: str | SubmissionType | None = None, id: int | None = None, limit: int = 0, **kwargs @@ -266,11 +248,11 @@ class KitType(BaseClass): KitType|List[KitType]: KitType(s) of interest. """ query: Query = cls.__database_session__.query(cls) - match used_for: + match submissiontype: case str(): - query = query.filter(cls.used_for.any(name=used_for)) + query = query.filter(cls.submissiontype.any(name=submissiontype)) case SubmissionType(): - query = query.filter(cls.used_for.contains(used_for)) + query = query.filter(cls.submissiontype.contains(submissiontype)) case _: pass match name: @@ -399,9 +381,6 @@ class KitType(BaseClass): def to_omni(self, expand: bool = False) -> "OmniKitType": from backend.validators.omni_gui_objects import OmniKitType - # logger.debug(f"self.name: {self.name}") - # level = len(getouterframes(currentframe())) - # logger.warning(f"Function level is {level}") if expand: processes = [item.to_omni() for item in self.processes] kit_reagentrole_associations = [item.to_omni() for item in self.kit_reagentrole_associations] @@ -425,6 +404,8 @@ class ReagentRole(BaseClass): Base of reagent type abstract """ + skip_on_edit = False + id = Column(INTEGER, primary_key=True) #: primary key name = Column(String(64)) #: name of role reagent plays instances = relationship("Reagent", back_populates="role", @@ -442,13 +423,6 @@ class ReagentRole(BaseClass): creator=lambda kit: KitTypeReagentRoleAssociation( kit_type=kit)) #: Association proxy to KitTypeReagentRoleAssociation - def __repr__(self) -> str: - """ - Returns: - str: Representation of object - """ - return f"" - @classmethod def query_or_create(cls, **kwargs) -> Tuple[ReagentRole, bool]: new = False @@ -603,7 +577,6 @@ class Reagent(BaseClass, LogMixin): Returns: dict: representation of the reagent's attributes """ - if extraction_kit is not None: # NOTE: Get the intersection of this reagent's ReagentType and all ReagentTypes in KitType reagent_role = next((item for item in set(self.role).intersection(extraction_kit.reagent_roles)), @@ -713,8 +686,6 @@ class Reagent(BaseClass, LogMixin): limit = 1 case _: pass - # if not role and "reagentrole" in kwargs.keys(): - # role = kwargs['reagentrole'] match role: case str(): query = query.join(cls.role).filter(ReagentRole.name == role) @@ -772,6 +743,7 @@ class Reagent(BaseClass, LogMixin): @check_authorization def edit_from_search(self, obj, **kwargs): from frontend.widgets.omni_add_edit import AddEdit + # logger.debug(f"Calling edit_from_search for {self.name}") dlg = AddEdit(parent=None, instance=self) if dlg.exec(): pyd = dlg.parse_form() @@ -1377,20 +1349,6 @@ class SubmissionType(BaseClass): def to_omni(self, expand: bool = False): from backend.validators.omni_gui_objects import OmniSubmissionType - # level = len(getouterframes(currentframe())) - # logger.warning(f"Function level is {level}") - # try: - # info_map = self.submission_type.info_map - # except AttributeError: - # info_map = {} - # try: - # defaults = self.submission_type.defaults - # except AttributeError: - # defaults = {} - # try: - # sample_map = self.submission_type.sample_map - # except AttributeError: - # sample_map = {} try: template_file = self.template_file except AttributeError: @@ -1555,8 +1513,6 @@ class SubmissionTypeKitTypeAssociation(BaseClass): def to_omni(self, expand: bool = False): from backend.validators.omni_gui_objects import OmniSubmissionTypeKitTypeAssociation - # level = len(getouterframes(currentframe())) - # logger.warning(f"Function level is {level}") if expand: try: submissiontype = self.submission_type.to_omni() @@ -1569,10 +1525,6 @@ class SubmissionTypeKitTypeAssociation(BaseClass): else: submissiontype = self.submission_type.name kittype = self.kit_type.name - # try: - # processes = [item.to_omni() for item in self.submission_type.processes] - # except AttributeError: - # processes = [] return OmniSubmissionTypeKitTypeAssociation( instance_object=self, submissiontype=submissiontype, @@ -1580,7 +1532,6 @@ class SubmissionTypeKitTypeAssociation(BaseClass): mutable_cost_column=self.mutable_cost_column, mutable_cost_sample=self.mutable_cost_sample, constant_cost=self.constant_cost - # processes=processes, ) @@ -1719,7 +1670,6 @@ class KitTypeReagentRoleAssociation(BaseClass): pass setattr(instance, k, v) logger.info(f"Instance from query or create: {instance.__dict__}\nis new: {new}") - # sys.exit() return instance, new @classmethod @@ -1854,6 +1804,8 @@ class SubmissionReagentAssociation(BaseClass): DOC: https://docs.sqlalchemy.org/en/14/orm/extensions/associationproxy.html """ + skip_on_edit = True + reagent_id = Column(INTEGER, ForeignKey("_reagent.id"), primary_key=True) #: id of associated reagent submission_id = Column(INTEGER, ForeignKey("_basicsubmission.id"), primary_key=True) #: id of associated submission comments = Column(String(1024)) #: Comments about reagents @@ -1869,10 +1821,10 @@ class SubmissionReagentAssociation(BaseClass): str: Representation of this SubmissionReagentAssociation """ try: - return f"<{self.submission.rsl_plate_num} & {self.reagent.lot}>" + return f"" except AttributeError: logger.error(f"Reagent {self.reagent.lot} submission association {self.reagent_id} has no submissions!") - return f"" + return f"" def __init__(self, reagent=None, submission=None): if isinstance(reagent, list): @@ -1963,12 +1915,12 @@ class Equipment(BaseClass, LogMixin): submissions = association_proxy("equipment_submission_associations", "submission") #: proxy to equipment_submission_associations.submission - def __repr__(self) -> str: - """ - Returns: - str: representation of this Equipment - """ - return f"" + # def __repr__(self) -> str: + # """ + # Returns: + # str: representation of this Equipment + # """ + # return f"" def to_dict(self, processes: bool = False) -> dict: """ @@ -1987,7 +1939,7 @@ class Equipment(BaseClass, LogMixin): def get_processes(self, submission_type: str | SubmissionType | None = None, extraction_kit: str | KitType | None = None, - equipment_role: str | EquipmentRole | None = None) -> List[str]: + equipment_role: str | EquipmentRole | None = None) -> Generator[Process, None, None]: """ Get all processes associated with this Equipment for a given SubmissionType @@ -2133,12 +2085,12 @@ class EquipmentRole(BaseClass): submission_types = association_proxy("equipmentrole_submissiontype_associations", "submission_type") #: proxy to equipmentrole_submissiontype_associations.submission_type - def __repr__(self) -> str: - """ - Returns: - str: Representation of this EquipmentRole - """ - return f"" + # def __repr__(self) -> str: + # """ + # Returns: + # str: Representation of this EquipmentRole + # """ + # return f"" def to_dict(self) -> dict: """ @@ -2395,7 +2347,6 @@ class Process(BaseClass): id = Column(INTEGER, primary_key=True) #: Process id, primary key name = Column(String(64), unique=True) #: Process name - # version = Column(String(32)) submission_types = relationship("SubmissionType", back_populates='processes', secondary=submissiontypes_processes) #: relation to SubmissionType equipment = relationship("Equipment", back_populates='processes', @@ -2410,12 +2361,12 @@ class Process(BaseClass): secondary=process_tiprole) #: relation to KitType - def __repr__(self) -> str: - """ - Returns: - str: Representation of this Process - """ - return f"" + # def __repr__(self) -> str: + # """ + # Returns: + # str: Representation of this Process + # """ + # return f"" def set_attribute(self, key, value): match key: @@ -2506,13 +2457,20 @@ class Process(BaseClass): def to_omni(self, expand: bool = False): from backend.validators.omni_gui_objects import OmniProcess + if expand: + submission_types = [item.to_omni() for item in self.submission_types] + equipment_roles = [item.to_omni() for item in self.equipment_roles] + tip_roles = [item.to_omni() for item in self.tip_roles] + else: + submission_types = [item.name for item in self.submission_types] + equipment_roles = [item.name for item in self.equipment_roles] + tip_roles = [item.name for item in self.tip_roles] return OmniProcess( instance_object=self, name=self.name, - # version=self.version, - submission_types=[item.to_omni() for item in self.submission_types], - equipment_roles=[item.to_omni() for item in self.equipment_roles], - tip_roles=[item.to_omni() for item in self.tip_roles] + submission_types=submission_types, + equipment_roles=equipment_roles, + tip_roles=tip_roles ) @@ -2538,8 +2496,8 @@ class TipRole(BaseClass): def tips(self): return self.instances - def __repr__(self): - return f"" + # def __repr__(self): + # return f"" @classmethod def query_or_create(cls, **kwargs) -> Tuple[TipRole, bool]: @@ -2573,10 +2531,14 @@ class TipRole(BaseClass): def to_omni(self, expand: bool = False): from backend.validators.omni_gui_objects import OmniTipRole + if expand: + tips = [item.to_omni() for item in self.tips] + else: + tips = [item.name for item in self.tips] return OmniTipRole( instance_object=self, name=self.name, - tips=[item.to_omni() for item in self.tips] + tips=tips ) @@ -2605,8 +2567,8 @@ class Tips(BaseClass, LogMixin): def tiprole(self): return self.role - def __repr__(self): - return f"" + # def __repr__(self): + # return f"" @classmethod def query_or_create(cls, **kwargs) -> Tuple[Tips, bool]: diff --git a/src/submissions/backend/db/models/organizations.py b/src/submissions/backend/db/models/organizations.py index 94eef6e..785b8c6 100644 --- a/src/submissions/backend/db/models/organizations.py +++ b/src/submissions/backend/db/models/organizations.py @@ -29,8 +29,6 @@ class Organization(BaseClass): Base of organization """ - - id = Column(INTEGER, primary_key=True) #: primary key name = Column(String(64)) #: organization name submissions = relationship("BasicSubmission", @@ -43,8 +41,8 @@ class Organization(BaseClass): def contact(self): return self.contacts - def __repr__(self) -> str: - return f"" + # def __repr__(self) -> str: + # return f"" @classmethod @setup_lookup @@ -139,8 +137,8 @@ class Contact(BaseClass): secondary=orgs_contacts) #: relationship to joined organization submissions = relationship("BasicSubmission", back_populates="contact") #: submissions this contact has submitted - def __repr__(self) -> str: - return f"" + # def __repr__(self) -> str: + # return f"" @classproperty def searchables(cls): diff --git a/src/submissions/backend/db/models/submissions.py b/src/submissions/backend/db/models/submissions.py index bf875fb..339021f 100644 --- a/src/submissions/backend/db/models/submissions.py +++ b/src/submissions/backend/db/models/submissions.py @@ -402,7 +402,6 @@ class BasicSubmission(BaseClass, LogMixin): columns = set([assoc.column for assoc in self.submission_sample_associations]) return len(columns) - def calculate_base_cost(self) -> None: """ Calculates cost of the plate @@ -733,7 +732,7 @@ class BasicSubmission(BaseClass, LogMixin): @classmethod def find_polymorphic_subclass(cls, polymorphic_identity: str | SubmissionType | None = None, - attrs: dict | None = None): + attrs: dict | None = None) -> BasicSubmission: """ Find subclass based on polymorphic identity or relevant attributes. diff --git a/src/submissions/backend/excel/parser.py b/src/submissions/backend/excel/parser.py index f70de73..226f195 100644 --- a/src/submissions/backend/excel/parser.py +++ b/src/submissions/backend/excel/parser.py @@ -59,7 +59,6 @@ class SheetParser(object): Pulls basic information from the excel sheet """ parser = InfoParser(xl=self.xl, submission_type=self.submission_type, sub_object=self.sub_object) - # info = parser.parsed_info self.info_map = parser.info_map # NOTE: in order to accommodate generic submission types we have to check for the type in the excel sheet and rerun accordingly try: @@ -274,37 +273,12 @@ class ReagentParser(object): Returns: dict: locations of reagent info for the kit. """ - # report = Report() - # if isinstance(submission_type, dict): - # submission_type = submission_type['value'] - # if isinstance(submission_type, str): - # submission_type = SubmissionType.query(name=submission_type) - # logger.debug("Running kit map") associations, self.kit_object = self.kit_object.construct_xl_map_for_use(submission_type=self.submission_type_obj) reagent_map = {k: v for k, v in associations.items() if k != 'info'} try: del reagent_map['info'] except KeyError: pass - # # NOTE: If reagent map is empty, maybe the wrong kit was given, check if there's only one kit for that submission type and use it if so. - # if not reagent_map: - # temp_kit_object = self.submission_type_obj.default_kit - # if temp_kit_object: - # self.kit_object = temp_kit_object - # logger.warning(f"Attempting to salvage with default kit {self.kit_object} and submission_type: {self.submission_type_obj}") - # return self.fetch_kit_map(submission_type=self.submission_type_obj) - # else: - # logger.error(f"Still no reagent map, displaying error.") - # try: - # ext_kit_loc = self.submission_type_obj.info_map['extraction_kit']['read'][0] - # location_string = f"Sheet: {ext_kit_loc['sheet']}, Row: {ext_kit_loc['row']}, Column: {ext_kit_loc['column']}?" - # except (IndexError, KeyError): - # location_string = "" - # report.add_result(Result(owner=__name__, code=0, - # msg=f"No kit map found for {self.kit_object.name}.\n\n" - # f"Are you sure you put the right kit in:\n\n{location_string}?", - # status="Critical")) - # logger.debug(f"Here is the map coming out: {reagent_map}") return reagent_map @property @@ -375,9 +349,6 @@ class SampleParser(object): self.sub_object = sub_object self.sample_type = self.sub_object.get_default_info("sample_type", submission_type=submission_type) self.samp_object = BasicSample.find_polymorphic_subclass(polymorphic_identity=self.sample_type) - # self.sample_map = self.sample_map(submission_type=submission_type, sample_map=sample_map) - # self.plate_map_samples = self.parse_plate_map() - # self.lookup_samples = self.parse_lookup_table() @property def sample_map(self) -> dict: @@ -391,11 +362,6 @@ class SampleParser(object): dict: Info locations. """ - # if sample_map is None: - # sample_info_map = self.sub_object.construct_sample_map(submission_type=self.submission_type_obj) - # else: - # sample_info_map = sample_map - # return sample_info_map return self.sub_object.construct_sample_map(submission_type=self.submission_type_obj) @property @@ -519,7 +485,6 @@ class EquipmentParser(object): submission_type = SubmissionType.query(name=submission_type) self.submission_type = submission_type self.xl = xl - # self.equipment_map = self.fetch_equipment_map() @property def equipment_map(self) -> dict: @@ -597,7 +562,6 @@ class TipParser(object): submission_type = SubmissionType.query(name=submission_type) self.submission_type = submission_type self.xl = xl - # self.map = self.fetch_tip_map() @property def tip_map(self) -> dict: @@ -669,7 +633,6 @@ class PCRParser(object): else: self.submission_obj = submission rsl_plate_num = self.submission_obj.rsl_plate_num - # self.pcr = self.parse_general() self.samples = self.submission_obj.parse_pcr(xl=self.xl, rsl_plate_num=rsl_plate_num) self.controls = self.submission_obj.parse_pcr_controls(xl=self.xl, rsl_plate_num=rsl_plate_num) diff --git a/src/submissions/backend/validators/__init__.py b/src/submissions/backend/validators/__init__.py index e08f3c2..7d310b0 100644 --- a/src/submissions/backend/validators/__init__.py +++ b/src/submissions/backend/validators/__init__.py @@ -28,7 +28,8 @@ class RSLNamer(object): logger.info(f"got submission type: {self.submission_type}") if self.submission_type: self.sub_object = BasicSubmission.find_polymorphic_subclass(polymorphic_identity=self.submission_type) - self.parsed_name = self.retrieve_rsl_number(filename=filename, regex=self.sub_object.get_regex(submission_type=submission_type)) + self.parsed_name = self.retrieve_rsl_number(filename=filename, regex=self.sub_object.get_regex( + submission_type=submission_type)) if not data: data = dict(submission_type=self.submission_type) if "submission_type" not in data.keys(): @@ -50,24 +51,36 @@ class RSLNamer(object): Returns: str: parsed submission type """ - def st_from_path(filename:Path) -> str: - if filename.exists(): - wb = load_workbook(filename) + + def st_from_path(filepath: Path) -> str: + """ + Sub def to get submissiontype from a file path + + Args: + filepath (): + + Returns: + + """ + if filepath.exists(): + wb = load_workbook(filepath) try: # NOTE: Gets first category in the metadata. categories = wb.properties.category.split(";") submission_type = next(item.strip().title() for item in categories) except (StopIteration, AttributeError): - sts = {item.name: item.template_file_sheets for item in SubmissionType.query() if item.template_file} + sts = {item.name: item.template_file_sheets for item in SubmissionType.query() if + item.template_file} try: - submission_type = next(k.title() for k,v in sts.items() if wb.sheetnames==v) + submission_type = next(k.title() for k, v in sts.items() if wb.sheetnames == v) except StopIteration: - # NOTE: On failure recurse using filename as string for string method - submission_type = cls.retrieve_submission_type(filename=filename.stem.__str__()) + # NOTE: On failure recurse using filepath as string for string method + submission_type = cls.retrieve_submission_type(filename=filepath.stem.__str__()) else: - submission_type = cls.retrieve_submission_type(filename=filename.stem.__str__()) + submission_type = cls.retrieve_submission_type(filename=filepath.stem.__str__()) return submission_type - def st_from_str(filename:str) -> str: + + def st_from_str(filename: str) -> str: if filename.startswith("tmp"): return "Bacterial Culture" regex = BasicSubmission.regex @@ -78,9 +91,10 @@ class RSLNamer(object): submission_type = None logger.critical(f"No submission type found or submission type found!: {e}") return submission_type + match filename: case Path(): - submission_type = st_from_path(filename=filename) + submission_type = st_from_path(filepath=filename) case str(): submission_type = st_from_str(filename=filename) case _: diff --git a/src/submissions/backend/validators/omni_gui_objects.py b/src/submissions/backend/validators/omni_gui_objects.py index d1aeeed..59096e7 100644 --- a/src/submissions/backend/validators/omni_gui_objects.py +++ b/src/submissions/backend/validators/omni_gui_objects.py @@ -1,5 +1,5 @@ from __future__ import annotations -import logging, sys +import logging from pydantic import BaseModel, field_validator, Field from typing import List, ClassVar from backend.db.models import * @@ -16,7 +16,7 @@ class BaseOmni(BaseModel): try: return f"<{self.__class__.__name__}({self.name})>" except AttributeError: - return f"<{self.__class__.__name__}(NO NAME)>" + return f"<{self.__class__.__name__}({self.__repr_name__})>" @classproperty def aliases(cls): @@ -478,7 +478,6 @@ class OmniProcess(BaseOmni): # NOTE: How am I going to figure out relatioinships without getting into recursion issues? name: str = Field(default="", description="property") #: Process name - # version: str = Field(default="", description="property") #: Version (string to account for "in_use" or whatever) submission_types: List[OmniSubmissionType] | List[str] = Field(default=[], description="relationship", title="SubmissionType") equipment_roles: List[OmniEquipmentRole] | List[str] = Field(default=[], description="relationship", @@ -507,13 +506,6 @@ class OmniProcess(BaseOmni): return "" return value - # @field_validator("version", mode="before") - # @classmethod - # def rescue_name_none(cls, value): - # if not value: - # return "1" - # return value - def to_sql(self): instance, new = self.class_object.query_or_create(name=self.name) for st in self.submission_types: @@ -539,12 +531,8 @@ class OmniKitType(BaseOmni): class_object: ClassVar[Any] = KitType name: str = Field(default="", description="property") - kit_submissiontype_associations: List[OmniSubmissionTypeKitTypeAssociation] | List[str] = Field(default=[], - description="relationship", - title="SubmissionTypeKitTypeAssociation") - kit_reagentrole_associations: List[OmniKitTypeReagentRoleAssociation] | List[str] = Field(default=[], - description="relationship", - title="KitTypeReagentRoleAssociation") + kit_submissiontype_associations: List[OmniSubmissionTypeKitTypeAssociation] | List[str] = Field(default=[], description="relationship", title="SubmissionTypeKitTypeAssociation") + kit_reagentrole_associations: List[OmniKitTypeReagentRoleAssociation] | List[str] = Field(default=[], description="relationship", title="KitTypeReagentRoleAssociation") processes: List[OmniProcess] | List[str] = Field(default=[], description="relationship", title="Process") @field_validator("name", mode="before") @@ -577,7 +565,6 @@ class OmniKitType(BaseOmni): new_rr.append(new_assoc) logger.debug(f"Setting kit_reagentrole_associations to {pformat([item.__dict__ for item in new_rr])}") kit.kit_reagentrole_associations = new_rr - # sys.exit() new_st = [] for st_assoc in self.kit_submissiontype_associations: new_assoc = st_assoc.to_sql() diff --git a/src/submissions/backend/validators/pydant.py b/src/submissions/backend/validators/pydant.py index d4500e7..b730f6d 100644 --- a/src/submissions/backend/validators/pydant.py +++ b/src/submissions/backend/validators/pydant.py @@ -288,8 +288,6 @@ class PydTips(BaseModel): tips = Tips.query(name=self.name, limit=1) # logger.debug(f"Tips query has yielded: {tips}") assoc = SubmissionTipsAssociation.query_or_create(tips=tips, submission=submission, role=self.role, limit=1) - # if assoc is None: - # assoc = SubmissionTipsAssociation(submission=submission, tips=tips, role_name=self.role) return assoc, report @@ -355,14 +353,13 @@ class PydEquipment(BaseModel, extra='ignore'): # TODO: This seems precarious. What if there is more than one process? # NOTE: It looks like the way fetching the processes is done in the SQL model, this shouldn't be a problem, but I'll include a failsafe. # NOTE: I need to find a way to filter this by the kit involved. - if len(self.processes) > 1: process = Process.query(submissiontype=submission.get_submission_type(), kittype=extraction_kit, equipmentrole=self.role) else: process = Process.query(name=self.processes[0]) if process is None: logger.error(f"Found unknown process: {process}.") - logger.debug(f"Using process: {process}") + # logger.debug(f"Using process: {process}") assoc.process = process assoc.role = self.role else: @@ -746,7 +743,16 @@ class PydSubmission(BaseModel, extra='allow'): output = {k: self.filter_field(k) for k in fields} return output - def filter_field(self, key: str): + def filter_field(self, key: str) -> Any: + """ + Attempts to get value from field dictionary + + Args: + key (str): name of the field of interest + + Returns: + Any (): Value found. + """ item = getattr(self, key) match item: case dict(): @@ -780,9 +786,8 @@ class PydSubmission(BaseModel, extra='allow'): """ report = Report() dicto = self.improved_dict() - logger.debug(f"Pydantic submission type: {self.submission_type['value']}") - logger.debug(f"Pydantic improved_dict: {pformat(dicto)}") - # At this point, pcr_info is not duplicated + # logger.debug(f"Pydantic submission type: {self.submission_type['value']}") + # logger.debug(f"Pydantic improved_dict: {pformat(dicto)}") instance, result = BasicSubmission.query_or_create(submission_type=self.submission_type['value'], rsl_plate_num=self.rsl_plate_num['value']) # logger.debug(f"Created or queried instance: {instance}") @@ -792,8 +797,7 @@ class PydSubmission(BaseModel, extra='allow'): report.add_result(result) self.handle_duplicate_samples() for key, value in dicto.items(): - logger.debug(f"Checking key {key}, value {value}") - # At this point, pcr_info is not duplicated. + # logger.debug(f"Checking key {key}, value {value}") if isinstance(value, dict): try: value = value['value'] @@ -849,8 +853,7 @@ class PydSubmission(BaseModel, extra='allow'): value = value instance.set_attribute(key=key, value=value) case item if item in instance.jsons: - # At this point pcr_info is not duplicated - logger.debug(f"Validating json value: {item} to value:{pformat(value)}") + # logger.debug(f"Validating json value: {item} to value:{pformat(value)}") try: ii = value.items() except AttributeError: @@ -860,8 +863,7 @@ class PydSubmission(BaseModel, extra='allow'): value[k] = v.strftime("%Y-%m-%d %H:%M:%S") else: pass - logger.debug(f"Setting json value: {item} to value:{pformat(value)}") - # At this point, pcr_info is not duplicated. + # logger.debug(f"Setting json value: {item} to value:{pformat(value)}") instance.set_attribute(key=key, value=value) case _: try: @@ -878,7 +880,6 @@ class PydSubmission(BaseModel, extra='allow'): continue else: logger.warning(f"{key} already == {value} so no updating.") - logger.debug(f"Entering cost calculation for {instance}") try: instance.calculate_base_cost() except (TypeError, AttributeError) as e: @@ -937,7 +938,6 @@ class PydSubmission(BaseModel, extra='allow'): "/", "") return render - # @report_result def check_kit_integrity(self, extraction_kit: str | dict | None = None, exempt: List[PydReagent] = []) -> Tuple[ List[PydReagent], Report, List[PydReagent]]: """ @@ -1212,7 +1212,6 @@ class PydIridaControl(BaseModel, extra='ignore'): contains: list | dict #: unstructured hashes in contains.tsv for each organism matches: list | dict #: unstructured hashes in matches.tsv for each organism kraken: list | dict #: unstructured output from kraken_report - # subtype: str #: EN-NOS, MCS-NOS, etc subtype: Literal["ATCC49226", "ATCC49619", "EN-NOS", "EN-SSTI", "MCS-NOS", "MCS-SSTI", "SN-NOS", "SN-SSTI"] refseq_version: str #: version of refseq used in fastq parsing kraken2_version: str @@ -1264,7 +1263,6 @@ class PydProcess(BaseModel, extra="allow"): instance = Process.query(name=self.name) if not instance: instance = Process() - # dicto = instance.omnigui_instance_dict fields = [item for item in self.model_fields] for field in fields: logger.debug(f"Field: {field}") @@ -1315,5 +1313,3 @@ class PydElastic(BaseModel, extra="allow", arbitrary_types_allowed=True): field_value = getattr(self, field) self.instance.__setattr__(field, field_value) return self.instance - - diff --git a/src/submissions/frontend/visualizations/irida_charts.py b/src/submissions/frontend/visualizations/irida_charts.py index 78eae18..e66caf1 100644 --- a/src/submissions/frontend/visualizations/irida_charts.py +++ b/src/submissions/frontend/visualizations/irida_charts.py @@ -19,10 +19,6 @@ class IridaFigure(CustomFigure): super().__init__(df=df, modes=modes, settings=settings) self.df = df - # try: - # months = int(settings['months']) - # except KeyError: - # months = 6 self.construct_chart(df=df, modes=modes, start_date=settings['start_date'], end_date=settings['end_date']) diff --git a/src/submissions/frontend/visualizations/pcr_charts.py b/src/submissions/frontend/visualizations/pcr_charts.py index dec8a25..27db500 100644 --- a/src/submissions/frontend/visualizations/pcr_charts.py +++ b/src/submissions/frontend/visualizations/pcr_charts.py @@ -3,10 +3,8 @@ Functions for constructing irida controls graphs using plotly. """ from pprint import pformat from . import CustomFigure -import plotly.express as px -import pandas as pd from PyQt6.QtWidgets import QWidget -import logging +import logging, plotly.express as px, pandas as pd logger = logging.getLogger(f"submissions.{__name__}") @@ -17,10 +15,6 @@ class PCRFigure(CustomFigure): months: int = 6): super().__init__(df=df, modes=modes, settings=settings) self.df = df - # try: - # months = int(settings['months']) - # except KeyError: - # months = 6 self.construct_chart(df=df) def construct_chart(self, df: pd.DataFrame): diff --git a/src/submissions/frontend/visualizations/turnaround_chart.py b/src/submissions/frontend/visualizations/turnaround_chart.py index 6d1d28b..3e3c1af 100644 --- a/src/submissions/frontend/visualizations/turnaround_chart.py +++ b/src/submissions/frontend/visualizations/turnaround_chart.py @@ -3,10 +3,8 @@ Construct turnaround time charts """ from pprint import pformat from . import CustomFigure -import plotly.express as px -import pandas as pd from PyQt6.QtWidgets import QWidget -import logging +import logging, plotly.express as px, pandas as pd logger = logging.getLogger(f"submissions.{__name__}") diff --git a/src/submissions/frontend/widgets/app.py b/src/submissions/frontend/widgets/app.py index 2cfd156..d210b02 100644 --- a/src/submissions/frontend/widgets/app.py +++ b/src/submissions/frontend/widgets/app.py @@ -230,7 +230,9 @@ class App(QMainWindow): def update_data(self): self.table_widget.sub_wid.setData(page=self.table_widget.pager.page_anchor, page_size=page_size) + # TODO: Change this to the Pydantic version. def manage_orgs(self): + from frontend.widgets.omni_manager_pydant import ManagerWindow as ManagerWindowPyd dlg = ManagerWindow(parent=self, object_type=Organization, extras=[], add_edit='edit', managers=set()) if dlg.exec(): new_org = dlg.parse_form() @@ -245,13 +247,9 @@ class App(QMainWindow): logger.debug("\n\nBeginning parsing\n\n") output = dlg.parse_form() logger.debug(f"Kit output: {pformat(output.__dict__)}") - # with open(f"{output.name}.obj", "wb") as f: - # pickle.dump(output, f) logger.debug("\n\nBeginning transformation\n\n") sql = output.to_sql() assert isinstance(sql, KitType) - # with open(f"{output.name}.sql", "wb") as f: - # pickle.dump(sql, f) sql.save() diff --git a/src/submissions/frontend/widgets/controls_chart.py b/src/submissions/frontend/widgets/controls_chart.py index fff89b5..3a52a5d 100644 --- a/src/submissions/frontend/widgets/controls_chart.py +++ b/src/submissions/frontend/widgets/controls_chart.py @@ -113,10 +113,6 @@ class ControlsViewer(InfoPane): if issubclass(self.fig.__class__, CustomFigure): self.save_button.setEnabled(True) # NOTE: construct html for webview - # try: - # html = self.fig.html - # except AttributeError: - # html = "" self.webview.setHtml(self.fig.html) self.webview.update() return report diff --git a/src/submissions/frontend/widgets/omni_add_edit.py b/src/submissions/frontend/widgets/omni_add_edit.py index 5983229..29f53cf 100644 --- a/src/submissions/frontend/widgets/omni_add_edit.py +++ b/src/submissions/frontend/widgets/omni_add_edit.py @@ -28,12 +28,12 @@ class AddEdit(QDialog): self.object_type = instance.__class__ # self.managers = deepcopy(managers) self.managers = managers - if instance.level < 2: - try: - logger.debug(f"Parent instance: {self.parent().instance}") - self.managers.add(self.parent().instance) - except AttributeError: - pass + # if instance.level < 2: + # try: + # logger.debug(f"Parent instance: {self.parent().instance}") + # self.managers.add(self.parent().instance) + # except AttributeError: + # pass logger.debug(f"Managers: {managers}") self.layout = QGridLayout(self) QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel @@ -111,14 +111,13 @@ class EditProperty(QWidget): case _: logger.error(f"{column_type} not a supported type.") return - # if not self.is_list: self.layout.addWidget(self.label, 0, 0, 1, 1) self.layout.addWidget(self.widget, 0, 1, 1, 3) self.setLayout(self.layout) def relationship_property_set(self, relationship, value=None): self.widget = QComboBox() - logger.debug(self.parent().managers) + # logger.debug(self.parent().managers) for manager in self.parent().managers: if self.name in manager.aliases: logger.debug(f"Name: {self.name} is in aliases: {manager.aliases}") diff --git a/src/submissions/frontend/widgets/omni_manager.py b/src/submissions/frontend/widgets/omni_manager.py index 87ddcea..783bdda 100644 --- a/src/submissions/frontend/widgets/omni_manager.py +++ b/src/submissions/frontend/widgets/omni_manager.py @@ -47,7 +47,6 @@ class ManagerWindow(QDialog): self.manager = None else: self.manager = manager - # logger.debug(f"Managers: {managers}") self.extras = extras self.context = kwargs @@ -104,7 +103,6 @@ class ManagerWindow(QDialog): self.options.setEditable(False) self.options.setMinimumWidth(self.minimumWidth()) self.layout.addWidget(self.options, 1, 0, 1, 1) - # if len(options) > 0: self.add_button = QPushButton("Add New") self.layout.addWidget(self.add_button, 1, 1, 1, 1) self.add_button.clicked.connect(self.add_new) @@ -126,12 +124,6 @@ class ManagerWindow(QDialog): for item in deletes: item.setParent(None) # logger.debug(f"Current options text lower: {self.options.currentText().lower()}") - # NOTE: Find the instance this manager will update - # try: - # check = "blank" not in self.options.currentText().lower() and self.options.currentText() != "" - # except AttributeError: - # check = False - # if check: if self.add_edit == "edit" and initial: # logger.debug(f"Querying with {self.options.currentText()}") self.instance = self.class_object.query(name=self.options.currentText(), limit=1) @@ -173,7 +165,6 @@ class ManagerWindow(QDialog): Returns: Any: The instance with updated fields. """ - # TODO: Need Relationship property here too? results = [item.parse_form() for item in self.findChildren(EditProperty)] for result in results: # logger.debug(f"Incoming result: {result}") @@ -211,7 +202,6 @@ class ManagerWindow(QDialog): else: value = current_value + [data] setattr(self.instance, name, value) - # self.instance.save() def toggle_textedit(self, caller_child=None): already_exists = self.findChildren(LargeTextEdit) @@ -305,7 +295,6 @@ class EditRelationship(QWidget): # logger.debug(f"self.relationship: {self.relationship}") # logger.debug(f"Relationship uses list: {self.relationship.property.uselist}") # NOTE: value is a database object in this case. - # logger.debug(f"Data for edit relationship: {self.data}") self.widget = QTableView() self.add_button = QPushButton("Add New") @@ -319,7 +308,6 @@ class EditRelationship(QWidget): else: value = [] self.data = value - # self.update_buttons() checked_manager, is_primary = check_object_in_manager(self.parent().manager, self.objectName()) if checked_manager: logger.debug(f"Checked manager for {self.objectName()}: {checked_manager}") @@ -369,7 +357,6 @@ class EditRelationship(QWidget): new_instance = dlg.parse_form() # NOTE: My custom __setattr__ should take care of any list problems. self.parent().instance.__setattr__(self.objectName(), new_instance) - # self.parent().instance.save() self.parent().update_data() def add_existing(self): @@ -381,7 +368,6 @@ class EditRelationship(QWidget): instance = self.class_object.query(**row) # NOTE: My custom __setattr__ should take care of any list problems. self.parent().instance.__setattr__(self.objectName(), instance) - # self.parent().instance.save() self.parent().update_data() def set_data(self) -> None: @@ -420,7 +406,6 @@ class EditRelationship(QWidget): Args: event (_type_): the item of interest """ - # print(self.widget.isEnabled()) if not self.widget.isEnabled(): logger.warning(f"{self.objectName()} is disabled.") return @@ -471,7 +456,6 @@ class EditRelationship(QWidget): except ValueError as e: logger.error(f"Remove failed for {self.objectName().lower()} due to {e}.") self.parent().instance.save() - # self.parent().update_data() self.set_data() def parse_form(self): @@ -555,7 +539,6 @@ class JsonEditScreen(QDialog): output.append(value) else: raise ValueError(f"Inappropriate data type: {type(self.json_field)}") - # output[key] = value return output diff --git a/src/submissions/frontend/widgets/omni_manager_pydant.py b/src/submissions/frontend/widgets/omni_manager_pydant.py index 604ea2f..4e4413e 100644 --- a/src/submissions/frontend/widgets/omni_manager_pydant.py +++ b/src/submissions/frontend/widgets/omni_manager_pydant.py @@ -120,7 +120,6 @@ class ManagerWindow(QDialog): # logger.debug(f"Querying with {self.options.currentText()}") self.instance = self.class_object.query(name=self.options.currentText(), limit=1) except AttributeError: - # self.instance = None pass # logger.debug(f"Instance: {self.instance}") if not self.instance: @@ -164,11 +163,6 @@ class ManagerWindow(QDialog): # NOTE: RelationshipDeclareds will be given a list of existing related objects. case "relationship": # NOTE: field.comparator.class_object.class_ gives the relationship class - # try: - # logger.debug( - # f"Creating relationship widget with value: {[pformat(item.__dict__) for item in value]}") - # except AttributeError: - # logger.debug(f"Creating relationship widget with value: {value}") widget = EditRelationship(self, key=key, class_object=info.title, value=value) case _: continue @@ -294,7 +288,6 @@ class EditRelationship(QWidget): value = [] self.data = value # logger.debug(f"Set data: {self.data}") - # self.update_buttons() # logger.debug(f"Parent manager: {self.parent().manager}") checked_manager, is_primary = check_object_in_manager(self.parent().manager, self.objectName()) if checked_manager: @@ -374,8 +367,6 @@ class EditRelationship(QWidget): return logger.debug(f"Updating \n{pformat(obj)} with \n{pformat(new_instance.__dict__)}") obj.__dict__.update(new_instance.__dict__) - # # self.parent().omni_object.__setattr__(self.objectName(), obj) - # # instance.__dict__.update(new_instance.__dict__) logger.debug(f"Final instance: {pformat(self.parent().omni_object.__dict__)}") # NOTE: somewhere in the update_data I'm losing changes. self.parent().update_data() diff --git a/src/submissions/frontend/widgets/omni_search.py b/src/submissions/frontend/widgets/omni_search.py index b679a85..4b3ab57 100644 --- a/src/submissions/frontend/widgets/omni_search.py +++ b/src/submissions/frontend/widgets/omni_search.py @@ -45,7 +45,6 @@ class SearchBox(QDialog): self.setLayout(self.layout) self.setWindowTitle(f"Search {self.object_type.__name__}") self.update_widgets() - # self.update_data() if returnable: QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel self.buttonBox = QDialogButtonBox(QBtn) @@ -60,7 +59,6 @@ class SearchBox(QDialog): Changes form inputs based on sample type """ search_fields = [] - # search_fields = self.object_type.searchables logger.debug(f"Search fields: {search_fields}") deletes = [item for item in self.findChildren(FieldSearch)] for item in deletes: @@ -69,7 +67,6 @@ class SearchBox(QDialog): if not self.sub_class: logger.warning(f"No subclass selected.") self.update_data() - # return else: if self.sub_class.currentText() == "Any": self.object_type = self.original_type diff --git a/src/submissions/frontend/widgets/submission_widget.py b/src/submissions/frontend/widgets/submission_widget.py index 139aa52..ce45696 100644 --- a/src/submissions/frontend/widgets/submission_widget.py +++ b/src/submissions/frontend/widgets/submission_widget.py @@ -315,8 +315,6 @@ class SubmissionFormWidget(QWidget): query = self.findChildren(QWidget, name=object_name) else: query = self.findChildren(QWidget) - # if object_name is not None: - # query = [widget for widget in query if widget.objectName() == object_name] return query @report_result @@ -338,7 +336,6 @@ class SubmissionFormWidget(QWidget): if self.disabler.checkbox.isChecked(): _, result, _ = self.pyd.check_kit_integrity(exempt=exempt) report.add_result(result) - # result = self.pyd.check_reagent_expiries(exempt=exempt) if len(result.results) > 0: return report base_submission = self.pyd.to_sql() @@ -372,7 +369,6 @@ class SubmissionFormWidget(QWidget): pass # NOTE: add reagents to submission object if base_submission is None: - # self.app.table_widget.sub_wid.setData() return for reagent in base_submission.reagents: reagent.update_last_used(kit=base_submission.extraction_kit) @@ -752,11 +748,9 @@ class SubmissionFormWidget(QWidget): looked_up_reg = None if looked_up_reg: try: - # relevant_reagents.remove(str(looked_up_reg.lot)) relevant_reagents.insert(0, relevant_reagents.pop(relevant_reagents.index(looked_up_reg.lot))) except ValueError as e: logger.error(f"Error reordering relevant reagents: {e}") - # relevant_reagents.insert(0, str(looked_up_reg.lot)) else: if len(relevant_reagents) > 1: idx = relevant_reagents.index(str(reagent.lot)) diff --git a/src/submissions/tools/__init__.py b/src/submissions/tools/__init__.py index d391745..26972f6 100644 --- a/src/submissions/tools/__init__.py +++ b/src/submissions/tools/__init__.py @@ -2,16 +2,11 @@ Contains miscellaenous functions used by both frontend and backend. ''' from __future__ import annotations -import builtins -import importlib -import time +import builtins, importlib, time, logging, re, yaml, sys, os, stat, platform, getpass, json, numpy as np, pandas as pd from datetime import date, datetime, timedelta from json import JSONDecodeError -import logging, re, yaml, sys, os, stat, platform, getpass, json, numpy as np, pandas as pd from threading import Thread from inspect import getmembers, isfunction, stack -from types import GeneratorType - from dateutil.easter import easter from jinja2 import Environment, FileSystemLoader from logging import handlers @@ -19,11 +14,9 @@ from pathlib import Path from sqlalchemy.orm import Session, InstrumentedAttribute from sqlalchemy import create_engine, text, MetaData from pydantic import field_validator, BaseModel, Field -from pydantic_settings import BaseSettings, SettingsConfigDict +from pydantic_settings import BaseSettings, SettingsConfigDict, PydanticBaseSettingsSource, YamlConfigSettingsSource from typing import Any, Tuple, Literal, List, Generator - from sqlalchemy.orm.relationships import _RelationshipDeclared - from __init__ import project_path from configparser import ConfigParser from tkinter import Tk # NOTE: This is for choosing database path before app is created. @@ -148,7 +141,6 @@ def check_key_or_attr(key: str, interest: dict | object, check_none: bool = Fals return False - def check_not_nan(cell_contents) -> bool: """ Check to ensure excel sheet cell contents are not blank. @@ -432,7 +424,6 @@ class Settings(BaseSettings, extra="allow"): return package def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) self.set_from_db() self.set_scripts() @@ -1231,3 +1222,29 @@ class classproperty(property): builtins.classproperty = classproperty ctx = get_config(None) + +class Settings2(BaseSettings, extra="allow"): + + model_config = SettingsConfigDict(yaml_file="C:\\Users\lwark\AppData\Local\submissions\config\config.yml", + yaml_file_encoding='utf-8') + + @classmethod + def settings_customise_sources( + cls, + settings_cls: type[BaseSettings], + init_settings: PydanticBaseSettingsSource, + env_settings: PydanticBaseSettingsSource, + dotenv_settings: PydanticBaseSettingsSource, + file_secret_settings: PydanticBaseSettingsSource, + ) -> tuple[PydanticBaseSettingsSource, ...]: + return ( + YamlConfigSettingsSource(settings_cls), + init_settings, + env_settings, + dotenv_settings, + file_secret_settings, + ) + + + +