Bugs squashed.
This commit is contained in:
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
try:
|
||||||
instance.sample_submission_associations.append(association)
|
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 = {}
|
||||||
|
|||||||
@@ -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()
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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> {% 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> {% 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 %}
|
||||||
|
|||||||
Reference in New Issue
Block a user