Pre-cleanup
This commit is contained in:
@@ -13,7 +13,7 @@ from PyQt6.QtCore import pyqtSignal
|
||||
from PyQt6.QtGui import QAction
|
||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||
from pathlib import Path
|
||||
from backend.db import (
|
||||
from backend.db.functions import (
|
||||
lookup_control_types, lookup_modes
|
||||
)
|
||||
from backend.validators import PydSubmission, PydReagent
|
||||
@@ -22,6 +22,7 @@ from frontend.custom_widgets import SubmissionsSheet, AlertPop, AddReagentForm,
|
||||
import logging
|
||||
from datetime import date
|
||||
import webbrowser
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(f'submissions.{__name__}')
|
||||
logger.info("Hello, I am a logger")
|
||||
@@ -32,6 +33,7 @@ class App(QMainWindow):
|
||||
logger.debug(f"Initializing main window...")
|
||||
super().__init__()
|
||||
self.ctx = ctx
|
||||
self.last_dir = ctx.directory_path
|
||||
# indicate version and connected database in title bar
|
||||
try:
|
||||
self.title = f"Submissions App (v{ctx.package.__version__}) - {ctx.database_path}"
|
||||
@@ -156,6 +158,7 @@ class App(QMainWindow):
|
||||
Args:
|
||||
result (dict | None, optional): The result from a function. Defaults to None.
|
||||
"""
|
||||
logger.info(f"We got the result: {result}")
|
||||
if result != None:
|
||||
msg = AlertPop(message=result['message'], status=result['status'])
|
||||
msg.exec()
|
||||
@@ -399,7 +402,7 @@ class SubmissionFormContainer(QWidget):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
logger.debug(f"Setting form widget...")
|
||||
super().__init__(parent)
|
||||
self.parent = parent
|
||||
# self.parent = parent
|
||||
|
||||
self.setAcceptDrops(True)
|
||||
|
||||
@@ -411,37 +414,8 @@ class SubmissionFormContainer(QWidget):
|
||||
|
||||
def dropEvent(self, event):
|
||||
fname = Path([u.toLocalFile() for u in event.mimeData().urls()][0])
|
||||
app = self.parent().parent().parent().parent().parent().parent().parent
|
||||
logger.debug(f"App: {app}")
|
||||
app.last_dir = fname.parent
|
||||
self.import_drag.emit(fname)
|
||||
|
||||
def clear_form(self):
|
||||
for item in self.findChildren(QWidget):
|
||||
item.setParent(None)
|
||||
|
||||
def parse_form(self) -> PydSubmission:
|
||||
logger.debug(f"Hello from form parser!")
|
||||
info = {}
|
||||
reagents = []
|
||||
samples = self.parent.parent.samples
|
||||
logger.debug(f"Using samples: {pformat(samples)}")
|
||||
widgets = [widget for widget in self.findChildren(QWidget) if widget.objectName() not in self.ignore]
|
||||
# widgets = [widget for widget in self.findChildren(QWidget)]
|
||||
for widget in widgets:
|
||||
logger.debug(f"Parsed widget: {widget.objectName()} of type {type(widget)}")
|
||||
match widget:
|
||||
case ReagentFormWidget():
|
||||
reagent, _ = widget.parse_form()
|
||||
reagents.append(reagent)
|
||||
case ImportReagent():
|
||||
reagent = dict(name=widget.objectName().replace("lot_", ""), lot=widget.currentText(), type=None, expiry=None)
|
||||
reagents.append(PydReagent(ctx=self.parent.parent.ctx, **reagent))
|
||||
case QLineEdit():
|
||||
info[widget.objectName()] = dict(value=widget.text())
|
||||
case QComboBox():
|
||||
info[widget.objectName()] = dict(value=widget.currentText())
|
||||
case QDateEdit():
|
||||
info[widget.objectName()] = dict(value=widget.date().toPyDate())
|
||||
logger.debug(f"Info: {pformat(info)}")
|
||||
logger.debug(f"Reagents: {pformat(reagents)}")
|
||||
# sys.exit("Hi Landon. Check the reagents! frontend.__init__ line 442")
|
||||
submission = PydSubmission(ctx=self.parent.parent.ctx, filepath=self.parent.parent.current_file, reagents=reagents, samples=samples, **info)
|
||||
return submission
|
||||
|
||||
@@ -23,11 +23,13 @@ def select_open_file(obj:QMainWindow, file_extension:str) -> Path:
|
||||
Path: Path of file to be opened
|
||||
"""
|
||||
try:
|
||||
home_dir = Path(obj.ctx.directory_path).resolve().__str__()
|
||||
# home_dir = Path(obj.ctx.directory_path).resolve().__str__()
|
||||
home_dir = obj.last_dir.resolve().__str__()
|
||||
except FileNotFoundError:
|
||||
home_dir = Path.home().resolve().__str__()
|
||||
fname = Path(QFileDialog.getOpenFileName(obj, 'Open file', home_dir, filter = f"{file_extension}(*.{file_extension})")[0])
|
||||
# fname = Path(QFileDialog.getOpenFileName(obj, 'Open file', filter = f"{file_extension}(*.{file_extension})")[0])
|
||||
obj.last_file = fname
|
||||
return fname
|
||||
|
||||
def select_save_file(obj:QMainWindow, default_name:str, extension:str) -> Path:
|
||||
@@ -43,12 +45,13 @@ def select_save_file(obj:QMainWindow, default_name:str, extension:str) -> Path:
|
||||
Path: Path of file to be opened
|
||||
"""
|
||||
try:
|
||||
home_dir = Path(obj.ctx.directory_path).joinpath(default_name).resolve().__str__()
|
||||
# home_dir = Path(obj.ctx.directory_path).joinpath(default_name).resolve().__str__()
|
||||
home_dir = obj.last_dir.joinpath(default_name).resolve().__str__()
|
||||
except FileNotFoundError:
|
||||
home_dir = Path.home().joinpath(default_name).resolve().__str__()
|
||||
fname = Path(QFileDialog.getSaveFileName(obj, "Save File", home_dir, filter = f"{extension}(*.{extension})")[0])
|
||||
# fname = Path(QFileDialog.getSaveFileName(obj, "Save File", filter = f"{extension}(*.{extension})")[0])
|
||||
|
||||
obj.last_dir = fname.parent
|
||||
return fname
|
||||
|
||||
def extract_form_info(object) -> dict:
|
||||
|
||||
@@ -11,19 +11,20 @@ from PyQt6.QtWidgets import (
|
||||
QGridLayout, QPushButton, QSpinBox, QDoubleSpinBox,
|
||||
QHBoxLayout, QScrollArea, QFormLayout
|
||||
)
|
||||
from PyQt6.QtCore import Qt, QDate, QSize
|
||||
from PyQt6.QtCore import Qt, QDate, QSize, pyqtSignal
|
||||
from tools import check_not_nan, jinja_template_loading, Settings
|
||||
from backend.db.functions import \
|
||||
lookup_reagent_types, lookup_reagents, lookup_submission_type, lookup_reagenttype_kittype_association, \
|
||||
lookup_submissions#, construct_kit_from_yaml
|
||||
lookup_submissions, lookup_organizations, lookup_kit_types
|
||||
from backend.db.models import SubmissionTypeKitTypeAssociation
|
||||
from sqlalchemy import FLOAT, INTEGER
|
||||
import logging
|
||||
import numpy as np
|
||||
from .pop_ups import AlertPop, QuestionAsker
|
||||
from backend.validators import PydReagent, PydKit, PydReagentType, PydSubmission
|
||||
from typing import Tuple
|
||||
from typing import Tuple, List
|
||||
from pprint import pformat
|
||||
import difflib
|
||||
|
||||
logger = logging.getLogger(f"submissions.{__name__}")
|
||||
|
||||
@@ -388,6 +389,10 @@ class ControlsDatePicker(QWidget):
|
||||
|
||||
class ImportReagent(QComboBox):
|
||||
|
||||
"""
|
||||
NOTE: Depreciated in favour of ReagentFormWidget
|
||||
"""
|
||||
|
||||
def __init__(self, ctx:Settings, reagent:dict|PydReagent, extraction_kit:str):
|
||||
super().__init__()
|
||||
self.setEditable(True)
|
||||
@@ -442,25 +447,6 @@ class ImportReagent(QComboBox):
|
||||
self.setObjectName(f"lot_{reagent.type}")
|
||||
self.addItems(relevant_reagents)
|
||||
|
||||
class ParsedQLabel(QLabel):
|
||||
|
||||
def __init__(self, input_object, field_name, title:bool=True, label_name:str|None=None):
|
||||
super().__init__()
|
||||
try:
|
||||
check = input_object['parsed']
|
||||
except:
|
||||
return
|
||||
if label_name != None:
|
||||
self.setObjectName(label_name)
|
||||
if title:
|
||||
output = field_name.replace('_', ' ').title()
|
||||
else:
|
||||
output = field_name.replace('_', ' ')
|
||||
if check:
|
||||
self.setText(f"Parsed {output}")
|
||||
else:
|
||||
self.setText(f"MISSING {output}")
|
||||
|
||||
class FirstStrandSalvage(QDialog):
|
||||
|
||||
def __init__(self, ctx:Settings, submitter_id:str, rsl_plate_num:str|None=None) -> None:
|
||||
@@ -526,10 +512,8 @@ class FirstStrandPlateList(QDialog):
|
||||
class ReagentFormWidget(QWidget):
|
||||
|
||||
def __init__(self, parent:QWidget, reagent:PydReagent, extraction_kit:str):
|
||||
super().__init__()
|
||||
self.setParent(parent)
|
||||
logger.debug(f"Reagent form widget parent is: {self.parent()}")
|
||||
logger.debug(f"It's great grandparent is {self.parent().parent.parent} which has a method [add_reagent]: {hasattr(self.parent().parent.parent, 'add_reagent')}")
|
||||
super().__init__(parent)
|
||||
# self.setParent(parent)
|
||||
self.reagent = reagent
|
||||
self.extraction_kit = extraction_kit
|
||||
self.ctx = reagent.ctx
|
||||
@@ -538,49 +522,57 @@ class ReagentFormWidget(QWidget):
|
||||
layout.addWidget(self.label)
|
||||
self.lot = self.ReagentLot(reagent=reagent, extraction_kit=extraction_kit)
|
||||
layout.addWidget(self.lot)
|
||||
# Remove spacing between reagents
|
||||
layout.setContentsMargins(0,0,0,0)
|
||||
self.setLayout(layout)
|
||||
self.setObjectName(reagent.name)
|
||||
self.missing = not reagent.parsed
|
||||
self.missing = reagent.missing
|
||||
# If changed set self.missing to True and update self.label
|
||||
self.lot.currentTextChanged.connect(self.updated)
|
||||
|
||||
def parse_form(self) -> Tuple[PydReagent, dict]:
|
||||
lot = self.lot.currentText()
|
||||
# type = self.label.text().replace("_label")
|
||||
wanted_reagent = lookup_reagents(ctx=self.ctx, lot_number=lot, reagent_type=self.reagent.type)
|
||||
# if reagent doesn't exist in database, off 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?")
|
||||
if dlg.exec():
|
||||
# logger.debug(f"Looking through {pformat(self.parent.reagents)} for reagent {reagent.name}")
|
||||
# try:
|
||||
# picked_reagent = [item for item in obj.reagents if item.type == reagent.name][0]
|
||||
# except IndexError:
|
||||
# logger.error(f"Couldn't find {reagent.name} in obj.reagents. Checking missing reagents {pprint.pformat(obj.missing_reagents)}")
|
||||
# picked_reagent = [item for item in obj.missing_reagents if item.type == reagent.name][0]
|
||||
# logger.debug(f"checking reagent: {reagent.name} in obj.reagents. Result: {picked_reagent}")
|
||||
# expiry_date = picked_reagent.expiry
|
||||
wanted_reagent = self.parent().parent.parent.add_reagent(reagent_lot=lot, reagent_type=self.reagent.type, expiry=self.reagent.expiry, name=self.reagent.name)
|
||||
wanted_reagent = self.parent().parent().parent().parent().parent().parent().parent().parent().parent.add_reagent(reagent_lot=lot, reagent_type=self.reagent.type, expiry=self.reagent.expiry, name=self.reagent.name)
|
||||
return wanted_reagent, None
|
||||
else:
|
||||
# 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, dict(message="Failed integrity check", status="critical")
|
||||
else:
|
||||
rt = lookup_reagent_types(ctx=self.ctx, kit_type=self.extraction_kit, reagent=wanted_reagent)
|
||||
# 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.
|
||||
rt = lookup_reagent_types(ctx=self.ctx, name=self.reagent.type)
|
||||
# rt = lookup_reagent_types(ctx=self.ctx, kit_type=self.extraction_kit, reagent=wanted_reagent)
|
||||
if rt == None:
|
||||
rt = lookup_reagent_types(ctx=self.ctx, kit_type=self.extraction_kit, reagent=wanted_reagent)
|
||||
return PydReagent(ctx=self.ctx, name=wanted_reagent.name, lot=wanted_reagent.lot, type=rt.name, expiry=wanted_reagent.expiry, parsed=not self.missing), None
|
||||
|
||||
def updated(self):
|
||||
self.missing = True
|
||||
self.label.updated(self.reagent.type)
|
||||
|
||||
|
||||
class ReagentParsedLabel(QLabel):
|
||||
|
||||
def __init__(self, reagent:PydReagent):
|
||||
super().__init__()
|
||||
try:
|
||||
check = reagent.parsed
|
||||
check = not reagent.missing
|
||||
except:
|
||||
return
|
||||
check = False
|
||||
self.setObjectName(f"{reagent.type}_label")
|
||||
if check:
|
||||
self.setText(f"Parsed {reagent.type}")
|
||||
else:
|
||||
self.setText(f"MISSING {reagent.type}")
|
||||
|
||||
def updated(self, reagent_type:str):
|
||||
self.setText(f"UPDATED {reagent_type}")
|
||||
|
||||
class ReagentLot(QComboBox):
|
||||
|
||||
@@ -588,8 +580,8 @@ class ReagentFormWidget(QWidget):
|
||||
super().__init__()
|
||||
self.ctx = reagent.ctx
|
||||
self.setEditable(True)
|
||||
if reagent.parsed:
|
||||
pass
|
||||
# if reagent.parsed:
|
||||
# pass
|
||||
logger.debug(f"Attempting lookup of reagents by type: {reagent.type}")
|
||||
# below was lookup_reagent_by_type_name_and_kit_name, but I couldn't get it to work.
|
||||
lookup = lookup_reagents(ctx=self.ctx, reagent_type=reagent.type)
|
||||
@@ -611,8 +603,11 @@ class ReagentFormWidget(QWidget):
|
||||
else:
|
||||
# TODO: look up the last used reagent of this type in the database
|
||||
looked_up_rt = lookup_reagenttype_kittype_association(ctx=self.ctx, reagent_type=reagent.type, kit_type=extraction_kit)
|
||||
looked_up_reg = lookup_reagents(ctx=self.ctx, lot_number=looked_up_rt.last_used)
|
||||
logger.debug(f"Because there was no reagent listed for {reagent}, we will insert the last lot used: {looked_up_reg}")
|
||||
try:
|
||||
looked_up_reg = lookup_reagents(ctx=self.ctx, lot_number=looked_up_rt.last_used)
|
||||
except AttributeError:
|
||||
looked_up_reg = None
|
||||
logger.debug(f"Because there was no reagent listed for {reagent.lot}, we will insert the last lot used: {looked_up_reg}")
|
||||
if looked_up_reg != None:
|
||||
relevant_reagents.remove(str(looked_up_reg.lot))
|
||||
relevant_reagents.insert(0, str(looked_up_reg.lot))
|
||||
@@ -631,41 +626,212 @@ class ReagentFormWidget(QWidget):
|
||||
|
||||
class SubmissionFormWidget(QWidget):
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
def __init__(self, parent: QWidget, **kwargs) -> None:
|
||||
super().__init__(parent)
|
||||
self.ignore = [None, "", "qt_spinbox_lineedit", "qt_scrollarea_viewport", "qt_scrollarea_hcontainer",
|
||||
"qt_scrollarea_vcontainer", "submit_btn"
|
||||
]
|
||||
# self.ignore = [None, "", "qt_spinbox_lineedit", "qt_scrollarea_viewport", "qt_scrollarea_hcontainer",
|
||||
# "qt_scrollarea_vcontainer", "submit_btn"
|
||||
# ]
|
||||
self.ignore = ['filepath', 'samples', 'reagents', 'csv', 'ctx']
|
||||
layout = QVBoxLayout()
|
||||
for k, v in kwargs.items():
|
||||
if k not in self.ignore:
|
||||
add_widget = self.create_widget(key=k, value=v, submission_type=kwargs['submission_type'])
|
||||
if add_widget != None:
|
||||
layout.addWidget(add_widget)
|
||||
else:
|
||||
setattr(self, k, v)
|
||||
self.setLayout(layout)
|
||||
|
||||
def create_widget(self, key:str, value:dict, submission_type:str|None=None):
|
||||
if key not in self.ignore:
|
||||
return self.InfoItem(self, key=key, value=value, submission_type=submission_type)
|
||||
return None
|
||||
|
||||
def clear_form(self):
|
||||
for item in self.findChildren(QWidget):
|
||||
item.setParent(None)
|
||||
|
||||
def find_widgets(self, object_name:str|None=None) -> List[QWidget]:
|
||||
query = self.findChildren(QWidget)
|
||||
if object_name != None:
|
||||
query = [widget for widget in query if widget.objectName()==object_name]
|
||||
return query
|
||||
|
||||
def parse_form(self) -> PydSubmission:
|
||||
logger.debug(f"Hello from form parser!")
|
||||
info = {}
|
||||
reagents = []
|
||||
samples = self.parent.parent.samples
|
||||
logger.debug(f"Using samples: {pformat(samples)}")
|
||||
widgets = [widget for widget in self.findChildren(QWidget) if widget.objectName() not in self.ignore]
|
||||
if hasattr(self, 'csv'):
|
||||
info['csv'] = self.csv
|
||||
# samples = self.parent().parent.parent.samples
|
||||
# filepath = self.parent().parent.parent.pyd.filepath
|
||||
# logger.debug(f"Using samples: {pformat(samples)}")
|
||||
# widgets = [widget for widget in self.findChildren(QWidget) if widget.objectName() not in self.ignore]
|
||||
# widgets = [widget for widget in self.findChildren(QWidget)]
|
||||
for widget in widgets:
|
||||
logger.debug(f"Parsed widget: {widget.objectName()} of type {type(widget)}")
|
||||
# for widget in widgets:
|
||||
for widget in self.findChildren(QWidget):
|
||||
logger.debug(f"Parsed widget of type {type(widget)}")
|
||||
match widget:
|
||||
case ReagentFormWidget():
|
||||
reagent, _ = widget.parse_form()
|
||||
reagents.append(reagent)
|
||||
case ImportReagent():
|
||||
reagent = dict(name=widget.objectName().replace("lot_", ""), lot=widget.currentText(), type=None, expiry=None)
|
||||
reagents.append(PydReagent(ctx=self.parent.parent.ctx, **reagent))
|
||||
case QLineEdit():
|
||||
info[widget.objectName()] = dict(value=widget.text())
|
||||
case QComboBox():
|
||||
info[widget.objectName()] = dict(value=widget.currentText())
|
||||
case QDateEdit():
|
||||
info[widget.objectName()] = dict(value=widget.date().toPyDate())
|
||||
case self.InfoItem():
|
||||
field, value = widget.parse_form()
|
||||
if field != None:
|
||||
info[field] = value
|
||||
# case ImportReagent():
|
||||
# reagent = dict(name=widget.objectName().replace("lot_", ""), lot=widget.currentText(), type=None, expiry=None)
|
||||
# # ctx: self.SubmissionContinerWidget.AddSubForm
|
||||
# reagents.append(PydReagent(ctx=self.parent.parent.ctx, **reagent))
|
||||
# case QLineEdit():
|
||||
# info[widget.objectName()] = dict(value=widget.text())
|
||||
# case QComboBox():
|
||||
# info[widget.objectName()] = dict(value=widget.currentText())
|
||||
# case QDateEdit():
|
||||
# info[widget.objectName()] = dict(value=widget.date().toPyDate())
|
||||
logger.debug(f"Info: {pformat(info)}")
|
||||
logger.debug(f"Reagents: {pformat(reagents)}")
|
||||
# sys.exit("Hi Landon. Check the reagents! frontend.__init__ line 442")
|
||||
submission = PydSubmission(ctx=self.parent.parent.ctx, filepath=self.parent.parent.current_file, reagents=reagents, samples=samples, **info)
|
||||
app = self.parent().parent().parent().parent().parent().parent().parent().parent
|
||||
submission = PydSubmission(ctx=app.ctx, filepath=self.filepath, reagents=reagents, samples=self.samples, **info)
|
||||
return submission
|
||||
|
||||
class InfoItem(QWidget):
|
||||
|
||||
def __init__(self, parent: QWidget, key:str, value:dict, submission_type:str|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['value'])
|
||||
self.setObjectName(key)
|
||||
try:
|
||||
self.missing:bool = value['missing']
|
||||
except (TypeError, KeyError):
|
||||
self.missing:bool = False
|
||||
if self.input != None:
|
||||
layout.addWidget(self.label)
|
||||
layout.addWidget(self.input)
|
||||
layout.setContentsMargins(0,0,0,0)
|
||||
self.setLayout(layout)
|
||||
match self.input:
|
||||
case QComboBox():
|
||||
self.input.currentTextChanged.connect(self.update_missing)
|
||||
case QDateEdit():
|
||||
self.input.dateChanged.connect(self.update_missing)
|
||||
case QLineEdit():
|
||||
self.input.textChanged.connect(self.update_missing)
|
||||
|
||||
def parse_form(self):
|
||||
match self.input:
|
||||
case QLineEdit():
|
||||
value = self.input.text()
|
||||
case QComboBox():
|
||||
value = self.input.currentText()
|
||||
case QDateEdit():
|
||||
value = self.input.date().toPyDate()
|
||||
case _:
|
||||
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) -> QWidget:
|
||||
try:
|
||||
value = value['value']
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
obj = parent.parent().parent()
|
||||
logger.debug(f"Creating widget for: {key}")
|
||||
match key:
|
||||
case 'submitting_lab':
|
||||
add_widget = QComboBox()
|
||||
# lookup organizations suitable for submitting_lab (ctx: self.InfoItem.SubmissionFormWidget.SubmissionFormContainer.AddSubForm )
|
||||
labs = [item.__str__() for item in lookup_organizations(ctx=obj.ctx)]
|
||||
# try to set closest match to top of list
|
||||
try:
|
||||
labs = difflib.get_close_matches(value, labs, len(labs), 0)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
# set combobox values to lookedup values
|
||||
add_widget.addItems(labs)
|
||||
case 'extraction_kit':
|
||||
# if extraction kit not available, all other values fail
|
||||
if not check_not_nan(value):
|
||||
msg = AlertPop(message="Make sure to check your extraction kit in the excel sheet!", status="warning")
|
||||
msg.exec()
|
||||
# create combobox to hold looked up kits
|
||||
add_widget = QComboBox()
|
||||
# lookup existing kits by 'submission_type' decided on by sheetparser
|
||||
logger.debug(f"Looking up kits used for {submission_type}")
|
||||
uses = [item.__str__() for item in lookup_kit_types(ctx=obj.ctx, used_for=submission_type)]
|
||||
obj.uses = uses
|
||||
logger.debug(f"Kits received for {submission_type}: {uses}")
|
||||
if check_not_nan(value):
|
||||
logger.debug(f"The extraction kit in parser was: {value}")
|
||||
uses.insert(0, uses.pop(uses.index(value)))
|
||||
obj.ext_kit = value
|
||||
else:
|
||||
logger.error(f"Couldn't find {obj.prsr.sub['extraction_kit']}")
|
||||
obj.ext_kit = uses[0]
|
||||
add_widget.addItems(uses)
|
||||
|
||||
# Run reagent scraper whenever extraction kit is changed.
|
||||
# add_widget.currentTextChanged.connect(obj.scrape_reagents)
|
||||
case 'submitted_date':
|
||||
# uses base calendar
|
||||
add_widget = QDateEdit(calendarPopup=True)
|
||||
# sets submitted date based on date found in excel sheet
|
||||
try:
|
||||
add_widget.setDate(value)
|
||||
# if not found, use today
|
||||
except:
|
||||
add_widget.setDate(date.today())
|
||||
case 'submission_category':
|
||||
add_widget = QComboBox()
|
||||
cats = ['Diagnostic', "Surveillance", "Research"]
|
||||
cats += [item.name for item in lookup_submission_type(ctx=obj.ctx)]
|
||||
try:
|
||||
cats.insert(0, cats.pop(cats.index(value)))
|
||||
except ValueError:
|
||||
cats.insert(0, cats.pop(cats.index(submission_type)))
|
||||
add_widget.addItems(cats)
|
||||
case _:
|
||||
# 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("_", " "))
|
||||
if add_widget != None:
|
||||
add_widget.setObjectName(key)
|
||||
add_widget.setParent(parent)
|
||||
|
||||
return add_widget
|
||||
|
||||
def update_missing(self):
|
||||
self.missing = True
|
||||
self.label.updated(self.objectName())
|
||||
|
||||
class ParsedQLabel(QLabel):
|
||||
|
||||
def __init__(self, key:str, value:dict, title:bool=True, label_name:str|None=None):
|
||||
super().__init__()
|
||||
try:
|
||||
check = not value['missing']
|
||||
except:
|
||||
check = True
|
||||
if label_name != None:
|
||||
self.setObjectName(label_name)
|
||||
else:
|
||||
self.setObjectName(f"{key}_label")
|
||||
if title:
|
||||
output = key.replace('_', ' ').title()
|
||||
else:
|
||||
output = key.replace('_', ' ')
|
||||
if check:
|
||||
self.setText(f"Parsed {output}")
|
||||
else:
|
||||
self.setText(f"MISSING {output}")
|
||||
|
||||
def updated(self, key:str, title:bool=True):
|
||||
if title:
|
||||
output = key.replace('_', ' ').title()
|
||||
else:
|
||||
output = key.replace('_', ' ')
|
||||
self.setText(f"UPDATED {output}")
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from getpass import getuser
|
||||
import inspect
|
||||
import pprint
|
||||
import re
|
||||
import sys
|
||||
import yaml
|
||||
import json
|
||||
from typing import Tuple, List
|
||||
@@ -35,7 +36,6 @@ from backend.validators import PydSubmission, PydSample, PydReagent
|
||||
from tools import check_not_nan, convert_well_to_row_column
|
||||
from .custom_widgets.pop_ups import AlertPop, QuestionAsker
|
||||
from .custom_widgets import ReportDatePicker
|
||||
from .custom_widgets.misc import ImportReagent, ParsedQLabel
|
||||
from .visualizations.control_charts import create_charts, construct_html
|
||||
from pathlib import Path
|
||||
from frontend.custom_widgets.misc import FirstStrandSalvage, FirstStrandPlateList, ReagentFormWidget
|
||||
@@ -54,8 +54,12 @@ def import_submission_function(obj:QMainWindow, fname:Path|None=None) -> Tuple[Q
|
||||
"""
|
||||
logger.debug(f"\n\nStarting Import...\n\n")
|
||||
result = None
|
||||
logger.debug(obj.ctx)
|
||||
# logger.debug(obj.ctx)
|
||||
# initialize samples
|
||||
try:
|
||||
obj.form.setParent(None)
|
||||
except AttributeError:
|
||||
pass
|
||||
obj.samples = []
|
||||
obj.missing_info = []
|
||||
# set file dialog
|
||||
@@ -73,106 +77,114 @@ def import_submission_function(obj:QMainWindow, fname:Path|None=None) -> Tuple[Q
|
||||
return obj, result
|
||||
try:
|
||||
logger.debug(f"Submission dictionary:\n{pprint.pformat(obj.prsr.sub)}")
|
||||
pyd = obj.prsr.to_pydantic()
|
||||
logger.debug(f"Pydantic result: \n\n{pprint.pformat(pyd)}\n\n")
|
||||
obj.pyd = obj.prsr.to_pydantic()
|
||||
logger.debug(f"Pydantic result: \n\n{pprint.pformat(obj.pyd)}\n\n")
|
||||
except Exception as e:
|
||||
return obj, dict(message= f"Problem creating pydantic model:\n\n{e}", status="critical")
|
||||
# destroy any widgets from previous imports
|
||||
obj.table_widget.formwidget.clear_form()
|
||||
obj.current_submission_type = pyd.submission_type['value']
|
||||
obj.current_file = pyd.filepath
|
||||
# obj.table_widget.formwidget.set_parent(None)
|
||||
# obj.current_submission_type = pyd.submission_type['value']
|
||||
# obj.current_file = pyd.filepath
|
||||
# Get list of fields from pydantic model.
|
||||
fields = list(pyd.model_fields.keys()) + list(pyd.model_extra.keys())
|
||||
fields.remove('filepath')
|
||||
logger.debug(f"pydantic fields: {fields}")
|
||||
for field in fields:
|
||||
value = getattr(pyd, field)
|
||||
logger.debug(f"Checking: {field}: {value}")
|
||||
# Get from pydantic model whether field was completed in the form
|
||||
if isinstance(value, dict) and field != 'ctx':
|
||||
logger.debug(f"The field {field} is a dictionary: {value}")
|
||||
if not value['parsed']:
|
||||
obj.missing_info.append(field)
|
||||
label = ParsedQLabel(value, field)
|
||||
match field:
|
||||
case 'submitting_lab':
|
||||
logger.debug(f"{field}: {value['value']}")
|
||||
# create combobox to hold looked up submitting labs
|
||||
add_widget = QComboBox()
|
||||
labs = [item.__str__() for item in lookup_organizations(ctx=obj.ctx)]
|
||||
# try to set closest match to top of list
|
||||
try:
|
||||
labs = difflib.get_close_matches(value['value'], labs, len(labs), 0)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
# set combobox values to lookedup values
|
||||
add_widget.addItems(labs)
|
||||
case 'extraction_kit':
|
||||
# if extraction kit not available, all other values fail
|
||||
if not check_not_nan(value['value']):
|
||||
msg = AlertPop(message="Make sure to check your extraction kit in the excel sheet!", status="warning")
|
||||
msg.exec()
|
||||
# create combobox to hold looked up kits
|
||||
add_widget = QComboBox()
|
||||
# lookup existing kits by 'submission_type' decided on by sheetparser
|
||||
logger.debug(f"Looking up kits used for {pyd.submission_type['value']}")
|
||||
uses = [item.__str__() for item in lookup_kit_types(ctx=obj.ctx, used_for=pyd.submission_type['value'])]
|
||||
logger.debug(f"Kits received for {pyd.submission_type['value']}: {uses}")
|
||||
if check_not_nan(value['value']):
|
||||
logger.debug(f"The extraction kit in parser was: {value['value']}")
|
||||
uses.insert(0, uses.pop(uses.index(value['value'])))
|
||||
obj.ext_kit = value['value']
|
||||
else:
|
||||
logger.error(f"Couldn't find {obj.prsr.sub['extraction_kit']}")
|
||||
obj.ext_kit = uses[0]
|
||||
# Run reagent scraper whenever extraction kit is changed.
|
||||
add_widget.currentTextChanged.connect(obj.scrape_reagents)
|
||||
case 'submitted_date':
|
||||
# uses base calendar
|
||||
add_widget = QDateEdit(calendarPopup=True)
|
||||
# sets submitted date based on date found in excel sheet
|
||||
try:
|
||||
add_widget.setDate(value['value'])
|
||||
# if not found, use today
|
||||
except:
|
||||
add_widget.setDate(date.today())
|
||||
case 'samples':
|
||||
# hold samples in 'obj' until form submitted
|
||||
logger.debug(f"{field}:\n\t{value}")
|
||||
obj.samples = value
|
||||
continue
|
||||
case 'submission_category':
|
||||
add_widget = QComboBox()
|
||||
cats = ['Diagnostic', "Surveillance", "Research"]
|
||||
cats += [item.name for item in lookup_submission_type(ctx=obj.ctx)]
|
||||
try:
|
||||
cats.insert(0, cats.pop(cats.index(value['value'])))
|
||||
except ValueError:
|
||||
cats.insert(0, cats.pop(cats.index(pyd.submission_type['value'])))
|
||||
add_widget.addItems(cats)
|
||||
case "ctx" | 'reagents' | 'csv' | 'filepath':
|
||||
continue
|
||||
case _:
|
||||
# anything else gets added in as a line edit
|
||||
add_widget = QLineEdit()
|
||||
logger.debug(f"Setting widget text to {str(value['value']).replace('_', ' ')}")
|
||||
add_widget.setText(str(value['value']).replace("_", " "))
|
||||
try:
|
||||
add_widget.setObjectName(field)
|
||||
logger.debug(f"Widget name set to: {add_widget.objectName()}")
|
||||
obj.table_widget.formlayout.addWidget(label)
|
||||
obj.table_widget.formlayout.addWidget(add_widget)
|
||||
except AttributeError as e:
|
||||
logger.error(e)
|
||||
kit_widget = obj.table_widget.formlayout.parentWidget().findChild(QComboBox, 'extraction_kit')
|
||||
kit_widget.addItems(uses)
|
||||
# fields = list(pyd.model_fields.keys()) + list(pyd.model_extra.keys())
|
||||
# fields.remove('filepath')
|
||||
# logger.debug(f"pydantic fields: {fields}")
|
||||
# for field in fields:
|
||||
# value = getattr(pyd, field)
|
||||
# logger.debug(f"Checking: {field}: {value}")
|
||||
# # Get from pydantic model whether field was completed in the form
|
||||
# if isinstance(value, dict) and field != 'ctx':
|
||||
# logger.debug(f"The field {field} is a dictionary: {value}")
|
||||
# if not value['parsed']:
|
||||
# obj.missing_info.append(field)
|
||||
# label = ParsedQLabel(value, field)
|
||||
# match field:
|
||||
# case 'submitting_lab':
|
||||
# logger.debug(f"{field}: {value['value']}")
|
||||
# # create combobox to hold looked up submitting labs
|
||||
# add_widget = QComboBox()
|
||||
# labs = [item.__str__() for item in lookup_organizations(ctx=obj.ctx)]
|
||||
# # try to set closest match to top of list
|
||||
# try:
|
||||
# labs = difflib.get_close_matches(value['value'], labs, len(labs), 0)
|
||||
# except (TypeError, ValueError):
|
||||
# pass
|
||||
# # set combobox values to lookedup values
|
||||
# add_widget.addItems(labs)
|
||||
# case 'extraction_kit':
|
||||
# # if extraction kit not available, all other values fail
|
||||
# if not check_not_nan(value['value']):
|
||||
# msg = AlertPop(message="Make sure to check your extraction kit in the excel sheet!", status="warning")
|
||||
# msg.exec()
|
||||
# # create combobox to hold looked up kits
|
||||
# add_widget = QComboBox()
|
||||
# # lookup existing kits by 'submission_type' decided on by sheetparser
|
||||
# logger.debug(f"Looking up kits used for {pyd.submission_type['value']}")
|
||||
# uses = [item.__str__() for item in lookup_kit_types(ctx=obj.ctx, used_for=pyd.submission_type['value'])]
|
||||
# logger.debug(f"Kits received for {pyd.submission_type['value']}: {uses}")
|
||||
# if check_not_nan(value['value']):
|
||||
# logger.debug(f"The extraction kit in parser was: {value['value']}")
|
||||
# uses.insert(0, uses.pop(uses.index(value['value'])))
|
||||
# obj.ext_kit = value['value']
|
||||
# else:
|
||||
# logger.error(f"Couldn't find {obj.prsr.sub['extraction_kit']}")
|
||||
# obj.ext_kit = uses[0]
|
||||
# # Run reagent scraper whenever extraction kit is changed.
|
||||
# add_widget.currentTextChanged.connect(obj.scrape_reagents)
|
||||
# case 'submitted_date':
|
||||
# # uses base calendar
|
||||
# add_widget = QDateEdit(calendarPopup=True)
|
||||
# # sets submitted date based on date found in excel sheet
|
||||
# try:
|
||||
# add_widget.setDate(value['value'])
|
||||
# # if not found, use today
|
||||
# except:
|
||||
# add_widget.setDate(date.today())
|
||||
# case 'samples':
|
||||
# # hold samples in 'obj' until form submitted
|
||||
# logger.debug(f"{field}:\n\t{value}")
|
||||
# obj.samples = value
|
||||
# continue
|
||||
# case 'submission_category':
|
||||
# add_widget = QComboBox()
|
||||
# cats = ['Diagnostic', "Surveillance", "Research"]
|
||||
# cats += [item.name for item in lookup_submission_type(ctx=obj.ctx)]
|
||||
# try:
|
||||
# cats.insert(0, cats.pop(cats.index(value['value'])))
|
||||
# except ValueError:
|
||||
# cats.insert(0, cats.pop(cats.index(pyd.submission_type['value'])))
|
||||
# add_widget.addItems(cats)
|
||||
# case "ctx" | 'reagents' | 'csv' | 'filepath':
|
||||
# continue
|
||||
# case _:
|
||||
# # anything else gets added in as a line edit
|
||||
# add_widget = QLineEdit()
|
||||
# logger.debug(f"Setting widget text to {str(value['value']).replace('_', ' ')}")
|
||||
# add_widget.setText(str(value['value']).replace("_", " "))
|
||||
# try:
|
||||
# add_widget.setObjectName(field)
|
||||
# logger.debug(f"Widget name set to: {add_widget.objectName()}")
|
||||
# obj.table_widget.formlayout.addWidget(label)
|
||||
# obj.table_widget.formlayout.addWidget(add_widget)
|
||||
# except AttributeError as e:
|
||||
# logger.error(e)
|
||||
obj.form = obj.pyd.toForm(parent=obj)
|
||||
obj.table_widget.formlayout.addWidget(obj.form)
|
||||
# kit_widget = obj.table_widget.formlayout.parentWidget().findChild(QComboBox, 'extraction_kit')
|
||||
kit_widget = obj.form.find_widgets(object_name="extraction_kit")[0].input
|
||||
logger.debug(f"Kitwidget {kit_widget}")
|
||||
# block
|
||||
# with QSignalBlocker(kit_widget) as blocker:
|
||||
# kit_widget.addItems(obj.uses)
|
||||
obj.scrape_reagents(kit_widget.currentText())
|
||||
kit_widget.currentTextChanged.connect(obj.scrape_reagents)
|
||||
# compare obj.reagents with expected reagents in kit
|
||||
if obj.prsr.sample_result != None:
|
||||
msg = AlertPop(message=obj.prsr.sample_result, status="WARNING")
|
||||
msg.exec()
|
||||
logger.debug(f"Pydantic extra fields: {pyd.model_extra}")
|
||||
if "csv" in pyd.model_extra:
|
||||
obj.csv = pyd.model_extra['csv']
|
||||
# logger.debug(f"Pydantic extra fields: {obj.pyd.model_extra}")
|
||||
# if "csv" in pyd.model_extra:
|
||||
# obj.csv = pyd.model_extra['csv']
|
||||
logger.debug(f"All attributes of obj:\n{pprint.pformat(obj.__dict__)}")
|
||||
return obj, result
|
||||
|
||||
@@ -187,15 +199,19 @@ def kit_reload_function(obj:QMainWindow) -> Tuple[QMainWindow, dict]:
|
||||
Tuple[QMainWindow, dict]: Collection of new main app window and result dict
|
||||
"""
|
||||
result = None
|
||||
for item in obj.table_widget.formlayout.parentWidget().findChildren(QWidget):
|
||||
if isinstance(item, QLabel):
|
||||
if item.text().startswith("Lot"):
|
||||
item.setParent(None)
|
||||
else:
|
||||
logger.debug(f"Type of {item.objectName()} is {type(item)}")
|
||||
if item.objectName().startswith("lot_"):
|
||||
item.setParent(None)
|
||||
obj.kit_integrity_completion_function()
|
||||
# for item in obj.table_widget.formlayout.parentWidget().findChildren(QWidget):
|
||||
logger.debug(f"Attempting to clear {obj.form.find_widgets()}")
|
||||
|
||||
for item in obj.form.find_widgets():
|
||||
if isinstance(item, ReagentFormWidget):
|
||||
item.setParent(None)
|
||||
# if item.text().startswith("Lot"):
|
||||
# item.setParent(None)
|
||||
# else:
|
||||
# logger.debug(f"Type of {item.objectName()} is {type(item)}")
|
||||
# if item.objectName().startswith("lot_"):
|
||||
# item.setParent(None)
|
||||
kit_integrity_completion_function(obj)
|
||||
return obj, result
|
||||
|
||||
def kit_integrity_completion_function(obj:QMainWindow) -> Tuple[QMainWindow, dict]:
|
||||
@@ -209,23 +225,31 @@ def kit_integrity_completion_function(obj:QMainWindow) -> Tuple[QMainWindow, dic
|
||||
Tuple[QMainWindow, dict]: Collection of new main app window and result dict
|
||||
"""
|
||||
result = None
|
||||
missing_reagents = []
|
||||
# kit_reload_function(obj=obj)
|
||||
logger.debug(inspect.currentframe().f_back.f_code.co_name)
|
||||
# find the widget that contains kit info
|
||||
kit_widget = obj.table_widget.formlayout.parentWidget().findChild(QComboBox, 'extraction_kit')
|
||||
kit_widget = obj.form.find_widgets(object_name="extraction_kit")[0].input
|
||||
logger.debug(f"Kit selector: {kit_widget}")
|
||||
# get current kit being used
|
||||
obj.ext_kit = kit_widget.currentText()
|
||||
for reagent in obj.reagents:
|
||||
# for reagent in obj.pyd.reagents:
|
||||
for reagent in obj.form.reagents:
|
||||
# obj.table_widget.formlayout.addWidget(ParsedQLabel({'parsed':True}, item.type, title=False, label_name=f"lot_{item.type}"))
|
||||
# reagent = dict(type=item.type, lot=item.lot, expiry=item.expiry, name=item.name)
|
||||
# add_widget = ImportReagent(ctx=obj.ctx, reagent=reagent, extraction_kit=obj.ext_kit)
|
||||
# obj.table_widget.formlayout.addWidget(add_widget)
|
||||
add_widget = ReagentFormWidget(parent=obj.table_widget.formwidget, reagent=reagent, extraction_kit=obj.ext_kit)
|
||||
obj.table_widget.formlayout.addWidget(add_widget)
|
||||
add_widget.setParent(obj.form)
|
||||
# obj.table_widget.formlayout.addWidget(add_widget)
|
||||
obj.form.layout().addWidget(add_widget)
|
||||
if reagent.missing:
|
||||
missing_reagents.append(reagent)
|
||||
logger.debug(f"Checking integrity of {obj.ext_kit}")
|
||||
# TODO: put check_kit_integrity here instead of what's here?
|
||||
# see if there are any missing reagents
|
||||
if len(obj.missing_reagents) > 0:
|
||||
result = dict(message=f"The submission you are importing is missing some reagents expected by the kit.\n\nIt looks like you are missing: {[item.type.upper() for item in obj.missing_reagents]}\n\nAlternatively, you may have set the wrong extraction kit.\n\nThe program will populate lists using existing reagents.\n\nPlease make sure you check the lots carefully!", status="Warning")
|
||||
if len(missing_reagents) > 0:
|
||||
result = dict(message=f"The submission you are importing is missing some reagents expected by the kit.\n\nIt looks like you are missing: {[item.type.upper() for item in missing_reagents]}\n\nAlternatively, you may have set the wrong extraction kit.\n\nThe program will populate lists using existing reagents.\n\nPlease make sure you check the lots carefully!", status="Warning")
|
||||
# for item in obj.missing_reagents:
|
||||
# # Add label that has parsed as False to show "MISSING" label.
|
||||
# obj.table_widget.formlayout.addWidget(ParsedQLabel({'parsed':False}, item.type, title=False, label_name=f"missing_{item.type}"))
|
||||
@@ -238,7 +262,7 @@ def kit_integrity_completion_function(obj:QMainWindow) -> Tuple[QMainWindow, dic
|
||||
# Add submit button to the form.
|
||||
submit_btn = QPushButton("Submit")
|
||||
submit_btn.setObjectName("submit_btn")
|
||||
obj.table_widget.formlayout.addWidget(submit_btn)
|
||||
obj.form.layout().addWidget(submit_btn)
|
||||
submit_btn.clicked.connect(obj.submit_new_sample)
|
||||
return obj, result
|
||||
|
||||
@@ -254,61 +278,25 @@ def submit_new_sample_function(obj:QMainWindow) -> Tuple[QMainWindow, dict]:
|
||||
"""
|
||||
logger.debug(f"\n\nBeginning Submission\n\n")
|
||||
result = None
|
||||
# extract info from the form widgets
|
||||
# info = extract_form_info(obj.table_widget.tab1)
|
||||
# if isinstance(info, tuple):
|
||||
# logger.warning(f"Got tuple for info for some reason.")
|
||||
# info = info[0]
|
||||
# # seperate out reagents
|
||||
# reagents = {k.replace("lot_", ""):v for k,v in info.items() if k.startswith("lot_")}
|
||||
# info = {k:v for k,v in info.items() if not k.startswith("lot_")}
|
||||
# info, reagents = obj.table_widget.formwidget.parse_form()
|
||||
submission: PydSubmission = obj.table_widget.formwidget.parse_form()
|
||||
logger.debug(f"Submission: {pprint.pformat(submission)}")
|
||||
# parsed_reagents = []
|
||||
# compare reagents in form to reagent database
|
||||
# for reagent in submission.reagents:
|
||||
# # Lookup any existing reagent of this type with this lot number
|
||||
# wanted_reagent = lookup_reagents(ctx=obj.ctx, lot_number=reagent.lot, reagent_type=reagent.name)
|
||||
# logger.debug(f"Looked up reagent: {wanted_reagent}")
|
||||
# # if reagent not found offer to add to database
|
||||
# if wanted_reagent == None:
|
||||
# # r_lot = reagent[reagent]
|
||||
# dlg = QuestionAsker(title=f"Add {reagent.lot}?", message=f"Couldn't find reagent type {reagent.name.strip('Lot')}: {reagent.lot} in the database.\n\nWould you like to add it?")
|
||||
# if dlg.exec():
|
||||
# logger.debug(f"Looking through {pprint.pformat(obj.reagents)} for reagent {reagent.name}")
|
||||
# try:
|
||||
# picked_reagent = [item for item in obj.reagents if item.type == reagent.name][0]
|
||||
# except IndexError:
|
||||
# logger.error(f"Couldn't find {reagent.name} in obj.reagents. Checking missing reagents {pprint.pformat(obj.missing_reagents)}")
|
||||
# picked_reagent = [item for item in obj.missing_reagents if item.type == reagent.name][0]
|
||||
# logger.debug(f"checking reagent: {reagent.name} in obj.reagents. Result: {picked_reagent}")
|
||||
# expiry_date = picked_reagent.expiry
|
||||
# wanted_reagent = obj.add_reagent(reagent_lot=reagent.lot, reagent_type=reagent.name.replace("lot_", ""), expiry=expiry_date, name=picked_reagent.name)
|
||||
# else:
|
||||
# # In this case we will have an empty reagent and the submission will fail kit integrity check
|
||||
# logger.debug("Will not add reagent.")
|
||||
# return obj, dict(message="Failed integrity check", status="critical")
|
||||
# # Append the PydReagent object o be added to the submission
|
||||
# parsed_reagents.append(reagent)
|
||||
# # move samples into preliminary submission dict
|
||||
# submission.reagents = parsed_reagents
|
||||
# submission.uploaded_by = getuser()
|
||||
# construct submission object
|
||||
# logger.debug(f"Here is the info_dict: {pprint.pformat(info)}")
|
||||
# base_submission, result = construct_submission_info(ctx=obj.ctx, info_dict=info)
|
||||
base_submission, result = submission.toSQL()
|
||||
# delattr(base_submission, "ctx")
|
||||
# raise ValueError(base_submission.__dict__)
|
||||
obj.pyd: PydSubmission = obj.form.parse_form()
|
||||
logger.debug(f"Submission: {pprint.pformat(obj.pyd)}")
|
||||
logger.debug("Checking kit integrity...")
|
||||
kit_integrity = check_kit_integrity(ctx=obj.ctx, sub=obj.pyd)
|
||||
if kit_integrity != None:
|
||||
return obj, dict(message=kit_integrity['message'], status="critical")
|
||||
base_submission, result = obj.pyd.toSQL()
|
||||
# check output message for issues
|
||||
match result['code']:
|
||||
# code 0: everything is fine.
|
||||
case 0:
|
||||
result = None
|
||||
# code 1: ask for overwrite
|
||||
case 1:
|
||||
dlg = QuestionAsker(title=f"Review {base_submission.rsl_plate_num}?", message=result['message'])
|
||||
if dlg.exec():
|
||||
# Do not add duplicate reagents.
|
||||
# base_submission.reagents = []
|
||||
pass
|
||||
result = None
|
||||
else:
|
||||
obj.ctx.database_session.rollback()
|
||||
return obj, dict(message="Overwrite cancelled", status="Information")
|
||||
@@ -321,31 +309,19 @@ def submit_new_sample_function(obj:QMainWindow) -> Tuple[QMainWindow, dict]:
|
||||
for reagent in base_submission.reagents:
|
||||
update_last_used(ctx=obj.ctx, reagent=reagent, kit=base_submission.extraction_kit)
|
||||
logger.debug(f"Here is the final submission: {pprint.pformat(base_submission.__dict__)}")
|
||||
logger.debug(f"Parsed reagents: {pprint.pformat(base_submission.reagents)}")
|
||||
logger.debug("Checking kit integrity...")
|
||||
kit_integrity = check_kit_integrity(base_submission)
|
||||
if kit_integrity != None:
|
||||
return obj, dict(message=kit_integrity['message'], status="critical")
|
||||
logger.debug(f"Parsed reagents: {pprint.pformat(base_submission.reagents)}")
|
||||
logger.debug(f"Sending submission: {base_submission.rsl_plate_num} to database.")
|
||||
# result = store_object(ctx=obj.ctx, object=base_submission)
|
||||
base_submission.save(ctx=obj.ctx)
|
||||
# update summary sheet
|
||||
obj.table_widget.sub_wid.setData()
|
||||
# reset form
|
||||
for item in obj.table_widget.formlayout.parentWidget().findChildren(QWidget):
|
||||
item.setParent(None)
|
||||
obj.form.setParent(None)
|
||||
logger.debug(f"All attributes of obj: {pprint.pformat(obj.__dict__)}")
|
||||
if len(obj.missing_reagents + obj.missing_info) > 0:
|
||||
logger.debug(f"We have blank reagents in the excel sheet.\n\tLet's try to fill them in.")
|
||||
extraction_kit = lookup_kit_types(ctx=obj.ctx, name=obj.ext_kit)
|
||||
logger.debug(f"We have the extraction kit: {extraction_kit.name}")
|
||||
excel_map = extraction_kit.construct_xl_map_for_use(obj.current_submission_type)
|
||||
logger.debug(f"Extraction kit map:\n\n{pprint.pformat(excel_map)}")
|
||||
input_reagents = [item.to_reagent_dict(extraction_kit=base_submission.extraction_kit) for item in base_submission.reagents]
|
||||
logger.debug(f"Parsed reagents going into autofile: {pprint.pformat(input_reagents)}")
|
||||
# autofill_excel(obj=obj, xl_map=excel_map, reagents=input_reagents, missing_reagents=obj.missing_reagents, info=info, missing_info=obj.missing_info)
|
||||
autofill_excel(obj=obj, xl_map=excel_map, reagents=input_reagents, missing_reagents=obj.missing_reagents, info=base_submission.__dict__, missing_info=obj.missing_info)
|
||||
if hasattr(obj, 'csv'):
|
||||
wkb = obj.pyd.autofill_excel()
|
||||
if wkb != None:
|
||||
fname = select_save_file(obj=obj, default_name=obj.pyd.rsl_plate_num['value'], extension="xlsx")
|
||||
wkb.save(filename=fname.__str__())
|
||||
if hasattr(obj.pyd, 'csv'):
|
||||
dlg = QuestionAsker("Export CSV?", "Would you like to export the csv file?")
|
||||
if dlg.exec():
|
||||
fname = select_save_file(obj, f"{base_submission.rsl_plate_num}.csv", extension="csv")
|
||||
@@ -353,10 +329,6 @@ def submit_new_sample_function(obj:QMainWindow) -> Tuple[QMainWindow, dict]:
|
||||
obj.csv.to_csv(fname.__str__(), index=False)
|
||||
except PermissionError:
|
||||
logger.debug(f"Could not get permissions to {fname}. Possibly the request was cancelled.")
|
||||
try:
|
||||
delattr(obj, "csv")
|
||||
except AttributeError:
|
||||
pass
|
||||
return obj, result
|
||||
|
||||
def generate_report_function(obj:QMainWindow) -> Tuple[QMainWindow, dict]:
|
||||
@@ -905,6 +877,8 @@ def autofill_excel(obj:QMainWindow, xl_map:dict, reagents:List[dict], missing_re
|
||||
fname = select_save_file(obj=obj, default_name=info['rsl_plate_num'], extension="xlsx")
|
||||
workbook.save(filename=fname.__str__())
|
||||
|
||||
|
||||
|
||||
def construct_first_strand_function(obj:QMainWindow) -> Tuple[QMainWindow, dict]:
|
||||
"""
|
||||
Generates a csv file from client submitted xlsx file.
|
||||
@@ -1016,23 +990,29 @@ def scrape_reagents(obj:QMainWindow, extraction_kit:str) -> Tuple[QMainWindow, d
|
||||
Returns:
|
||||
Tuple[QMainWindow, dict]: Updated application and result
|
||||
"""
|
||||
logger.debug("\n\nHello from reagent scraper!!\n\n")
|
||||
logger.debug(f"Extraction kit: {extraction_kit}")
|
||||
obj.reagents = []
|
||||
obj.missing_reagents = []
|
||||
# obj.reagents = []
|
||||
# obj.missing_reagents = []
|
||||
# Remove previous reagent widgets
|
||||
# [item.setParent(None) for item in obj.table_widget.formlayout.parentWidget().findChildren(QWidget) if item.objectName().startswith("lot_") or item.objectName().startswith("missing_")]
|
||||
# [item.setParent(None) for item in obj.table_widget.formlayout.parentWidget().findChildren(QPushButton)]
|
||||
reagents = obj.prsr.parse_reagents(extraction_kit=extraction_kit)
|
||||
logger.debug(f"Got reagents: {reagents}")
|
||||
try:
|
||||
old_reagents = obj.form.find_widgets()
|
||||
except AttributeError:
|
||||
logger.error(f"Couldn't find old reagents.")
|
||||
old_reagents = []
|
||||
# logger.debug(f"\n\nAttempting to clear: {old_reagents}\n\n")
|
||||
for reagent in old_reagents:
|
||||
if isinstance(reagent, ReagentFormWidget) or isinstance(reagent, QPushButton):
|
||||
reagent.setParent(None)
|
||||
# reagents = obj.prsr.parse_reagents(extraction_kit=extraction_kit)
|
||||
# logger.debug(f"Got reagents: {reagents}")
|
||||
# for reagent in obj.prsr.sub['reagents']:
|
||||
# # create label
|
||||
# if reagent.parsed:
|
||||
# obj.reagents.append(reagent)
|
||||
# else:
|
||||
# obj.missing_reagents.append(reagent)
|
||||
obj.reagents = obj.prsr.sub['reagents']
|
||||
logger.debug(f"Imported reagents: {obj.reagents}")
|
||||
logger.debug(f"Missing reagents: {obj.missing_reagents}")
|
||||
obj.form.reagents = obj.prsr.sub['reagents']
|
||||
# logger.debug(f"Imported reagents: {obj.reagents}")
|
||||
# logger.debug(f"Missing reagents: {obj.missing_reagents}")
|
||||
return obj, None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user