From f994f81d1117a8e68fd77193b19ed15fbef3874c Mon Sep 17 00:00:00 2001 From: Landon Wark Date: Thu, 11 Apr 2024 09:33:16 -0500 Subject: [PATCH] Moved import PCR results to context menu. --- CHANGELOG.md | 1 + .../backend/db/models/submissions.py | 55 +++++++++++++- src/submissions/frontend/widgets/app.py | 13 +--- .../frontend/widgets/submission_details.py | 4 +- .../frontend/widgets/submission_widget.py | 75 ------------------- 5 files changed, 59 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8250431..4e2b581 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 202404.02 - Various bug fixes. +- Move import PCR results to context menu. - Added ability to sign off on submission in submission details. ## 202403.03 diff --git a/src/submissions/backend/db/models/submissions.py b/src/submissions/backend/db/models/submissions.py index def102d..d6002d6 100644 --- a/src/submissions/backend/db/models/submissions.py +++ b/src/submissions/backend/db/models/submissions.py @@ -3,7 +3,7 @@ Models for the main submission types. ''' from __future__ import annotations from getpass import getuser -import json, logging, uuid, tempfile, re, yaml, base64 +import logging, uuid, tempfile, re, yaml, base64 from zipfile import ZipFile from tempfile import TemporaryDirectory from reportlab.graphics.barcode import createBarcodeImageInMemory @@ -14,7 +14,6 @@ from pprint import pformat from . import Reagent, SubmissionType, KitType, Organization from sqlalchemy import Column, String, TIMESTAMP, INTEGER, ForeignKey, JSON, FLOAT, case from sqlalchemy.orm import relationship, validates, Query -from json.decoder import JSONDecodeError from sqlalchemy.ext.associationproxy import association_proxy import pandas as pd from openpyxl import Workbook @@ -252,7 +251,7 @@ class BasicSubmission(BaseClass): sample_list = self.hitpick_plate() # logger.debug("Setting background colours") for sample in sample_list: - if sample['Positive']: + if sample['positive']: sample['background_color'] = "#f10f07" else: if "colour" in sample.keys(): @@ -1268,6 +1267,54 @@ class Wastewater(BasicSubmission): row = idx.index.to_list()[0] return row + 1 + def custom_context_events(self) -> dict: + events = super().custom_context_events() + events['Link PCR'] = self.link_pcr + return events + + def link_pcr(self, obj): + from backend.excel import PCRParser + from frontend.widgets import select_open_file + fname = select_open_file(obj=obj, file_extension="xlsx") + parser = PCRParser(filepath=fname) + # Check if PCR info already exists + if hasattr(self, 'pcr_info') and self.pcr_info != None: + # existing = json.loads(sub.pcr_info) + existing = self.pcr_info + else: + existing = None + if existing != None: + # update pcr_info + try: + logger.debug(f"Updating {type(existing)}: {existing} with {type(parser.pcr)}: {parser.pcr}") + # if json.dumps(parser.pcr) not in sub.pcr_info: + if parser.pcr not in self.pcr_info: + existing.append(parser.pcr) + logger.debug(f"Setting: {existing}") + # sub.pcr_info = json.dumps(existing) + self.pcr_info = existing + except TypeError: + logger.error(f"Error updating!") + # sub.pcr_info = json.dumps([parser.pcr]) + self.pcr_info = [parser.pcr] + logger.debug(f"Final pcr info for {self.rsl_plate_num}: {self.pcr_info}") + else: + # sub.pcr_info = json.dumps([parser.pcr]) + self.pcr_info = [parser.pcr] + logger.debug(f"Existing {type(self.pcr_info)}: {self.pcr_info}") + logger.debug(f"Inserting {type(parser.pcr)}: {parser.pcr}") + self.save(original=False) + logger.debug(f"Got {len(parser.samples)} samples to update!") + logger.debug(f"Parser samples: {parser.samples}") + for sample in self.samples: + logger.debug(f"Running update on: {sample}") + try: + sample_dict = [item for item in parser.samples if item['sample']==sample.rsl_number][0] + except IndexError: + continue + self.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')) + class WastewaterArtic(BasicSubmission): """ derivative submission type for artic wastewater @@ -2094,7 +2141,7 @@ class SubmissionSampleAssociation(BaseClass): logger.error(f"Unable to find row {self.row} in row_map.") sample['Well'] = None sample['Plate Name'] = self.submission.rsl_plate_num - sample['Positive'] = False + sample['positive'] = False sample['submitted_date'] = self.submission.submitted_date return sample diff --git a/src/submissions/frontend/widgets/app.py b/src/submissions/frontend/widgets/app.py index 6bc47b0..e403fb1 100644 --- a/src/submissions/frontend/widgets/app.py +++ b/src/submissions/frontend/widgets/app.py @@ -8,19 +8,16 @@ from PyQt6.QtWidgets import ( ) from PyQt6.QtGui import QAction from pathlib import Path -from backend.validators import PydReagent from tools import check_if_app, Settings, Report from .pop_ups import AlertPop -from .misc import AddReagentForm, LogParser +from .misc import LogParser import logging, webbrowser, sys -from datetime import date from .submission_table import SubmissionsSheet from .submission_widget import SubmissionFormContainer from .controls_chart import ControlsViewer from .kit_creator import KitAdder from .submission_type_creator import SubmissionTypeAdder - logger = logging.getLogger(f'submissions.{__name__}') logger.info("Hello, I am a logger") @@ -70,7 +67,7 @@ class App(QMainWindow): helpMenu.addAction(self.helpAction) helpMenu.addAction(self.docsAction) fileMenu.addAction(self.importAction) - fileMenu.addAction(self.importPCRAction) + # fileMenu.addAction(self.importPCRAction) methodsMenu.addAction(self.searchLog) reportMenu.addAction(self.generateReportAction) maintenanceMenu.addAction(self.joinExtractionAction) @@ -93,7 +90,7 @@ class App(QMainWindow): """ logger.debug(f"Creating actions...") self.importAction = QAction("&Import Submission", self) - self.importPCRAction = QAction("&Import PCR Results", self) + # self.importPCRAction = QAction("&Import PCR Results", self) self.addReagentAction = QAction("Add Reagent", self) self.generateReportAction = QAction("Make Report", self) self.addKitAction = QAction("Import Kit", self) @@ -110,7 +107,7 @@ class App(QMainWindow): """ logger.debug(f"Connecting actions...") self.importAction.triggered.connect(self.table_widget.formwidget.importSubmission) - self.importPCRAction.triggered.connect(self.table_widget.formwidget.import_pcr_results) + # self.importPCRAction.triggered.connect(self.table_widget.formwidget.import_pcr_results) self.addReagentAction.triggered.connect(self.table_widget.formwidget.add_reagent) self.generateReportAction.triggered.connect(self.table_widget.sub_wid.generate_report) self.joinExtractionAction.triggered.connect(self.table_widget.sub_wid.link_extractions) @@ -157,8 +154,6 @@ class App(QMainWindow): self.report = Report() else: self.statusBar().showMessage("Action completed sucessfully.", 5000) - - def runSearch(self): dlg = LogParser(self) diff --git a/src/submissions/frontend/widgets/submission_details.py b/src/submissions/frontend/widgets/submission_details.py index 29c278d..645a142 100644 --- a/src/submissions/frontend/widgets/submission_details.py +++ b/src/submissions/frontend/widgets/submission_details.py @@ -95,10 +95,12 @@ class SubmissionDetails(QDialog): self.html = self.template.render(sub=self.base_dict, signing_permission=is_power_user()) self.webview.setHtml(self.html) self.setWindowTitle(f"Submission Details - {submission.rsl_plate_num}") + with open("details.html", "w") as f: + f.write(self.html) @pyqtSlot(str) def sign_off(self, submission:str|BasicSubmission): - logger.debug(f"Signing off on {submission}") + logger.debug(f"Signing off on {submission} - ({getuser()})") if isinstance(submission, str): submission = BasicSubmission.query(rsl_number=submission) submission.uploaded_by = getuser() diff --git a/src/submissions/frontend/widgets/submission_widget.py b/src/submissions/frontend/widgets/submission_widget.py index ad3ca18..3db65c7 100644 --- a/src/submissions/frontend/widgets/submission_widget.py +++ b/src/submissions/frontend/widgets/submission_widget.py @@ -112,81 +112,6 @@ class SubmissionFormContainer(QWidget): logger.debug(f"Outgoing report: {self.report.results}") logger.debug(f"All attributes of submission container:\n{pformat(self.__dict__)}") - def import_pcr_results(self): - """ - Pull QuantStudio results into db - """ - self.import_pcr_results_function() - self.app.report.add_result(self.report) - self.report = Report() - self.app.result_reporter() - - def import_pcr_results_function(self): - """ - Import Quant-studio PCR data to an imported submission - - Args: - obj (QMainWindow): original app window - - Returns: - Tuple[QMainWindow, dict]: Collection of new main app window and result dict - """ - report = Report() - fname = select_open_file(self, file_extension="xlsx") - parser = PCRParser(filepath=fname) - logger.debug(f"Attempting lookup for {parser.plate_num}") - sub = BasicSubmission.query(rsl_number=parser.plate_num) - try: - logger.debug(f"Found submission: {sub.rsl_plate_num}") - except AttributeError: - # If no plate is found, may be because this is a repeat. Lop off the '-1' or '-2' and repeat - logger.error(f"Submission of number {parser.plate_num} not found. Attempting rescue of plate repeat.") - parser.plate_num = "-".join(parser.plate_num.split("-")[:-1]) - sub = BasicSubmission.query(rsl_number=parser.plate_num) - try: - logger.debug(f"Found submission: {sub.rsl_plate_num}") - except AttributeError: - logger.error(f"Rescue of {parser.plate_num} failed.") - self.report.add_result(Result(msg="Couldn't find a submission with that RSL number.", status="Warning")) - return - # Check if PCR info already exists - if hasattr(sub, 'pcr_info') and sub.pcr_info != None: - # existing = json.loads(sub.pcr_info) - existing = sub.pcr_info - else: - existing = None - if existing != None: - # update pcr_info - try: - logger.debug(f"Updating {type(existing)}: {existing} with {type(parser.pcr)}: {parser.pcr}") - # if json.dumps(parser.pcr) not in sub.pcr_info: - if parser.pcr not in sub.pcr_info: - existing.append(parser.pcr) - logger.debug(f"Setting: {existing}") - # sub.pcr_info = json.dumps(existing) - sub.pcr_info = existing - except TypeError: - logger.error(f"Error updating!") - # sub.pcr_info = json.dumps([parser.pcr]) - sub.pcr_info = [parser.pcr] - logger.debug(f"Final pcr info for {sub.rsl_plate_num}: {sub.pcr_info}") - else: - # sub.pcr_info = json.dumps([parser.pcr]) - sub.pcr_info = [parser.pcr] - logger.debug(f"Existing {type(sub.pcr_info)}: {sub.pcr_info}") - logger.debug(f"Inserting {type(json.dumps(parser.pcr))}: {json.dumps(parser.pcr)}") - sub.save(original=False) - logger.debug(f"Got {len(parser.samples)} samples to update!") - logger.debug(f"Parser samples: {parser.samples}") - for sample in sub.samples: - logger.debug(f"Running update on: {sample}") - try: - sample_dict = [item for item in parser.samples if item['sample']==sample.rsl_number][0] - except IndexError: - continue - 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')) - def add_reagent(self, reagent_lot:str|None=None, reagent_type:str|None=None, expiry:date|None=None, name:str|None=None): """ Action to create new reagent in DB.