Tips parser complete.

This commit is contained in:
lwark
2024-06-13 09:11:53 -05:00
parent 78c92cd31f
commit e0e3080af0
7 changed files with 311 additions and 66 deletions

View File

@@ -8,13 +8,12 @@ from sqlalchemy.ext.associationproxy import association_proxy
from datetime import date
import logging, re
from tools import check_authorization, setup_lookup, Report, Result
from typing import List, Literal
from typing import List, Literal, Any
from pandas import ExcelFile
from pathlib import Path
from . import Base, BaseClass, Organization
from io import BytesIO
logger = logging.getLogger(f'submissions.{__name__}')
# logger.debug("Table for ReagentType/Reagent relations")
@@ -79,14 +78,6 @@ tiproles_tips = Table(
extend_existing=True
)
submissions_tips = Table(
"_submissions_tips",
Base.metadata,
Column("submission_id", INTEGER, ForeignKey("_basicsubmissions.id")),
Column("tips_id", INTEGER, ForeignKey("_tips.id")),
extend_existing=True
)
process_tiprole = Table(
"_process_tiprole",
Base.metadata,
@@ -95,6 +86,15 @@ process_tiprole = Table(
extend_existing=True
)
equipment_tips = Table(
"_equipment_tips",
Base.metadata,
Column("equipment_id", INTEGER, ForeignKey("_equipment.id")),
Column("tips_id", INTEGER, ForeignKey("_tips.id")),
extend_existing=True
)
class KitType(BaseClass):
"""
Base of kits used in submission processing
@@ -133,7 +133,8 @@ class KitType(BaseClass):
"""
return f"<KitType({self.name})>"
def get_reagents(self, required: bool = False, submission_type: str | SubmissionType | None = None) -> List[ReagentRole]:
def get_reagents(self, required: bool = False, submission_type: str | SubmissionType | None = None) -> List[
ReagentRole]:
"""
Return ReagentTypes linked to kit through KitTypeReagentTypeAssociation.
@@ -143,7 +144,7 @@ class KitType(BaseClass):
Returns:
List[ReagentRole]: List of reagents linked to this kit.
"""
"""
match submission_type:
case SubmissionType():
# logger.debug(f"Getting reagents by SubmissionType {submission_type}")
@@ -609,6 +610,12 @@ class SubmissionType(BaseClass):
cascade="all, delete-orphan"
) #: triple association of KitTypes, ReagentTypes, SubmissionTypes
submissiontype_tiprole_associations = relationship(
"SubmissionTypeTipRoleAssociation",
back_populates="submission_type",
cascade="all, delete-orphan"
)
def __repr__(self) -> str:
"""
Returns:
@@ -656,7 +663,7 @@ class SubmissionType(BaseClass):
Returns:
dict: Map of locations
"""
"""
info = self.info_map
# logger.debug(f"Info map: {info}")
output = {}
@@ -674,7 +681,7 @@ class SubmissionType(BaseClass):
Returns:
dict: sample location map
"""
"""
return self.sample_map
def construct_equipment_map(self) -> dict:
@@ -693,6 +700,15 @@ class SubmissionType(BaseClass):
output[item.equipment_role.name] = emap
return output
def construct_tips_map(self):
output = {}
for item in self.submissiontype_tiprole_associations:
tmap = item.uses
if tmap is None:
tmap = {}
output[item.tip_role.name] = tmap
return output
def get_equipment(self, extraction_kit: str | KitType | None = None) -> List['PydEquipmentRole']:
"""
Returns PydEquipmentRole of all equipment associated with this SubmissionType
@@ -735,7 +751,7 @@ class SubmissionType(BaseClass):
Returns:
BasicSubmission: Submission class
"""
"""
from .submissions import BasicSubmission
return BasicSubmission.find_polymorphic_subclass(polymorphic_identity=self.name)
@@ -1071,6 +1087,8 @@ class Equipment(BaseClass):
secondary=equipmentroles_equipment) #: relation to EquipmentRoles
processes = relationship("Process", back_populates="equipment",
secondary=equipment_processes) #: relation to Processes
tips = relationship("Tips", back_populates="equipment",
secondary=equipment_tips) #: relation to Processes
equipment_submission_associations = relationship(
"SubmissionEquipmentAssociation",
back_populates="equipment",
@@ -1467,7 +1485,7 @@ class Process(BaseClass):
backref='process') #: relation to SubmissionEquipmentAssociation
kit_types = relationship("KitType", back_populates='processes',
secondary=kittypes_processes) #: relation to KitType
tip_roles = relationship("TipRoles", back_populates='processes',
tip_roles = relationship("TipRole", back_populates='processes',
secondary=process_tiprole) #: relation to KitType
def __repr__(self) -> str:
@@ -1502,19 +1520,25 @@ class Process(BaseClass):
class TipRole(BaseClass):
id = Column(INTEGER, primary_key=True) #: primary key
name = Column(String(64)) #: name of reagent type
instances = relationship("Tips", back_populates="role",
secondary=tiproles_tips) #: concrete instances of this reagent type
processes = relationship("Process", back_populates="tip_roles", secondary=process_tiprole)
tiprole_submissiontype_associations = relationship(
"SubmissionTypeTipRoleAssociation",
back_populates="tip_role",
cascade="all, delete-orphan"
) #: associated submission
submission_types = association_proxy("tiprole_submissiontype_associations", "submission_type")
def __repr__(self):
return f"<TipRole({self.name})>"
class Tips(BaseClass):
class Tips(BaseClass):
id = Column(INTEGER, primary_key=True) #: primary key
role = relationship("TipRole", back_populates="instances",
secondary=tiproles_tips) #: joined parent reagent type
@@ -1522,10 +1546,64 @@ class Tips(BaseClass):
name="fk_tip_role_id")) #: id of parent reagent type
name = Column(String(64)) #: tip common name
lot = Column(String(64)) #: lot number of tips
submissions = relationship("BasicSubmission", back_populates="tips",
secondary=submissions_tips) #: associated submission
equipment = relationship("Equipment", back_populates="tips",
secondary=equipment_tips) #: associated submission
tips_submission_associations = relationship(
"SubmissionTipsAssociation",
back_populates="tips",
cascade="all, delete-orphan"
) #: associated submission
submissions = association_proxy("tips_submission_associations", 'submission')
def __repr__(self):
return f"<Tips({self.name})>"
@classmethod
def query(cls, name: str | None = None, lot: str | None = None, limit: int = 0, **kwargs) -> Any | List[Any]:
query = cls.__database_session__.query(cls)
match name:
case str():
# logger.debug(f"Lookup Equipment by name str {name}")
query = query.filter(cls.name == name)
case _:
pass
match lot:
case str():
# logger.debug(f"Lookup Equipment by nickname str {nickname}")
query = query.filter(cls.lot == lot)
limit = 1
case _:
pass
return cls.execute_query(query=query, limit=limit)
class SubmissionTypeTipRoleAssociation(BaseClass):
"""
Abstract association between SubmissionType and TipRole
"""
tiprole_id = Column(INTEGER, ForeignKey("_tiprole.id"), primary_key=True) #: id of associated equipment
submissiontype_id = Column(INTEGER, ForeignKey("_submissiontype.id"),
primary_key=True) #: id of associated submission
uses = Column(JSON) #: locations of equipment on the submission type excel sheet.
static = Column(INTEGER,
default=1) #: if 1 this piece of equipment will always be used, otherwise it will need to be selected from list?
submission_type = relationship(SubmissionType,
back_populates="submissiontype_tiprole_associations") #: associated submission
tip_role = relationship(TipRole,
back_populates="tiprole_submissiontype_associations") #: associated equipment
class SubmissionTipsAssociation(BaseClass):
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",
back_populates="submission_tips_associations") #: associated submission
tips = relationship(Tips,
back_populates="tips_submission_associations") #: associated equipment
role_name = Column(String(32)) #, ForeignKey("_tiprole.name"))
# role = relationship(TipRole)
def to_sub_dict(self):
return dict(role=self.role_name, name=self.tips.name, lot=self.tips.lot)