Created WastewaterArticAssociation, added tip handling.
This commit is contained in:
@@ -1520,6 +1520,9 @@ class Process(BaseClass):
|
|||||||
|
|
||||||
|
|
||||||
class TipRole(BaseClass):
|
class TipRole(BaseClass):
|
||||||
|
"""
|
||||||
|
An abstract role that a tip fills during a process
|
||||||
|
"""
|
||||||
id = Column(INTEGER, primary_key=True) #: primary key
|
id = Column(INTEGER, primary_key=True) #: primary key
|
||||||
name = Column(String(64)) #: name of reagent type
|
name = Column(String(64)) #: name of reagent type
|
||||||
instances = relationship("Tips", back_populates="role",
|
instances = relationship("Tips", back_populates="role",
|
||||||
@@ -1539,6 +1542,9 @@ class TipRole(BaseClass):
|
|||||||
|
|
||||||
|
|
||||||
class Tips(BaseClass):
|
class Tips(BaseClass):
|
||||||
|
"""
|
||||||
|
A concrete instance of tips.
|
||||||
|
"""
|
||||||
id = Column(INTEGER, primary_key=True) #: primary key
|
id = Column(INTEGER, primary_key=True) #: primary key
|
||||||
role = relationship("TipRole", back_populates="instances",
|
role = relationship("TipRole", back_populates="instances",
|
||||||
secondary=tiproles_tips) #: joined parent reagent type
|
secondary=tiproles_tips) #: joined parent reagent type
|
||||||
@@ -1560,7 +1566,18 @@ class Tips(BaseClass):
|
|||||||
return f"<Tips({self.name})>"
|
return f"<Tips({self.name})>"
|
||||||
|
|
||||||
@classmethod
|
@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)
|
query = cls.__database_session__.query(cls)
|
||||||
match name:
|
match name:
|
||||||
case str():
|
case str():
|
||||||
@@ -1595,6 +1612,9 @@ class SubmissionTypeTipRoleAssociation(BaseClass):
|
|||||||
|
|
||||||
|
|
||||||
class SubmissionTipsAssociation(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
|
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_id = Column(INTEGER, ForeignKey("_basicsubmission.id"), primary_key=True) #: id of associated submission
|
||||||
submission = relationship("BasicSubmission",
|
submission = relationship("BasicSubmission",
|
||||||
@@ -1605,5 +1625,11 @@ class SubmissionTipsAssociation(BaseClass):
|
|||||||
|
|
||||||
# role = relationship(TipRole)
|
# 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)
|
return dict(role=self.role_name, name=self.tips.name, lot=self.tips.lot)
|
||||||
|
|||||||
@@ -2576,6 +2576,10 @@ class SubmissionSampleAssociation(BaseClass):
|
|||||||
|
|
||||||
|
|
||||||
class WastewaterAssociation(SubmissionSampleAssociation):
|
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)
|
id = Column(INTEGER, ForeignKey("_submissionsampleassociation.id"), primary_key=True)
|
||||||
ct_n1 = Column(FLOAT(2)) #: AKA ct for N1
|
ct_n1 = Column(FLOAT(2)) #: AKA ct for N1
|
||||||
ct_n2 = Column(FLOAT(2)) #: AKA ct for N2
|
ct_n2 = Column(FLOAT(2)) #: AKA ct for N2
|
||||||
@@ -2635,7 +2639,10 @@ class WastewaterAssociation(SubmissionSampleAssociation):
|
|||||||
|
|
||||||
|
|
||||||
class WastewaterArticAssociation(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)
|
id = Column(INTEGER, ForeignKey("_submissionsampleassociation.id"), primary_key=True)
|
||||||
source_plate = Column(String(16))
|
source_plate = Column(String(16))
|
||||||
source_plate_number = Column(INTEGER)
|
source_plate_number = Column(INTEGER)
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ class SheetParser(object):
|
|||||||
parser = InfoParser(xl=self.xl, submission_type=self.submission_type, sub_object=self.sub_object)
|
parser = InfoParser(xl=self.xl, submission_type=self.submission_type, sub_object=self.sub_object)
|
||||||
info = parser.parse_info()
|
info = parser.parse_info()
|
||||||
self.info_map = parser.map
|
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():
|
for k, v in info.items():
|
||||||
match k:
|
match k:
|
||||||
case "sample":
|
case "sample":
|
||||||
@@ -96,7 +95,6 @@ class SheetParser(object):
|
|||||||
"""
|
"""
|
||||||
parser = SampleParser(xl=self.xl, submission_type=self.submission_type)
|
parser = SampleParser(xl=self.xl, submission_type=self.submission_type)
|
||||||
self.sub['samples'] = parser.reconcile_samples()
|
self.sub['samples'] = parser.reconcile_samples()
|
||||||
# self.plate_map = parser.plate_map
|
|
||||||
|
|
||||||
def parse_equipment(self):
|
def parse_equipment(self):
|
||||||
parser = EquipmentParser(xl=self.xl, submission_type=self.submission_type)
|
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.
|
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)
|
self.sub = self.sub_object.finalize_parse(input_dict=self.sub, xl=self.xl, info_map=self.info_map)
|
||||||
|
|
||||||
def to_pydantic(self) -> PydSubmission:
|
def to_pydantic(self) -> PydSubmission:
|
||||||
@@ -264,16 +260,15 @@ class ReagentParser(object):
|
|||||||
if isinstance(extraction_kit, dict):
|
if isinstance(extraction_kit, dict):
|
||||||
extraction_kit = extraction_kit['value']
|
extraction_kit = extraction_kit['value']
|
||||||
self.kit_object = KitType.query(name=extraction_kit)
|
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}")
|
# logger.debug(f"Reagent Parser map: {self.map}")
|
||||||
self.xl = xl
|
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
|
Gets location of kit reagents from database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
extraction_kit (dict): Relevant kit information.
|
|
||||||
submission_type (str): Name of submission type.
|
submission_type (str): Name of submission type.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -388,47 +383,6 @@ class SampleParser(object):
|
|||||||
sample_info_map = sample_map
|
sample_info_map = sample_map
|
||||||
return sample_info_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):
|
def parse_plate_map(self):
|
||||||
"""
|
"""
|
||||||
Parse sample location/name from plate map
|
Parse sample location/name from plate map
|
||||||
@@ -614,6 +568,8 @@ class EquipmentParser(object):
|
|||||||
asset = self.get_asset_number(input=asset)
|
asset = self.get_asset_number(input=asset)
|
||||||
logger.debug(f"asset: {asset}")
|
logger.debug(f"asset: {asset}")
|
||||||
eq = Equipment.query(asset_number=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
|
process = ws.cell(row=v['process']['row'], column=v['process']['column']).value
|
||||||
try:
|
try:
|
||||||
output.append(
|
output.append(
|
||||||
@@ -674,7 +630,6 @@ class TipParser(object):
|
|||||||
previous_asset = asset
|
previous_asset = asset
|
||||||
logger.debug(f"asset: {asset}")
|
logger.debug(f"asset: {asset}")
|
||||||
eq = Tips.query(lot=lot, name=asset, limit=1)
|
eq = Tips.query(lot=lot, name=asset, limit=1)
|
||||||
# process = ws.cell(row=v['process']['row'], column=v['process']['column']).value
|
|
||||||
try:
|
try:
|
||||||
output.append(
|
output.append(
|
||||||
dict(name=eq.name, role=k, lot=lot))
|
dict(name=eq.name, role=k, lot=lot))
|
||||||
@@ -705,7 +660,7 @@ class PCRParser(object):
|
|||||||
logger.error(f'Incorrect value: {e}')
|
logger.error(f'Incorrect value: {e}')
|
||||||
self.xl = None
|
self.xl = None
|
||||||
except PermissionError:
|
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
|
return None
|
||||||
if submission is None:
|
if submission is None:
|
||||||
self.submission_obj = Wastewater
|
self.submission_obj = Wastewater
|
||||||
|
|||||||
@@ -128,7 +128,9 @@ class RoleComboBox(QWidget):
|
|||||||
self.process.addItems([item for item in equip2.processes if item in self.role.processes])
|
self.process.addItems([item for item in equip2.processes if item in self.role.processes])
|
||||||
|
|
||||||
def update_tips(self):
|
def update_tips(self):
|
||||||
|
"""
|
||||||
|
Changes what tips are available when process is changed
|
||||||
|
"""
|
||||||
process = self.process.currentText()
|
process = self.process.currentText()
|
||||||
logger.debug(f"Checking process: {process}")
|
logger.debug(f"Checking process: {process}")
|
||||||
process = Process.query(name=process)
|
process = Process.query(name=process)
|
||||||
|
|||||||
Reference in New Issue
Block a user