Renaming ReagentType to ReagentRole

This commit is contained in:
lwark
2024-06-04 15:24:40 -05:00
parent cdcce80898
commit a355c5bb76
8 changed files with 56 additions and 15 deletions

View File

@@ -1,3 +1,8 @@
## 202406.02
- Attached Contact to Submission.
- Renamed ReagentType to ReagentRole to prevent confusion.
## 202405.04
- Improved Webview of submission details.

View File

@@ -83,6 +83,7 @@ class Contact(BaseClass):
email = Column(String(64)) #: contact email
phone = Column(String(32)) #: contact phone number
organization = relationship("Organization", back_populates="contacts", uselist=True, secondary=orgs_contacts) #: relationship to joined organization
submissions = relationship("BasicSubmission", back_populates="contact") #: submissions this contact has submitted
def __repr__(self) -> str:
"""

View File

@@ -10,7 +10,7 @@ from zipfile import ZipFile
from tempfile import TemporaryDirectory
from operator import attrgetter, itemgetter
from pprint import pformat
from . import BaseClass, Reagent, SubmissionType, KitType, Organization
from . import BaseClass, Reagent, SubmissionType, KitType, Organization, Contact
from sqlalchemy import Column, String, TIMESTAMP, INTEGER, ForeignKey, JSON, FLOAT, case
from sqlalchemy.orm import relationship, validates, Query
from sqlalchemy.orm.attributes import flag_modified
@@ -65,6 +65,9 @@ class BasicSubmission(BaseClass):
String(64)) #: ["Research", "Diagnostic", "Surveillance", "Validation"], else defaults to submission_type_name
cost_centre = Column(
String(64)) #: Permanent storage of used cost centre in case organization field changed in the future.
contact = relationship("Contact", back_populates="submissions") #: client org
contact_id = Column(INTEGER, ForeignKey("_contact.id", ondelete="SET NULL",
name="fk_BS_contact_id")) #: client lab id from _organizations
submission_sample_associations = relationship(
"SubmissionSampleAssociation",
@@ -255,6 +258,7 @@ class BasicSubmission(BaseClass):
"sample_count": self.sample_count,
"extraction_kit": ext_kit,
"cost": self.run_cost,
}
if report:
return output
@@ -304,6 +308,9 @@ class BasicSubmission(BaseClass):
output["equipment"] = equipment
output["cost_centre"] = cost_centre
output["signed_by"] = self.signed_by
output["contact"] = self.contact.name
output["contact_phone"] = self.contact.phone
return output
def calculate_column_count(self) -> int:
@@ -453,6 +460,8 @@ class BasicSubmission(BaseClass):
# logger.debug(f"Looking up organization: {value}")
field_value = Organization.query(name=value)
# logger.debug(f"Got {field_value} for organization {value}")
case "contact":
field_value = Contact.query(name=value)
case "samples":
for sample in value:
# logger.debug(f"Parsing {sample} to sql.")
@@ -1196,7 +1205,7 @@ class BacterialCulture(BasicSubmission):
new_lot = matched.group()
try:
pos_control_reg = \
[reg for reg in input_dict['reagents'] if reg['type'] == "Bacterial-Positive Control"][0]
[reg for reg in input_dict['reagents'] if reg['role'] == "Bacterial-Positive Control"][0]
except IndexError:
logger.error(f"No positive control reagent listed")
return input_dict

View File

@@ -148,7 +148,7 @@ class ReagentWriter(object):
output = []
for reagent in reagent_list:
try:
mp_info = map[reagent['type']]
mp_info = map[reagent['role']]
except KeyError:
continue
placeholder = copy(reagent)

View File

@@ -104,7 +104,7 @@ class PydReagent(BaseModel):
if value != None:
return convert_nans_to_nones(str(value))
else:
return values.data['type']
return values.data['role']
def improved_dict(self) -> dict:
try:
@@ -123,7 +123,7 @@ class PydReagent(BaseModel):
# output[k] = value
return {k: getattr(self, k) for k in fields}
def toSQL(self, submission: BasicSubmission | str = None) -> Tuple[Reagent, SubmissionReagentAssociation]:
def toSQL(self, submission: BasicSubmission | str = None) -> Tuple[Reagent, SubmissionReagentAssociation, Report]:
"""
Converts this instance into a backend.db.models.kit.Reagent instance
@@ -168,6 +168,7 @@ class PydReagent(BaseModel):
# reagent.reagent_submission_associations.append(assoc)
else:
assoc = None
report.add_result(Result(owner = __name__, code=0, msg="New reagent created.", status="Information"))
else:
if submission is not None and reagent not in submission.reagents:
assoc = SubmissionReagentAssociation(reagent=reagent, submission=submission)
@@ -177,7 +178,8 @@ class PydReagent(BaseModel):
assoc = None
# add end-of-life extension from reagent type to expiry date
# NOTE: this will now be done only in the reporting phase to account for potential changes in end-of-life extensions
return reagent, assoc
return reagent, assoc, report
class PydSample(BaseModel, extra='allow'):
@@ -353,6 +355,7 @@ class PydSubmission(BaseModel, extra='allow'):
samples: List[PydSample]
equipment: List[PydEquipment] | None = []
cost_centre: dict | None = Field(default=dict(value=None, missing=True), validate_default=True)
contact: dict | None = Field(default=dict(value=None, missing=True), validate_default=True)
@field_validator('equipment', mode='before')
@classmethod
@@ -567,6 +570,17 @@ class PydSubmission(BaseModel, extra='allow'):
case _:
return value
@field_validator("contact")
@classmethod
def get_contact_from_org(cls, value, values):
check = Contact.query(name=value['value'])
if check is None:
org = Organization.query(name=values.data['submitting_lab']['value'])
contact = org.contacts[0].name
return dict(value=contact, missing=True)
else:
return value
def __init__(self, **data):
super().__init__(**data)
# this could also be done with default_factory
@@ -664,7 +678,7 @@ class PydSubmission(BaseModel, extra='allow'):
instance.submission_reagent_associations = []
# logger.debug(f"Looking through {self.reagents}")
for reagent in self.reagents:
reagent, assoc = reagent.toSQL(submission=instance)
reagent, assoc, _ = reagent.toSQL(submission=instance)
# logger.debug(f"Association: {assoc}")
if assoc is not None:# and assoc not in instance.submission_reagent_associations:
instance.submission_reagent_associations.append(assoc)

View File

@@ -153,7 +153,7 @@ class App(QMainWindow):
# logger.debug(f"We've got some results!")
for result in self.report.results:
# logger.debug(f"Showing result: {result}")
if result != None:
if result is not None:
alert = result.report()
if alert.exec():
pass

View File

@@ -33,9 +33,10 @@ class SubmissionFormContainer(QWidget):
# logger.debug(f"Setting form widget...")
super().__init__(parent)
self.app = self.parent().parent()
# logger.debug(f"App: {self.app}")
self.report = Report()
self.setAcceptDrops(True)
# if import_drag is emitted, importSubmission will fire
# NOTE: if import_drag is emitted, importSubmission will fire
self.import_drag.connect(self.importSubmission)
def dragEnterEvent(self, event):
@@ -138,9 +139,10 @@ class SubmissionFormContainer(QWidget):
# NOTE: create reagent object
reagent = PydReagent(ctx=self.app.ctx, **info, missing=False)
# NOTE: send reagent to db
sqlobj, result = reagent.toSQL()
sqlobj, assoc, result = reagent.toSQL()
sqlobj.save()
report.add_result(result)
self.app.report.add_result(report)
self.app.result_reporter()
return reagent
@@ -310,10 +312,14 @@ class SubmissionFormWidget(QWidget):
else:
self.app.ctx.database_session.rollback()
report.add_result(Result(msg="Overwrite cancelled", status="Information"))
self.app.report.add_result(report)
self.app.result_reporter()
return
# code 2: No RSL plate number given
case 2:
report.add_result(result)
self.app.report.add_result(report)
self.app.result_reporter()
return
case _:
pass
@@ -585,7 +591,7 @@ class SubmissionFormWidget(QWidget):
# NOTE: if reagent doesn't exist in database, offer to add it (uses App.add_reagent)
if wanted_reagent == None:
dlg = QuestionAsker(title=f"Add {lot}?",
message=f"Couldn't find reagent type {self.reagent.type}: {lot} in the database.\n\nWould you like to add it?")
message=f"Couldn't find reagent type {self.reagent.role}: {lot} in the database.\n\nWould you like to add it?")
if dlg.exec():
wanted_reagent = self.parent().parent().add_reagent(reagent_lot=lot, reagent_role=self.reagent.role,
expiry=self.reagent.expiry,
@@ -686,3 +692,4 @@ class SubmissionFormWidget(QWidget):
# logger.debug(f"New relevant reagents: {relevant_reagents}")
self.setObjectName(f"lot_{reagent.role}")
self.addItems(relevant_reagents)
self.setStyleSheet("{ background-color: white }")

View File

@@ -375,7 +375,10 @@ class CustomFormatter(logging.Formatter):
def format(self, record):
log_fmt = self.FORMATS.get(record.levelno)
formatter = logging.Formatter(log_fmt)
return formatter.format(record)
if check_if_app():
return record
else:
return formatter.format(record)
class StreamToLogger(object):
@@ -473,7 +476,7 @@ def jinja_template_loading() -> Environment:
Returns jinja2 template environment.
Returns:
_type_: _description_
Environment: jinja2 environment object
"""
# NOTE: determine if pyinstaller launcher is being used
if check_if_app():
@@ -577,7 +580,7 @@ class Report(BaseModel):
def add_result(self, result: Result | Report | None):
match result:
case Result():
logger.debug(f"Adding {result} to results.")
logger.info(f"Adding {result} to results.")
try:
self.results.append(result)
except AttributeError:
@@ -585,11 +588,13 @@ class Report(BaseModel):
case Report():
# logger.debug(f"Adding all results in report to new report")
for res in result.results:
logger.debug(f"Adding {res} from to results.")
logger.info(f"Adding {res} from {result} to results.")
self.results.append(res)
case _:
logger.error(f"Unknown variable type: {type(result)}")
def is_empty(self):
return bool(self.results)
def rreplace(s, old, new):
return (s[::-1].replace(old[::-1], new[::-1], 1))[::-1]