Bugs squashed.

This commit is contained in:
Landon Wark
2023-11-15 14:12:16 -06:00
parent da714c355d
commit 9312a66bb7
8 changed files with 66 additions and 42 deletions

View File

@@ -4,7 +4,7 @@ from pathlib import Path
# Version of the realpython-reader package # Version of the realpython-reader package
__project__ = "submissions" __project__ = "submissions"
__version__ = "202311.2b" __version__ = "202311.3b"
__author__ = {"name":"Landon Wark", "email":"Landon.Wark@phac-aspc.gc.ca"} __author__ = {"name":"Landon Wark", "email":"Landon.Wark@phac-aspc.gc.ca"}
__copyright__ = "2022-2023, Government of Canada" __copyright__ = "2022-2023, Government of Canada"

View File

@@ -1,9 +1,11 @@
import sys import sys
import os import os
# environment variable must be set to enable qtwebengine in network path # environment variable must be set to enable qtwebengine in network path
if getattr(sys, 'frozen', False): # if getattr(sys, 'frozen', False):
# os.environ['QTWEBENGINE_DISABLE_SANDBOX'] = "1"
from tools import get_config, setup_logger, check_if_app
if check_if_app():
os.environ['QTWEBENGINE_DISABLE_SANDBOX'] = "1" os.environ['QTWEBENGINE_DISABLE_SANDBOX'] = "1"
from tools import get_config, setup_logger
# setup custom logger # setup custom logger
logger = setup_logger(verbosity=3) logger = setup_logger(verbosity=3)
# create settings object # create settings object

View File

@@ -471,6 +471,21 @@ class Reagent(Base):
pass pass
return query_return(query=query, limit=limit) return query_return(query=query, limit=limit)
def update_last_used(self, kit:KitType):
report = Report()
logger.debug(f"Attempting update of reagent type at intersection of ({self}), ({kit})")
rt = ReagentType.query(kit_type=kit, reagent=self, limit=1)
if rt != None:
logger.debug(f"got reagenttype {rt}")
assoc = KitTypeReagentTypeAssociation.query(kit_type=kit, reagent_type=rt)
if assoc != None:
if assoc.last_used != self.lot:
logger.debug(f"Updating {assoc} last used to {self.lot}")
assoc.last_used = self.lot
result = assoc.save()
return(report.add_result(result))
return report.add_result(Result(msg=f"Updating last used {rt} was not performed.", status="Information"))
class Discount(Base): class Discount(Base):
""" """
Relationship table for client labs for certain kits. Relationship table for client labs for certain kits.

View File

@@ -25,7 +25,6 @@ from dateutil.parser._parser import ParserError
import yaml import yaml
from sqlalchemy.exc import OperationalError as AlcOperationalError, IntegrityError as AlcIntegrityError, StatementError from sqlalchemy.exc import OperationalError as AlcOperationalError, IntegrityError as AlcIntegrityError, StatementError
from sqlite3 import OperationalError as SQLOperationalError, IntegrityError as SQLIntegrityError from sqlite3 import OperationalError as SQLOperationalError, IntegrityError as SQLIntegrityError
import sys
logger = logging.getLogger(f"submissions.{__name__}") logger = logging.getLogger(f"submissions.{__name__}")
@@ -572,6 +571,17 @@ class BasicSubmission(Base):
except AttributeError: except AttributeError:
logger.error(f"Could not set {self} attribute {key} to {value}") logger.error(f"Could not set {self} attribute {key} to {value}")
def update_subsampassoc(self, sample:BasicSample, input_dict:dict):
assoc = SubmissionSampleAssociation.query(submission=self, sample=sample, limit=1)
for k,v in input_dict.items():
try:
setattr(assoc, k, v)
except AttributeError:
logger.error(f"Can't set {k} to {v}")
# result = store_object(ctx=ctx, object=assoc)
result = assoc.save()
return result
# Below are the custom submission types # Below are the custom submission types
class BacterialCulture(BasicSubmission): class BacterialCulture(BasicSubmission):
@@ -925,6 +935,8 @@ class WastewaterArtic(BasicSubmission):
input_dict['csv'] = df input_dict['csv'] = df
return input_dict return input_dict
# Sample Classes
class BasicSample(Base): class BasicSample(Base):
""" """
Base of basic sample which polymorphs into BCSample and WWSample Base of basic sample which polymorphs into BCSample and WWSample
@@ -1115,6 +1127,8 @@ class BasicSample(Base):
instance.sample_type = sample_type instance.sample_type = sample_type
return instance return instance
#Below are the custom sample types
class WastewaterSample(BasicSample): class WastewaterSample(BasicSample):
""" """
Derivative wastewater sample Derivative wastewater sample
@@ -1199,6 +1213,8 @@ class BacterialCultureSample(BasicSample):
sample['name'] = f"{self.submitter_id} - ({self.organism})" sample['name'] = f"{self.submitter_id} - ({self.organism})"
return sample return sample
# Submission to Sample Associations
class SubmissionSampleAssociation(Base): class SubmissionSampleAssociation(Base):
""" """
table containing submission/sample associations table containing submission/sample associations

View File

@@ -13,7 +13,7 @@ import re
import logging import logging
from tools import check_not_nan, convert_nans_to_nones, jinja_template_loading, Report, Result from tools import check_not_nan, convert_nans_to_nones, jinja_template_loading, Report, Result
from backend.db.models import * from backend.db.models import *
from sqlalchemy.exc import StatementError from sqlalchemy.exc import StatementError, IntegrityError
from PyQt6.QtWidgets import QComboBox, QWidget from PyQt6.QtWidgets import QComboBox, QWidget
from pprint import pformat from pprint import pformat
from openpyxl import load_workbook from openpyxl import load_workbook
@@ -172,7 +172,10 @@ class PydSample(BaseModel, extra='allow'):
submission=submission, submission=submission,
sample=instance, sample=instance,
row=row, column=column) row=row, column=column)
instance.sample_submission_associations.append(association) try:
instance.sample_submission_associations.append(association)
except IntegrityError:
instance.metadata.session.rollback()
return instance, result return instance, result
class PydSubmission(BaseModel, extra='allow'): class PydSubmission(BaseModel, extra='allow'):
@@ -408,9 +411,9 @@ class PydSubmission(BaseModel, extra='allow'):
extraction_kit = KitType.query(name=self.extraction_kit['value']) extraction_kit = KitType.query(name=self.extraction_kit['value'])
logger.debug(f"We have the extraction kit: {extraction_kit.name}") logger.debug(f"We have the extraction kit: {extraction_kit.name}")
excel_map = extraction_kit.construct_xl_map_for_use(self.submission_type['value']) excel_map = extraction_kit.construct_xl_map_for_use(self.submission_type['value'])
logger.debug(f"Extraction kit map:\n\n{pformat(excel_map)}") # logger.debug(f"Extraction kit map:\n\n{pformat(excel_map)}")
logger.debug(f"Missing reagents going into autofile: {pformat(reagents)}") # logger.debug(f"Missing reagents going into autofile: {pformat(reagents)}")
logger.debug(f"Missing info going into autofile: {pformat(info)}") # logger.debug(f"Missing info going into autofile: {pformat(info)}")
new_reagents = [] new_reagents = []
for reagent in reagents: for reagent in reagents:
new_reagent = {} new_reagent = {}

View File

@@ -145,7 +145,7 @@ class SubmissionsSheet(QTableView):
index = (self.selectionModel().currentIndex()) index = (self.selectionModel().currentIndex())
value = index.sibling(index.row(),1).data() value = index.sibling(index.row(),1).data()
logger.debug(f"Selected value: {value}") logger.debug(f"Selected value: {value}")
dlg = SubmissionComment(ctx=self.ctx, rsl=value) dlg = SubmissionComment(rsl=value)
if dlg.exec(): if dlg.exec():
dlg.add_comment() dlg.add_comment()
@@ -455,6 +455,8 @@ class SubmissionDetails(QDialog):
super().__init__(parent) super().__init__(parent)
# self.ctx = ctx # self.ctx = ctx
self.app = parent.parent().parent().parent().parent().parent().parent
print(f"App: {self.app}")
self.setWindowTitle("Submission Details") self.setWindowTitle("Submission Details")
# create scrollable interior # create scrollable interior
interior = QScrollArea() interior = QScrollArea()
@@ -603,10 +605,10 @@ class SubmissionComment(QDialog):
""" """
a window for adding comment text to a submission a window for adding comment text to a submission
""" """
def __init__(self, ctx:Settings, rsl:str) -> None: def __init__(self, rsl:str) -> None:
super().__init__() super().__init__()
self.ctx = ctx # self.ctx = ctx
self.rsl = rsl self.rsl = rsl
self.setWindowTitle(f"{self.rsl} Submission Comment") self.setWindowTitle(f"{self.rsl} Submission Comment")
# create text field # create text field
@@ -640,7 +642,6 @@ class SubmissionComment(QDialog):
except AttributeError: except AttributeError:
sub.comment = [full_comment] sub.comment = [full_comment]
logger.debug(sub.__dict__) logger.debug(sub.__dict__)
self.ctx.database_session.add(sub) sub.save()
self.ctx.database_session.commit()

View File

@@ -11,7 +11,7 @@ from tools import Report, Result, check_not_nan
from backend.excel.parser import SheetParser, PCRParser from backend.excel.parser import SheetParser, PCRParser
from backend.validators import PydSubmission, PydReagent from backend.validators import PydSubmission, PydReagent
from backend.db import ( from backend.db import (
check_kit_integrity, update_last_used, KitType, Organization, SubmissionType, Reagent, check_kit_integrity, KitType, Organization, SubmissionType, Reagent,
ReagentType, KitTypeReagentTypeAssociation, BasicSubmission, update_subsampassoc_with_pcr ReagentType, KitTypeReagentTypeAssociation, BasicSubmission, update_subsampassoc_with_pcr
) )
from pprint import pformat from pprint import pformat
@@ -22,7 +22,7 @@ import difflib
from datetime import date from datetime import date
import inspect import inspect
import json import json
import sys
logger = logging.getLogger(f"submissions.{__name__}") logger = logging.getLogger(f"submissions.{__name__}")
@@ -80,27 +80,6 @@ class SubmissionFormContainer(QWidget):
case _: case _:
self.app.result_reporter() self.app.result_reporter()
# def kit_reload_function(self):
# """
# Reload the fields in the form
# Args:
# obj (QMainWindow): original app window
# Returns:
# Tuple[QMainWindow, dict]: Collection of new main app window and result dict
# """
# report = Report()
# # for item in obj.table_widget.formlayout.parentWidget().findChildren(QWidget):
# logger.debug(f"Attempting to clear {obj.form.find_widgets()}")
# for item in self.form.find_widgets():
# if isinstance(item, ReagentFormWidget):
# item.setParent(None)
# self.kit_integrity_completion_function()
# self.report.add_result(report)
def kit_integrity_completion(self): def kit_integrity_completion(self):
""" """
Performs check of imported reagents Performs check of imported reagents
@@ -296,6 +275,8 @@ class SubmissionFormContainer(QWidget):
self.report.add_result(report) self.report.add_result(report)
return return
base_submission, result = self.pyd.toSQL() base_submission, result = self.pyd.toSQL()
# logger.debug(f"Base submission: {base_submission.to_dict()}")
# sys.exit()
# check output message for issues # check output message for issues
match result.code: match result.code:
# code 0: everything is fine. # code 0: everything is fine.
@@ -303,7 +284,7 @@ class SubmissionFormContainer(QWidget):
self.report.add_result(None) self.report.add_result(None)
# code 1: ask for overwrite # code 1: ask for overwrite
case 1: case 1:
dlg = QuestionAsker(title=f"Review {base_submission.rsl_plate_num}?", message=result['message']) dlg = QuestionAsker(title=f"Review {base_submission.rsl_plate_num}?", message=result.msg)
if dlg.exec(): if dlg.exec():
# Do not add duplicate reagents. # Do not add duplicate reagents.
# base_submission.reagents = [] # base_submission.reagents = []
@@ -320,7 +301,10 @@ class SubmissionFormContainer(QWidget):
pass pass
# add reagents to submission object # add reagents to submission object
for reagent in base_submission.reagents: for reagent in base_submission.reagents:
update_last_used(reagent=reagent, kit=base_submission.extraction_kit) # logger.debug(f"Updating: {reagent} with {reagent.lot}")
# update_last_used(reagent=reagent, kit=base_submission.extraction_kit)
reagent.update_last_used(kit=base_submission.extraction_kit)
# sys.exit()
logger.debug(f"Here is the final submission: {pformat(base_submission.__dict__)}") logger.debug(f"Here is the final submission: {pformat(base_submission.__dict__)}")
logger.debug(f"Parsed reagents: {pformat(base_submission.reagents)}") logger.debug(f"Parsed reagents: {pformat(base_submission.reagents)}")
logger.debug(f"Sending submission: {base_submission.rsl_plate_num} to database.") logger.debug(f"Sending submission: {base_submission.rsl_plate_num} to database.")
@@ -329,7 +313,7 @@ class SubmissionFormContainer(QWidget):
self.app.table_widget.sub_wid.setData() self.app.table_widget.sub_wid.setData()
# reset form # reset form
self.form.setParent(None) self.form.setParent(None)
logger.debug(f"All attributes of obj: {pformat(self.__dict__)}") # logger.debug(f"All attributes of obj: {pformat(self.__dict__)}")
wkb = self.pyd.autofill_excel() wkb = self.pyd.autofill_excel()
if wkb != None: if wkb != None:
fname = select_save_file(obj=self, default_name=self.pyd.construct_filename(), extension="xlsx") fname = select_save_file(obj=self, default_name=self.pyd.construct_filename(), extension="xlsx")
@@ -352,6 +336,7 @@ class SubmissionFormContainer(QWidget):
fname = select_save_file(obj=self, default_name=self.pyd.construct_filename(), extension="csv") fname = select_save_file(obj=self, default_name=self.pyd.construct_filename(), extension="csv")
try: try:
self.pyd.csv.to_csv(fname.__str__(), index=False) self.pyd.csv.to_csv(fname.__str__(), index=False)
del self.pyd.csv
except PermissionError: except PermissionError:
logger.debug(f"Could not get permissions to {fname}. Possibly the request was cancelled.") logger.debug(f"Could not get permissions to {fname}. Possibly the request was cancelled.")
@@ -424,7 +409,8 @@ class SubmissionFormContainer(QWidget):
sample_dict = [item for item in parser.samples if item['sample']==sample.rsl_number][0] sample_dict = [item for item in parser.samples if item['sample']==sample.rsl_number][0]
except IndexError: except IndexError:
continue continue
update_subsampassoc_with_pcr(submission=sub, sample=sample, input_dict=sample_dict) # update_subsampassoc_with_pcr(submission=sub, sample=sample, input_dict=sample_dict)
sub.update_subsampassoc(sample=sample, input_dict=sample_dict)
self.report.add_result(Result(msg=f"We added PCR info to {sub.rsl_plate_num}.", status='Information')) self.report.add_result(Result(msg=f"We added PCR info to {sub.rsl_plate_num}.", status='Information'))
# return obj, result # return obj, result
@@ -481,6 +467,7 @@ class SubmissionFormWidget(QWidget):
info[field] = value info[field] = value
logger.debug(f"Info: {pformat(info)}") logger.debug(f"Info: {pformat(info)}")
logger.debug(f"Reagents: {pformat(reagents)}") logger.debug(f"Reagents: {pformat(reagents)}")
# sys.exit()
# app = self.parent().parent().parent().parent().parent().parent().parent().parent # app = self.parent().parent().parent().parent().parent().parent().parent().parent
submission = PydSubmission(filepath=self.filepath, reagents=reagents, samples=self.samples, **info) submission = PydSubmission(filepath=self.filepath, reagents=reagents, samples=self.samples, **info)
return submission return submission

View File

@@ -35,7 +35,7 @@
</style> </style>
<title>Submission Details for {{ sub['Plate Number'] }}</title> <title>Submission Details for {{ sub['Plate Number'] }}</title>
</head> </head>
{% set excluded = ['reagents', 'samples', 'controls', 'ext_info', 'pcr_info', 'comments', 'barcode', 'platemap'] %} {% set excluded = ['reagents', 'samples', 'controls', 'ext_info', 'pcr_info', 'comments', 'barcode', 'platemap', 'export_map'] %}
<body> <body>
<h2><u>Submission Details for {{ sub['Plate Number'] }}</u></h2>&nbsp;&nbsp;&nbsp;{% if sub['barcode'] %}<img align='right' height="30px" width="120px" src="data:image/jpeg;base64,{{ sub['barcode'] | safe }}">{% endif %} <h2><u>Submission Details for {{ sub['Plate Number'] }}</u></h2>&nbsp;&nbsp;&nbsp;{% if sub['barcode'] %}<img align='right' height="30px" width="120px" src="data:image/jpeg;base64,{{ sub['barcode'] | safe }}">{% endif %}
<p>{% for key, value in sub.items() if key not in excluded %} <p>{% for key, value in sub.items() if key not in excluded %}