Added Postgres support.

This commit is contained in:
lwark
2024-07-25 08:41:44 -05:00
parent 54e1e55804
commit 4bc5e08ac6
32 changed files with 579 additions and 1030 deletions

View File

@@ -1,6 +1,6 @@
'''
"""
Constructs main application.
'''
"""
from PyQt6.QtWidgets import (
QTabWidget, QWidget, QVBoxLayout,
QHBoxLayout, QScrollArea, QMainWindow,
@@ -13,7 +13,7 @@ from markdown import markdown
from tools import check_if_app, Settings, Report, jinja_template_loading
from datetime import date
from .pop_ups import AlertPop, HTMLPop
from .pop_ups import HTMLPop
from .misc import LogParser
import logging, webbrowser, sys, shutil
from .submission_table import SubmissionsSheet
@@ -36,7 +36,7 @@ class App(QMainWindow):
self.report = Report()
# NOTE: indicate version and connected database in title bar
try:
self.title = f"Submissions App (v{ctx.package.__version__}) - {ctx.database_path}"
self.title = f"Submissions App (v{ctx.package.__version__}) - {ctx.database_session.get_bind().url}"
except (AttributeError, KeyError):
self.title = f"Submissions App"
# NOTE: set initial app position and size
@@ -164,27 +164,6 @@ class App(QMainWindow):
instr = HTMLPop(html=html, title="Instructions")
instr.exec()
def result_reporter(self):
"""
Report any anomolous results - if any - to the user
Args:
result (dict | None, optional): The result from a function. Defaults to None.
"""
# logger.debug(f"Running results reporter for: {self.report.results}")
if len(self.report.results) > 0:
# logger.debug(f"We've got some results!")
for result in self.report.results:
# logger.debug(f"Showing result: {result}")
if result is not None:
alert = result.report()
if alert.exec():
pass
self.report = Report()
else:
self.statusBar().showMessage("Action completed sucessfully.", 5000)
def runSearch(self):
dlg = LogParser(self)
dlg.exec()
@@ -201,12 +180,19 @@ class App(QMainWindow):
Copies the database into the backup directory the first time it is opened every month.
"""
month = date.today().strftime("%Y-%m")
current_month_bak = Path(self.ctx.backup_path).joinpath(f"submissions_backup-{month}").resolve()
# logger.debug(f"Here is the db directory: {self.ctx.database_path}")
# logger.debug(f"Here is the backup directory: {self.ctx.backup_path}")
current_month_bak = Path(self.ctx.backup_path).joinpath(f"submissions_backup-{month}").resolve().with_suffix(".db")
if not current_month_bak.exists() and "demo" not in self.ctx.database_path.__str__():
logger.info("No backup found for this month, backing up database.")
shutil.copyfile(self.ctx.database_path, current_month_bak)
match self.ctx.database_schema:
case "sqlite":
current_month_bak = current_month_bak.with_suffix(".db")
if not current_month_bak.exists() and "demo" not in self.ctx.database_path.__str__():
logger.info("No backup found for this month, backing up database.")
shutil.copyfile(self.ctx.database_path, current_month_bak)
case "postgresql+psycopg2":
logger.warning(f"Backup function not yet implemented for psql")
current_month_bak = current_month_bak.with_suffix(".psql")
class AddSubForm(QWidget):

View File

@@ -15,7 +15,7 @@ logger = logging.getLogger(f"submissions.{__name__}")
class EquipmentUsage(QDialog):
def __init__(self, parent, submission: BasicSubmission) -> QDialog:
def __init__(self, parent, submission: BasicSubmission):
super().__init__(parent)
self.submission = submission
self.setWindowTitle(f"Equipment Checklist - {submission.rsl_plate_num}")
@@ -139,7 +139,7 @@ class RoleComboBox(QWidget):
Changes what tips are available when process is changed
"""
process = self.process.currentText().strip()
logger.debug(f"Checking process: {process} for equipment {self.role.name}")
# logger.debug(f"Checking process: {process} for equipment {self.role.name}")
process = Process.query(name=process)
if process.tip_roles:
for iii, tip_role in enumerate(process.tip_roles):

View File

@@ -21,10 +21,10 @@ logger = logging.getLogger(f"submissions.{__name__}")
# Main window class
class GelBox(QDialog):
def __init__(self, parent, img_path:str|Path, submission:WastewaterArtic):
def __init__(self, parent, img_path: str | Path, submission: WastewaterArtic):
super().__init__(parent)
# NOTE: setting title
self.setWindowTitle("PyQtGraph")
self.setWindowTitle(f"Gel - {img_path}")
self.img_path = img_path
self.submission = submission
# NOTE: setting geometry
@@ -41,7 +41,7 @@ class GelBox(QDialog):
def UiComponents(self):
"""
Create widgets in ui
"""
"""
# NOTE: setting configuration options
pg.setConfigOptions(antialias=True)
# NOTE: creating image view object
@@ -49,41 +49,42 @@ class GelBox(QDialog):
# NOTE: Create image.
# NOTE: For some reason, ImageView wants to flip the image, so we have to rotate and flip the array first.
# NOTE: Using the Image.rotate function results in cropped image, so using np.
img = np.flip(np.rot90(np.array(Image.open(self.img_path)),1),0)
img = np.flip(np.rot90(np.array(Image.open(self.img_path)), 1), 0)
self.imv.setImage(img)
layout = QGridLayout()
layout.addWidget(QLabel("DNA Core Submission Number"),0,1)
layout.addWidget(QLabel("DNA Core Submission Number"), 21, 1)
self.core_number = QLineEdit()
self.core_number.setText(self.submission.dna_core_submission_number)
layout.addWidget(self.core_number, 0,2)
layout.addWidget(QLabel("Gel Barcode"),0,3)
layout.addWidget(self.core_number, 21, 2)
layout.addWidget(QLabel("Gel Barcode"), 21, 3)
self.gel_barcode = QLineEdit()
self.gel_barcode.setText(self.submission.gel_barcode)
layout.addWidget(self.gel_barcode, 0, 4)
layout.addWidget(self.gel_barcode, 21, 4)
# NOTE: setting this layout to the widget
# NOTE: plot window goes on right side, spanning 3 rows
layout.addWidget(self.imv, 1, 1,20,20)
layout.addWidget(self.imv, 0, 1, 20, 20)
# NOTE: setting this widget as central widget of the main window
try:
control_info = sorted(self.submission.gel_controls, key=lambda d: d['location'])
except KeyError:
control_info = None
self.form = ControlsForm(parent=self, control_info=control_info)
layout.addWidget(self.form,22,1,1,4)
layout.addWidget(self.form, 22, 1, 1, 4)
QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
layout.addWidget(self.buttonBox, 23, 1, 1, 1)#, alignment=Qt.AlignmentFlag.AlignTop)
layout.addWidget(self.buttonBox, 23, 1, 1, 1) #, alignment=Qt.AlignmentFlag.AlignTop)
self.setLayout(layout)
def parse_form(self) -> Tuple[str, str|Path, list]:
def parse_form(self) -> Tuple[str, str | Path, list]:
"""
Get relevant values from self/form
Returns:
Tuple[str, str|Path, list]: output values
"""
"""
dna_core_submission_number = self.core_number.text()
gel_barcode = self.gel_barcode.text()
values, comment = self.form.parse_form()
@@ -92,7 +93,7 @@ class GelBox(QDialog):
class ControlsForm(QWidget):
def __init__(self, parent, control_info:List=None) -> None:
def __init__(self, parent, control_info: List = None) -> None:
super().__init__(parent)
self.layout = QGridLayout()
columns = []
@@ -101,9 +102,10 @@ class ControlsForm(QWidget):
tt_text = "\n".join([f"{item['sample_id']} - CELL {item['location']}" for item in control_info])
except TypeError:
tt_text = None
for iii, item in enumerate(["Negative Control Key", "Description", "Results - 65 C", "Results - 63 C", "Results - Spike"]):
for iii, item in enumerate(
["Negative Control Key", "Description", "Results - 65 C", "Results - 63 C", "Results - Spike"]):
label = QLabel(item)
self.layout.addWidget(label, 0, iii,1,1)
self.layout.addWidget(label, 0, iii, 1, 1)
if iii > 1:
columns.append(item)
elif iii == 0:
@@ -114,7 +116,8 @@ class ControlsForm(QWidget):
label = QLabel(item)
self.layout.addWidget(label, iii, 0, 1, 1)
rows.append(item)
for iii, item in enumerate(["Processing Negative (PBS)", "Extraction Negative (Extraction buffers ONLY)", "Artic no-template control (mastermix ONLY)"], start=1):
for iii, item in enumerate(["Processing Negative (PBS)", "Extraction Negative (Extraction buffers ONLY)",
"Artic no-template control (mastermix ONLY)"], start=1):
label = QLabel(item)
self.layout.addWidget(label, iii, 1, 1, 1)
for iii in range(3):
@@ -125,11 +128,11 @@ class ControlsForm(QWidget):
widge.setCurrentIndex(0)
widge.setEditable(True)
widge.setObjectName(f"{rows[iii]} : {columns[jjj]}")
self.layout.addWidget(widge, iii+1, jjj+2, 1, 1)
self.layout.addWidget(QLabel("Comments:"), 0,5,1,1)
self.layout.addWidget(widge, iii + 1, jjj + 2, 1, 1)
self.layout.addWidget(QLabel("Comments:"), 0, 5, 1, 1)
self.comment_field = QTextEdit(self)
self.comment_field.setFixedHeight(50)
self.layout.addWidget(self.comment_field, 1,5,4,1)
self.layout.addWidget(self.comment_field, 1, 5, 4, 1)
self.setLayout(self.layout)
def parse_form(self) -> List[dict]:
@@ -138,12 +141,12 @@ class ControlsForm(QWidget):
Returns:
List[dict]: output of values
"""
"""
output = []
for le in self.findChildren(QComboBox):
label = [item.strip() for item in le.objectName().split(" : ")]
try:
dicto = [item for item in output if item['name']==label[0]][0]
dicto = [item for item in output if item['name'] == label[0]][0]
except IndexError:
dicto = dict(name=label[0], values=[])
dicto['values'].append(dict(name=label[1], value=le.currentText()))

View File

@@ -8,7 +8,7 @@ from PyQt6.QtWidgets import (
QDialogButtonBox, QDateEdit, QPushButton, QFormLayout
)
from PyQt6.QtCore import Qt, QDate
from tools import jinja_template_loading, Settings
from tools import jinja_template_loading
from backend.db.models import *
import logging
from .pop_ups import AlertPop
@@ -45,18 +45,19 @@ class AddReagentForm(QDialog):
self.exp_input.setObjectName('expiry')
# NOTE: if expiry is not passed in from gui, use today
if expiry is None:
self.exp_input.setDate(QDate.currentDate())
# self.exp_input.setDate(QDate.currentDate())
self.exp_input.setDate(QDate(1970, 1, 1))
else:
try:
self.exp_input.setDate(expiry)
except TypeError:
self.exp_input.setDate(QDate.currentDate())
self.exp_input.setDate(QDate(1970, 1, 1))
# NOTE: widget to get reagent type info
self.type_input = QComboBox()
self.type_input.setObjectName('type')
self.type_input.addItems([item.name for item in ReagentRole.query()])
# logger.debug(f"Trying to find index of {reagent_type}")
# NOTE: convert input to user friendly string?
# NOTE: convert input to user-friendly string?
try:
reagent_role = reagent_role.replace("_", " ").title()
except AttributeError:

View File

@@ -7,8 +7,8 @@ from PyQt6.QtWidgets import QTableView, QMenu
from PyQt6.QtCore import Qt, QAbstractTableModel, QSortFilterProxyModel
from PyQt6.QtGui import QAction, QCursor
from backend.db.models import BasicSubmission
from backend.excel import make_report_html, make_report_xlsx, ReportMaker
from tools import Report, Result, row_map, get_first_blank_df_row, html_to_pdf
from backend.excel import ReportMaker
from tools import Report, Result, report_result
from .functions import select_save_file, select_open_file
from .misc import ReportDatePicker
import pandas as pd
@@ -129,14 +129,15 @@ class SubmissionsSheet(QTableView):
func = self.con_actions[action_name]
func(obj=self)
@report_result
def link_extractions(self):
"""
Pull extraction logs into the db
"""
self.link_extractions_function()
self.app.report.add_result(self.report)
"""
self.report = Report()
self.app.result_reporter()
self.link_extractions_function()
self.report.add_result(self.report)
return self.report
def link_extractions_function(self):
"""
@@ -179,6 +180,7 @@ class SubmissionsSheet(QTableView):
sub.save()
self.report.add_result(Result(msg=f"We added {count} logs to the database.", status='Information'))
@report_result
def link_pcr(self):
"""
Pull pcr logs into the db
@@ -186,7 +188,7 @@ class SubmissionsSheet(QTableView):
self.link_pcr_function()
self.app.report.add_result(self.report)
self.report = Report()
self.app.result_reporter()
return self.report
def link_pcr_function(self):
"""
@@ -225,15 +227,15 @@ class SubmissionsSheet(QTableView):
# NOTE: check if pcr_info already exists
sub.save()
self.report.add_result(Result(msg=f"We added {count} logs to the database.", status='Information'))
@report_result
def generate_report(self):
"""
Make a report
"""
self.generate_report_function()
self.app.report.add_result(self.report)
"""
self.report = Report()
self.app.result_reporter()
self.generate_report_function()
return self.report
def generate_report_function(self):
"""
@@ -250,43 +252,7 @@ class SubmissionsSheet(QTableView):
dlg = ReportDatePicker()
if dlg.exec():
info = dlg.parse_form()
# logger.debug(f"Report info: {info}")
# NOTE: find submissions based on date range
subs = BasicSubmission.query(start_date=info['start_date'], end_date=info['end_date'])
# NOTE: convert each object to dict
records = [item.to_dict(report=True) for item in subs]
# logger.debug(f"Records: {pformat(records)}")
# NOTE: make dataframe from record dictionaries
detailed_df, summary_df = make_report_xlsx(records=records)
html = make_report_html(df=summary_df, start_date=info['start_date'], end_date=info['end_date'])
# NOTE: get save location of report
fname = select_save_file(obj=self, default_name=f"Submissions_Report_{info['start_date']}-{info['end_date']}.docx", extension="docx")
# html_to_pdf(html=html, output_file=fname)
# writer = pd.ExcelWriter(fname.with_suffix(".xlsx"), engine='openpyxl')
# summary_df.to_excel(writer, sheet_name="Report")
# detailed_df.to_excel(writer, sheet_name="Details", index=False)
# worksheet: Worksheet = writer.sheets['Report']
# for idx, col in enumerate(summary_df, start=1): # loop through all columns
# series = summary_df[col]
# max_len = max((
# series.astype(str).map(len).max(), # len of largest item
# len(str(series.name)) # len of column name/header
# )) + 20 # adding a little extra space
# try:
# # NOTE: Convert idx to letter
# col_letter = chr(ord('@') + idx)
# worksheet.column_dimensions[col_letter].width = max_len
# except ValueError:
# pass
# blank_row = get_first_blank_df_row(summary_df) + 1
# # logger.debug(f"Blank row index = {blank_row}")
# for col in range(3,6):
# col_letter = row_map[col]
# worksheet.cell(row=blank_row, column=col, value=f"=SUM({col_letter}2:{col_letter}{str(blank_row-1)})")
# for cell in worksheet['D']:
# if cell.row > 1:
# cell.style = 'Currency'
# writer.close()
rp = ReportMaker(start_date=info['start_date'], end_date=info['end_date'])
rp.write_report(filename=fname, obj=self)
self.report.add_result(report)

View File

@@ -11,7 +11,7 @@ from pathlib import Path
from . import select_open_file, select_save_file
import logging, difflib, inspect
from pathlib import Path
from tools import Report, Result, check_not_nan, workbook_2_csv, main_form_style
from tools import Report, Result, check_not_nan, workbook_2_csv, main_form_style, report_result
from backend.excel.parser import SheetParser
from backend.validators import PydSubmission, PydReagent
from backend.db import (
@@ -59,17 +59,16 @@ class SubmissionFormContainer(QWidget):
self.app.last_dir = fname.parent
self.import_drag.emit(fname)
@report_result
def importSubmission(self, fname: Path | None = None):
"""
import submission from excel sheet into form
"""
self.app.raise_()
self.app.activateWindow()
self.import_submission_function(fname)
# logger.debug(f"Result from result reporter: {self.report.results}")
self.app.report.add_result(self.report)
self.report = Report()
self.app.result_reporter()
self.import_submission_function(fname)
return self.report
def import_submission_function(self, fname: Path | None = None):
"""
@@ -115,8 +114,9 @@ class SubmissionFormContainer(QWidget):
# logger.debug(f"Outgoing report: {self.report.results}")
# logger.debug(f"All attributes of submission container:\n{pformat(self.__dict__)}")
@report_result
def add_reagent(self, reagent_lot: str | None = None, reagent_role: str | None = None, expiry: date | None = None,
name: str | None = None):
name: str | None = None) -> Tuple[PydReagent, Report]:
"""
Action to create new reagent in DB.
@@ -144,16 +144,18 @@ class SubmissionFormContainer(QWidget):
sqlobj, assoc, result = reagent.toSQL()
sqlobj.save()
report.add_result(result)
self.app.report.add_result(report)
self.app.result_reporter()
return reagent
# logger.debug(f"Reagent: {reagent}, Report: {report}")
return reagent, report
class SubmissionFormWidget(QWidget):
def __init__(self, parent: QWidget, submission: PydSubmission) -> None:
def __init__(self, parent: QWidget, submission: PydSubmission, disable: list | None = None) -> None:
super().__init__(parent)
# self.report = Report()
# logger.debug(f"Disable: {disable}")
if disable is None:
disable = []
self.app = parent.app
self.pyd = submission
self.missing_info = []
@@ -166,12 +168,19 @@ class SubmissionFormWidget(QWidget):
for k in list(self.pyd.model_fields.keys()) + list(self.pyd.model_extra.keys()):
if k in self.ignore:
continue
try:
# logger.debug(f"Key: {k}, Disable: {disable}")
check = k in disable
# logger.debug(f"Check: {check}")
except TypeError:
check = False
try:
value = self.pyd.__getattribute__(k)
except AttributeError:
logger.error(f"Couldn't get attribute from pyd: {k}")
value = dict(value=None, missing=True)
add_widget = self.create_widget(key=k, value=value, submission_type=self.pyd.submission_type['value'], sub_obj=st)
add_widget = self.create_widget(key=k, value=value, submission_type=self.pyd.submission_type['value'],
sub_obj=st, disable=check)
if add_widget is not None:
self.layout.addWidget(add_widget)
if k == "extraction_kit":
@@ -180,11 +189,13 @@ class SubmissionFormWidget(QWidget):
self.scrape_reagents(self.pyd.extraction_kit)
def create_widget(self, key: str, value: dict | PydReagent, submission_type: str | None = None,
extraction_kit: str | None = None, sub_obj:BasicSubmission|None=None) -> "self.InfoItem":
extraction_kit: str | None = None, sub_obj: BasicSubmission | None = None,
disable: bool = False) -> "self.InfoItem":
"""
Make an InfoItem widget to hold a field
Args:
disable ():
key (str): Name of the field
value (dict): Value of field
submission_type (str | None, optional): Submissiontype as str. Defaults to None.
@@ -192,18 +203,25 @@ class SubmissionFormWidget(QWidget):
Returns:
self.InfoItem: Form widget to hold name:value
"""
# logger.debug(f"Key: {key}, Disable: {disable}")
if key not in self.ignore:
match value:
case PydReagent():
if value.name.lower() != "not applicable":
widget = self.ReagentFormWidget(self, reagent=value, extraction_kit=extraction_kit)
else:
widget = None
case _:
widget = self.InfoItem(self, key=key, value=value, submission_type=submission_type, sub_obj=sub_obj)
# logger.debug(f"Setting widget enabled to: {not disable}")
if disable:
widget.input.setEnabled(False)
widget.input.setToolTip("Widget disabled to protect database integrity.")
return widget
return None
@report_result
def scrape_reagents(self, *args, **kwargs): #extraction_kit:str, caller:str|None=None):
"""
Extracted scrape reagents function that will run when
@@ -250,8 +268,7 @@ class SubmissionFormWidget(QWidget):
self.layout.addWidget(submit_btn)
submit_btn.clicked.connect(self.submit_new_sample_function)
self.setLayout(self.layout)
self.app.report.add_result(report)
self.app.result_reporter()
return report
def clear_form(self):
"""
@@ -275,7 +292,8 @@ class SubmissionFormWidget(QWidget):
query = [widget for widget in query if widget.objectName() == object_name]
return query
def submit_new_sample_function(self) -> QWidget:
@report_result
def submit_new_sample_function(self, *args) -> Report:
"""
Parse forms and add sample to the database.
@@ -294,37 +312,40 @@ class SubmissionFormWidget(QWidget):
_, result = self.pyd.check_kit_integrity()
report.add_result(result)
if len(result.results) > 0:
self.app.report.add_result(report)
self.app.result_reporter()
# self.app.report.add_result(report)
# self.app.report_result()
return
# logger.debug(f"PYD before transformation into SQL:\n\n{self.pyd}\n\n")
base_submission, result = self.pyd.to_sql()
# logger.debug(f"SQL object: {pformat(base_submission.__dict__)}")
# logger.debug(f"Base submission: {base_submission.to_dict()}")
# NOTE: check output message for issues
match result.code:
try:
code = report.results[-1].code
except IndexError:
code = 0
match code:
# NOTE: code 0: everything is fine.
case 0:
report.add_result(None)
pass
# NOTE: code 1: ask for overwrite
case 1:
dlg = QuestionAsker(title=f"Review {base_submission.rsl_plate_num}?", message=result.msg)
if dlg.exec():
# NOTE: Do not add duplicate reagents.
result = None
pass
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
# self.app.report.add_result(report)
# self.app.report_result()
return report
# NOTE: code 2: No RSL plate number given
case 2:
report.add_result(result)
self.app.report.add_result(report)
self.app.result_reporter()
return
# self.app.report.add_result(report)
# self.app.report_result()
return report
case _:
pass
# NOTE: add reagents to submission object
@@ -338,8 +359,7 @@ class SubmissionFormWidget(QWidget):
# NOTE: reset form
self.setParent(None)
# logger.debug(f"All attributes of obj: {pformat(self.__dict__)}")
self.app.report.add_result(report)
self.app.result_reporter()
return report
def export_csv_function(self, fname: Path | None = None):
"""
@@ -352,7 +372,6 @@ class SubmissionFormWidget(QWidget):
fname = select_save_file(obj=self, default_name=self.pyd.construct_filename(), extension="csv")
try:
self.pyd.export_csv(fname)
# workbook_2_csv(worksheet=self.pyd.csv, filename=fname)
except PermissionError:
logger.warning(f"Could not get permissions to {fname}. Possibly the request was cancelled.")
except AttributeError:
@@ -398,11 +417,13 @@ class SubmissionFormWidget(QWidget):
class InfoItem(QWidget):
def __init__(self, parent: QWidget, key: str, value: dict, submission_type: str | None = None, sub_obj:BasicSubmission|None=None) -> None:
def __init__(self, parent: QWidget, key: str, value: dict, submission_type: str | None = None,
sub_obj: BasicSubmission | None = None) -> None:
super().__init__(parent)
layout = QVBoxLayout()
self.label = self.ParsedQLabel(key=key, value=value)
self.input: QWidget = self.set_widget(parent=self, key=key, value=value, submission_type=submission_type, sub_obj=sub_obj)
self.input: QWidget = self.set_widget(parent=self, key=key, value=value, submission_type=submission_type,
sub_obj=sub_obj)
self.setObjectName(key)
try:
self.missing: bool = value['missing']
@@ -439,7 +460,8 @@ class SubmissionFormWidget(QWidget):
return None, None
return self.input.objectName(), dict(value=value, missing=self.missing)
def set_widget(self, parent: QWidget, key: str, value: dict, submission_type: str | None = None, sub_obj:BasicSubmission|None=None) -> QWidget:
def set_widget(self, parent: QWidget, key: str, value: dict, submission_type: str | None = None,
sub_obj: BasicSubmission | None = None) -> QWidget:
"""
Creates form widget
@@ -472,6 +494,7 @@ class SubmissionFormWidget(QWidget):
pass
# set combobox values to lookedup values
add_widget.addItems(labs)
add_widget.setToolTip("Select submitting lab.")
case 'extraction_kit':
# if extraction kit not available, all other values fail
if not check_not_nan(value):
@@ -493,15 +516,7 @@ class SubmissionFormWidget(QWidget):
logger.error(f"Couldn't find {obj.prsr.sub['extraction_kit']}")
obj.ext_kit = uses[0]
add_widget.addItems(uses)
# case 'submitted_date':
# # NOTE: uses base calendar
# add_widget = QDateEdit(calendarPopup=True)
# # NOTE: sets submitted date based on date found in excel sheet
# try:
# add_widget.setDate(value)
# # NOTE: if not found, use today
# except:
# add_widget.setDate(date.today())
add_widget.setToolTip("Select extraction kit.")
case 'submission_category':
add_widget = QComboBox()
cats = ['Diagnostic', "Surveillance", "Research"]
@@ -511,6 +526,7 @@ class SubmissionFormWidget(QWidget):
except ValueError:
cats.insert(0, cats.pop(cats.index(submission_type)))
add_widget.addItems(cats)
add_widget.setToolTip("Enter submission category or select from list.")
case _:
if key in sub_obj.timestamps():
add_widget = QDateEdit(calendarPopup=True)
@@ -520,11 +536,13 @@ class SubmissionFormWidget(QWidget):
# NOTE: if not found, use today
except:
add_widget.setDate(date.today())
add_widget.setToolTip(f"Select date for {key}")
else:
# NOTE: anything else gets added in as a line edit
add_widget = QLineEdit()
# logger.debug(f"Setting widget text to {str(value).replace('_', ' ')}")
add_widget.setText(str(value).replace("_", " "))
add_widget.setToolTip(f"Enter value for {key}")
if add_widget is not None:
add_widget.setObjectName(key)
add_widget.setParent(parent)
@@ -594,13 +612,14 @@ class SubmissionFormWidget(QWidget):
# NOTE: If changed set self.missing to True and update self.label
self.lot.currentTextChanged.connect(self.updated)
def parse_form(self) -> Tuple[PydReagent, dict]:
def parse_form(self) -> Tuple[PydReagent | None, Report]:
"""
Pulls form info into PydReagent
Returns:
Tuple[PydReagent, dict]: PydReagent and Report(?)
"""
report = Report()
lot = self.lot.currentText()
# logger.debug(f"Using this lot for the reagent {self.reagent}: {lot}")
wanted_reagent = Reagent.query(lot_number=lot, reagent_role=self.reagent.role)
@@ -609,14 +628,16 @@ class SubmissionFormWidget(QWidget):
dlg = QuestionAsker(title=f"Add {lot}?",
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,
name=self.reagent.name)
return wanted_reagent, None
wanted_reagent, _ = self.parent().parent().add_reagent(reagent_lot=lot,
reagent_role=self.reagent.role,
expiry=self.reagent.expiry,
name=self.reagent.name)
return wanted_reagent, report
else:
# NOTE: In this case we will have an empty reagent and the submission will fail kit integrity check
# logger.debug("Will not add reagent.")
return None, Result(msg="Failed integrity check", status="Critical")
report.add_result(Result(msg="Failed integrity check", status="Critical"))
return None, report
else:
# NOTE: Since this now gets passed in directly from the parser -> pyd -> form and the parser gets the name
# from the db, it should no longer be necessary to query the db with reagent/kit, but with rt name directly.
@@ -624,7 +645,7 @@ class SubmissionFormWidget(QWidget):
if rt is None:
rt = ReagentRole.query(kit_type=self.extraction_kit, reagent=wanted_reagent)
return PydReagent(name=wanted_reagent.name, lot=wanted_reagent.lot, role=rt.name,
expiry=wanted_reagent.expiry, missing=False), None
expiry=wanted_reagent.expiry, missing=False), report
def updated(self):
"""
@@ -708,4 +729,5 @@ class SubmissionFormWidget(QWidget):
# logger.debug(f"New relevant reagents: {relevant_reagents}")
self.setObjectName(f"lot_{reagent.role}")
self.addItems(relevant_reagents)
self.setToolTip(f"Enter lot number for the reagent used for {reagent.role}")
# self.setStyleSheet(main_form_style)