Commit pre-refactor for code cleanup.

This commit is contained in:
Landon Wark
2023-02-10 10:22:39 -06:00
parent c3db706e7c
commit a9ce9514fc
11 changed files with 400 additions and 272 deletions

View File

@@ -1,18 +1,17 @@
from datetime import date
from PyQt6.QtWidgets import (
QLabel, QVBoxLayout,
QLineEdit, QComboBox, QDialog,
QDialogButtonBox, QDateEdit, QTableView,
QTextEdit, QSizePolicy, QWidget,
QDialogButtonBox, QDateEdit, QSizePolicy, QWidget,
QGridLayout, QPushButton, QSpinBox,
QScrollBar, QScrollArea, QHBoxLayout,
QMessageBox, QFileDialog, QToolBar
QScrollBar, QHBoxLayout,
QMessageBox
)
from PyQt6.QtCore import Qt, QDate, QAbstractTableModel, QSize
from PyQt6.QtGui import QFontMetrics, QAction
from PyQt6.QtCore import Qt, QDate, QSize
# from PyQt6.QtGui import QFontMetrics, QAction
from backend.db import get_all_reagenttype_names, submissions_to_df, lookup_submission_by_id, lookup_all_sample_types, create_kit_from_yaml
from backend.db import get_all_reagenttype_names, lookup_all_sample_types, create_kit_from_yaml
from jinja2 import Environment, FileSystemLoader
from xhtml2pdf import pisa
import sys
from pathlib import Path
import logging
@@ -26,55 +25,12 @@ else:
loader = FileSystemLoader(loader_path)
env = Environment(loader=loader)
class AddReagentQuestion(QDialog):
"""
dialog to ask about adding a new reagne to db
"""
def __init__(self, reagent_type:str, reagent_lot:str) -> None:
super().__init__()
self.setWindowTitle(f"Add {reagent_lot}?")
QBtn = QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
self.layout = QVBoxLayout()
message = QLabel(f"Couldn't find reagent type {reagent_type.replace('_', ' ').title().strip('Lot')}: {reagent_lot} in the database.\nWould you like to add it?")
self.layout.addWidget(message)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
class OverwriteSubQuestion(QDialog):
"""
dialog to ask about overwriting existing submission
"""
def __init__(self, message:str, rsl_plate_num:str) -> None:
super().__init__()
self.setWindowTitle(f"Overwrite {rsl_plate_num}?")
QBtn = QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
self.layout = QVBoxLayout()
message = QLabel(message)
self.layout.addWidget(message)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
class AddReagentForm(QDialog):
"""
dialog to add gather info about new reagent
"""
def __init__(self, ctx:dict, reagent_lot:str|None, reagent_type:str|None) -> None:
def __init__(self, ctx:dict, reagent_lot:str|None, reagent_type:str|None, expiry:date|None=None) -> None:
super().__init__()
if reagent_lot == None:
@@ -92,7 +48,10 @@ class AddReagentForm(QDialog):
lot_input.setText(reagent_lot)
# get expiry info
exp_input = QDateEdit(calendarPopup=True)
exp_input.setDate(QDate.currentDate())
if expiry == None:
exp_input.setDate(QDate.currentDate())
else:
exp_input.setDate(expiry)
# get reagent type info
type_input = QComboBox()
type_input.addItems([item.replace("_", " ").title() for item in get_all_reagenttype_names(ctx=ctx)])
@@ -117,172 +76,6 @@ class AddReagentForm(QDialog):
self.setLayout(self.layout)
class pandasModel(QAbstractTableModel):
"""
pandas model for inserting summary sheet into gui
"""
def __init__(self, data) -> None:
QAbstractTableModel.__init__(self)
self._data = data
def rowCount(self, parent=None) -> int:
"""
does what it says
Args:
parent (_type_, optional): _description_. Defaults to None.
Returns:
int: number of rows in data
"""
return self._data.shape[0]
def columnCount(self, parnet=None) -> int:
"""
does what it says
Args:
parnet (_type_, optional): _description_. Defaults to None.
Returns:
int: number of columns in data
"""
return self._data.shape[1]
def data(self, index, role=Qt.ItemDataRole.DisplayRole) -> str|None:
if index.isValid():
if role == Qt.ItemDataRole.DisplayRole:
return str(self._data.iloc[index.row(), index.column()])
return None
def headerData(self, col, orientation, role):
if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole:
return self._data.columns[col]
return None
class SubmissionsSheet(QTableView):
"""
presents submission summary to user in tab1
"""
def __init__(self, ctx:dict) -> None:
"""
initialize
Args:
ctx (dict): settings passed from gui
"""
super().__init__()
self.ctx = ctx
self.setData()
self.resizeColumnsToContents()
self.resizeRowsToContents()
# self.clicked.connect(self.test)
self.doubleClicked.connect(self.show_details)
def setData(self) -> None:
"""
sets data in model
"""
self.data = submissions_to_df(ctx=self.ctx)
self.model = pandasModel(self.data)
self.setModel(self.model)
# self.resize(800,600)
def show_details(self) -> None:
"""
creates detailed data to show in seperate window
"""
index=(self.selectionModel().currentIndex())
# logger.debug(index)
value=index.sibling(index.row(),0).data()
dlg = SubmissionDetails(ctx=self.ctx, id=value)
# dlg.show()
if dlg.exec():
pass
class SubmissionDetails(QDialog):
"""
a window showing text details of submission
"""
def __init__(self, ctx:dict, id:int) -> None:
super().__init__()
self.ctx = ctx
self.setWindowTitle("Submission Details")
# create scrollable interior
interior = QScrollArea()
interior.setParent(self)
# get submision from db
data = lookup_submission_by_id(ctx=ctx, id=id)
self.base_dict = data.to_dict()
logger.debug(f"Base dict: {self.base_dict}")
# don't want id
del self.base_dict['id']
# convert sub objects to dicts
self.base_dict['reagents'] = [item.to_sub_dict() for item in data.reagents]
self.base_dict['samples'] = [item.to_sub_dict() for item in data.samples]
# retrieve jinja template
template = env.get_template("submission_details.txt")
# render using object dict
text = template.render(sub=self.base_dict)
# create text field
txt_editor = QTextEdit(self)
txt_editor.setReadOnly(True)
txt_editor.document().setPlainText(text)
# resize
font = txt_editor.document().defaultFont()
fontMetrics = QFontMetrics(font)
textSize = fontMetrics.size(0, txt_editor.toPlainText())
w = textSize.width() + 10
h = textSize.height() + 10
txt_editor.setMinimumSize(w, h)
txt_editor.setMaximumSize(w, h)
txt_editor.resize(w, h)
interior.resize(w,900)
txt_editor.setText(text)
interior.setWidget(txt_editor)
self.layout = QVBoxLayout()
self.setFixedSize(w, 900)
btn = QPushButton("Export PDF")
btn.setParent(self)
btn.setFixedWidth(w)
btn.clicked.connect(self.export)
# def _create_actions(self):
# self.exportAction = QAction("Export", self)
def export(self):
template = env.get_template("submission_details.html")
html = template.render(sub=self.base_dict)
# logger.debug(f"Submission details: {self.base_dict}")
home_dir = Path(self.ctx["directory_path"]).joinpath(f"Submission_Details_{self.base_dict['Plate Number']}.pdf").resolve().__str__()
fname = Path(QFileDialog.getSaveFileName(self, "Save File", home_dir, filter=".pdf")[0])
# logger.debug(f"report output name: {fname}")
# df.to_excel(fname, engine='openpyxl')
if fname.__str__() == ".":
logger.debug("Saving pdf was cancelled.")
return
try:
with open(fname, "w+b") as f:
pisa.CreatePDF(html, dest=f)
except PermissionError as e:
logger.error(f"Error saving pdf: {e}")
msg = QMessageBox()
msg.setText("Permission Error")
msg.setInformativeText(f"Looks like {fname.__str__()} is open.\nPlease close it and try again.")
msg.setWindowTitle("Permission Error")
msg.exec()
class ReportDatePicker(QDialog):
"""
custom dialog to ask for report start/stop dates
@@ -467,7 +260,7 @@ class ControlsDatePicker(QWidget):
self.start_date = QDateEdit(calendarPopup=True)
# start date is three month prior to end date by default
threemonthsago = QDate.currentDate().addDays(-90)
threemonthsago = QDate.currentDate().addDays(-60)
self.start_date.setDate(threemonthsago)
self.end_date = QDateEdit(calendarPopup=True)
self.end_date.setDate(QDate.currentDate())