Pre-code cleanup.

This commit is contained in:
lwark
2025-03-25 15:25:14 -05:00
parent 6404bc499b
commit 3ec79fdcfe
7 changed files with 40 additions and 128 deletions

View File

@@ -1,6 +1,7 @@
# 202503.05 # 202503.05
- Added concentrations chart tab. - Added concentrations chart tab.
- Saving report xlsx/pdf now inserts report class name in file name.
# 202503.04 # 202503.04

View File

@@ -56,23 +56,23 @@ class BaseClass(Base):
omni_inheritable = [] omni_inheritable = []
searchables = [] searchables = []
@classproperty # @classproperty
def skip_on_edit(cls): # def skip_on_edit(cls):
if "association" in cls.__name__.lower() or cls.__name__.lower() == "discount": # if "association" in cls.__name__.lower() or cls.__name__.lower() == "discount":
return True # return True
else: # else:
return False # return False
@classproperty @classproperty
def aliases(cls): def aliases(cls):
return [cls.query_alias] return [cls.query_alias]
@classproperty # @classproperty
def level(cls): # def level(cls):
if "association" in cls.__name__.lower() or cls.__name__.lower() == "discount": # if "association" in cls.__name__.lower() or cls.__name__.lower() == "discount":
return 2 # return 2
else: # else:
return 1 # return 1
@classproperty @classproperty
def query_alias(cls): def query_alias(cls):
@@ -187,8 +187,9 @@ class BaseClass(Base):
return query.limit(50).all() return query.limit(50).all()
@classmethod @classmethod
def results_to_df(cls, objects: list, **kwargs) -> DataFrame: def results_to_df(cls, objects: list|None=None, **kwargs) -> DataFrame:
""" """
Converts class sub_dicts into a Dataframe for all instances of the class.
Args: Args:
objects (list): Objects to be converted to dataframe. objects (list): Objects to be converted to dataframe.
@@ -197,10 +198,16 @@ class BaseClass(Base):
Returns: Returns:
Dataframe Dataframe
""" """
try: if not objects:
records = [obj.to_sub_dict(**kwargs) for obj in objects] try:
except AttributeError: records = [obj.to_sub_dict(**kwargs) for obj in cls.query()]
records = [{k: v['instance_attr'] for k, v in obj.omnigui_instance_dict.items()} for obj in objects] except AttributeError:
records = [obj.to_dict(**kwargs) for obj in cls.query(page_size=0)]
else:
try:
records = [obj.to_sub_dict(**kwargs) for obj in objects]
except AttributeError:
records = [{k: v['instance_attr'] for k, v in obj.omnigui_instance_dict.items()} for obj in objects]
return DataFrame.from_records(records) return DataFrame.from_records(records)
@classmethod @classmethod

View File

@@ -262,7 +262,7 @@ class Control(BaseClass):
try: try:
model = next(subclass for subclass in cls.__subclasses__() if model = next(subclass for subclass in cls.__subclasses__() if
all([hasattr(subclass, attr) for attr in attrs.keys()])) all([hasattr(subclass, attr) for attr in attrs.keys()]))
except StopIteration as e: except StopIteration:
raise AttributeError( raise AttributeError(
f"Couldn't find existing class/subclass of {cls} with all attributes:\n{pformat(attrs.keys())}") f"Couldn't find existing class/subclass of {cls} with all attributes:\n{pformat(attrs.keys())}")
return model return model
@@ -286,6 +286,7 @@ class Control(BaseClass):
Dummy operation to be overridden by child classes. Dummy operation to be overridden by child classes.
Args: Args:
parent (QWidget): widget to add chart to.
chart_settings (dict): settings passed down from chart widget chart_settings (dict): settings passed down from chart widget
ctx (Settings): settings passed down from gui ctx (Settings): settings passed down from gui
""" """
@@ -663,7 +664,7 @@ class IridaControl(Control):
return df, previous_dates return df, previous_dates
# NOTE: if date was changed, rerun with new date # NOTE: if date was changed, rerun with new date
else: else:
logger.warning(f"Date check failed, running recursion") logger.warning(f"Date check failed, running recursion.")
df, previous_dates = cls.check_date(df, item, previous_dates) df, previous_dates = cls.check_date(df, item, previous_dates)
return df, previous_dates return df, previous_dates

View File

@@ -31,7 +31,6 @@ from jinja2.exceptions import TemplateNotFound
from jinja2 import Template from jinja2 import Template
from PIL import Image from PIL import Image
logger = logging.getLogger(f"submissions.{__name__}") logger = logging.getLogger(f"submissions.{__name__}")
@@ -1584,7 +1583,7 @@ class Wastewater(BasicSubmission):
continue continue
thing['tooltip'] = f"Sample Name: {thing['name']}\nWell: {thing['sample_location']}" thing['tooltip'] = f"Sample Name: {thing['name']}\nWell: {thing['sample_location']}"
dummy_samples.append(thing) dummy_samples.append(thing)
logger.debug(f"Dummy samples for 24 well: {pformat(dummy_samples)}") # logger.debug(f"Dummy samples for 24 well: {pformat(dummy_samples)}")
output['origin_plate'] = self.__class__.make_plate_map(sample_list=dummy_samples, plate_rows=4, output['origin_plate'] = self.__class__.make_plate_map(sample_list=dummy_samples, plate_rows=4,
plate_columns=6) plate_columns=6)
# logger.debug(f"PCR info: {output['pcr_info']}") # logger.debug(f"PCR info: {output['pcr_info']}")
@@ -2772,7 +2771,12 @@ class BacterialCultureSample(BasicSample):
sample['concentration'] = self.concentration sample['concentration'] = self.concentration
if self.control is not None: if self.control is not None:
sample['colour'] = [0, 128, 0] sample['colour'] = [0, 128, 0]
sample['tooltip'] = f"Control: {self.control.controltype.name} - {self.control.controltype.targets}" target = next((v for k,v in self.control.controltype.targets.items() if k == self.control.subtype), "Not Available")
try:
target = ", ".join(target)
except:
target = "None"
sample['tooltip'] = f"\nControl: {self.control.controltype.name} - {target}"
return sample return sample

View File

@@ -134,3 +134,5 @@ class CustomFigure(Figure):
from .irida_charts import IridaFigure from .irida_charts import IridaFigure
from .pcr_charts import PCRFigure from .pcr_charts import PCRFigure
from .concentrations_chart import ConcentrationsChart
from .turnaround_chart import TurnaroundChart

View File

@@ -60,12 +60,12 @@ class InfoPane(QWidget):
return abs((d1.year - d2.year) * 12 + d1.month - d2.month) return abs((d1.year - d2.year) * 12 + d1.month - d2.month)
def save_excel(self): def save_excel(self):
fname = select_save_file(self, default_name=f"Report {self.start_date.strftime('%Y%m%d')} - {self.end_date.strftime('%Y%m%d')}", extension="xlsx") fname = select_save_file(self, default_name=f"{self.__class__.__name__} Report {self.start_date.strftime('%Y%m%d')} - {self.end_date.strftime('%Y%m%d')}", extension="xlsx")
self.report_obj.write_report(fname, obj=self) self.report_obj.write_report(fname, obj=self)
def save_pdf(self): def save_pdf(self):
fname = select_save_file(obj=self, fname = select_save_file(obj=self,
default_name=f"Report {self.start_date.strftime('%Y%m%d')} - {self.end_date.strftime('%Y%m%d')}", default_name=f"{self.__class__.__name__} Report {self.start_date.strftime('%Y%m%d')} - {self.end_date.strftime('%Y%m%d')}",
extension="pdf") extension="pdf")
save_pdf(obj=self.webview, filename=fname) save_pdf(obj=self.webview, filename=fname)

View File

@@ -2,13 +2,12 @@
Contains miscellaneous widgets for frontend functions Contains miscellaneous widgets for frontend functions
""" """
import math import math
from datetime import date
from PyQt6.QtGui import QStandardItem, QIcon from PyQt6.QtGui import QStandardItem, QIcon
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QLabel, QLineEdit, QComboBox, QDateEdit, QPushButton, QWidget, QLabel, QLineEdit, QComboBox, QDateEdit, QPushButton, QWidget,
QHBoxLayout, QSizePolicy QHBoxLayout, QSizePolicy
) )
from PyQt6.QtCore import Qt, QDate, QSize, QMarginsF from PyQt6.QtCore import Qt, QDate, QSize
from tools import jinja_template_loading from tools import jinja_template_loading
from backend.db.models import * from backend.db.models import *
import logging import logging
@@ -18,98 +17,6 @@ logger = logging.getLogger(f"submissions.{__name__}")
env = jinja_template_loading() env = jinja_template_loading()
# class AddReagentForm(QDialog):
# """
# dialog to add gather info about new reagent (Defunct)
# """
#
# def __init__(self, reagent_lot: str | None = None, reagent_role: str | None = None, expiry: date | None = None,
# reagent_name: str | None = None, kit: str | KitType | None = None) -> None:
# super().__init__()
# if reagent_name is None:
# reagent_name = reagent_role
# self.setWindowTitle("Add Reagent")
# QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
# self.buttonBox = QDialogButtonBox(QBtn)
# self.buttonBox.accepted.connect(self.accept)
# self.buttonBox.rejected.connect(self.reject)
# # NOTE: widget to get lot info
# self.name_input = QComboBox()
# self.name_input.setObjectName("name")
# self.name_input.setEditable(True)
# self.name_input.setCurrentText(reagent_name)
# self.lot_input = QLineEdit()
# self.lot_input.setObjectName("lot")
# self.lot_input.setText(reagent_lot)
# # NOTE: widget to get expiry info
# self.expiry_input = QDateEdit(calendarPopup=True)
# self.expiry_input.setObjectName('expiry')
# # NOTE: if expiry is not passed in from gui, use today
# if expiry is None:
# logger.warning(f"Did not receive expiry, setting to 1970, 1, 1")
# self.expiry_input.setDate(QDate(1970, 1, 1))
# else:
# try:
# self.expiry_input.setDate(expiry)
# except TypeError:
# self.expiry_input.setDate(QDate(1970, 1, 1))
# # NOTE: widget to get reagent type info
# self.role_input = QComboBox()
# self.role_input.setObjectName('role')
# if kit:
# match kit:
# case str():
# kit = KitType.query(name=kit)
# case _:
# pass
# self.role_input.addItems([item.name for item in ReagentRole.query() if kit in item.kit_types])
# else:
# self.role_input.addItems([item.name for item in ReagentRole.query()])
# # NOTE: convert input to user-friendly string?
# try:
# reagent_role = reagent_role.replace("_", " ").title()
# except AttributeError:
# reagent_role = None
# # NOTE: set parsed reagent type to top of list
# index = self.role_input.findText(reagent_role, Qt.MatchFlag.MatchEndsWith)
# if index >= 0:
# self.role_input.setCurrentIndex(index)
# self.layout = QVBoxLayout()
# self.layout.addWidget(QLabel("Name:"))
# self.layout.addWidget(self.name_input)
# self.layout.addWidget(QLabel("Lot:"))
# self.layout.addWidget(self.lot_input)
# self.layout.addWidget(
# QLabel("Expiry:\n(use exact date on reagent.\nEOL will be calculated from kit automatically)")
# )
# self.layout.addWidget(self.expiry_input)
# self.layout.addWidget(QLabel("Type:"))
# self.layout.addWidget(self.role_input)
# self.layout.addWidget(self.buttonBox)
# self.setLayout(self.layout)
# self.role_input.currentTextChanged.connect(self.update_names)
#
# def parse_form(self) -> dict:
# """
# Converts information in form to dict.
#
# Returns:
# dict: Output info
# """
# return dict(name=self.name_input.currentText().strip(),
# lot=self.lot_input.text().strip(),
# expiry=self.expiry_input.date().toPyDate(),
# role=self.role_input.currentText().strip())
#
# def update_names(self):
# """
# Updates reagent names form field with examples from reagent type
# """
# self.name_input.clear()
# lookup = Reagent.query(role=self.role_input.currentText())
# self.name_input.addItems(list(set([item.name for item in lookup])))
#
#
class StartEndDatePicker(QWidget): class StartEndDatePicker(QWidget):
""" """
custom widget to pick start and end dates for controls graphs custom widget to pick start and end dates for controls graphs
@@ -135,16 +42,6 @@ class StartEndDatePicker(QWidget):
return QSize(80, 20) return QSize(80, 20)
# def save_pdf(obj: QWebEngineView, filename: Path):
# page_layout = QPageLayout()
# page_layout.setPageSize(QPageSize(QPageSize.PageSizeId.A4))
# page_layout.setOrientation(QPageLayout.Orientation.Portrait)
# page_layout.setMargins(QMarginsF(25, 25, 25, 25))
# obj.page().printToPdf(filename.absolute().__str__(), page_layout)
# NOTE: subclass
class CheckableComboBox(QComboBox): class CheckableComboBox(QComboBox):
# once there is a checkState set, it is rendered # once there is a checkState set, it is rendered
# here we assume default Unchecked # here we assume default Unchecked