diff --git a/src/submissions/backend/__init__.py b/src/submissions/backend/__init__.py
index a34cd2b..e0a0e2e 100644
--- a/src/submissions/backend/__init__.py
+++ b/src/submissions/backend/__init__.py
@@ -3,4 +3,4 @@ Contains database, validators and excel operations.
"""
from .db import *
from .excel import *
-from .validators import *
\ No newline at end of file
+from .validators import *
diff --git a/src/submissions/backend/db/models/__init__.py b/src/submissions/backend/db/models/__init__.py
index 1bddfd6..af8f025 100644
--- a/src/submissions/backend/db/models/__init__.py
+++ b/src/submissions/backend/db/models/__init__.py
@@ -484,7 +484,8 @@ class BaseClass(Base):
if check:
try:
value = json.dumps(value)
- except TypeError:
+ except TypeError as e:
+ logger.error(f"Error json dumping value: {e}")
value = str(value)
try:
self._misc_info.update({key: value})
diff --git a/src/submissions/backend/db/models/procedures.py b/src/submissions/backend/db/models/procedures.py
index 7ee12a2..6404c8c 100644
--- a/src/submissions/backend/db/models/procedures.py
+++ b/src/submissions/backend/db/models/procedures.py
@@ -917,7 +917,7 @@ class Procedure(BaseClass):
obj (_type_): parent widget
"""
logger.info(f"Add equipment")
- from frontend.widgets.equipment_usage_2 import EquipmentUsage
+ from frontend.widgets.equipment_usage import EquipmentUsage
dlg = EquipmentUsage(parent=obj, procedure=self.to_pydantic())
if dlg.exec():
dlg.save_procedure()
diff --git a/src/submissions/backend/db/models/submissions.py b/src/submissions/backend/db/models/submissions.py
index 418eb6b..d9b4be1 100644
--- a/src/submissions/backend/db/models/submissions.py
+++ b/src/submissions/backend/db/models/submissions.py
@@ -646,7 +646,7 @@ class Run(BaseClass, LogMixin):
'permission', "clientsubmission"]
output['sample_count'] = self.sample_count
output['clientsubmission'] = self.clientsubmission.name
- output['clientlab'] = self.clientsubmission.clientlab
+ # output['clientlab'] = self.clientsubmission.clientlab
output['started_date'] = self.started_date
output['completed_date'] = self.completed_date
return output
diff --git a/src/submissions/backend/excel/parsers/__init__.py b/src/submissions/backend/excel/parsers/__init__.py
index 892443f..f3748dc 100644
--- a/src/submissions/backend/excel/parsers/__init__.py
+++ b/src/submissions/backend/excel/parsers/__init__.py
@@ -126,7 +126,7 @@ class DefaultTABLEParser(DefaultParser):
df = df.dropna(axis=1, how='all')
for ii, row in enumerate(df.iterrows()):
output = {}
- for key, value in row[1].details_dict().items():
+ for key, value in row[1].to_dict().items():
if isinstance(key, str):
key = key.lower().replace(" ", "_")
key = re.sub(r"_(\(.*\)|#)", "", key)
diff --git a/src/submissions/backend/validators/__init__.py b/src/submissions/backend/validators/__init__.py
index a32bdca..7e9512e 100644
--- a/src/submissions/backend/validators/__init__.py
+++ b/src/submissions/backend/validators/__init__.py
@@ -265,5 +265,5 @@ class RSLNamer(object):
return ""
-from .pydant import PydRun, PydKitType, PydContact, PydClientLab, PydSample, PydReagent, PydReagentRole, \
+from .pydant import PydRun, PydContact, PydClientLab, PydSample, PydReagent, PydReagentRole, \
PydEquipment, PydEquipmentRole, PydTips, PydProcess, PydElastic, PydClientSubmission, PydProcedure, PydResults
diff --git a/src/submissions/backend/validators/pydant.py b/src/submissions/backend/validators/pydant.py
index 5b75d7b..491701f 100644
--- a/src/submissions/backend/validators/pydant.py
+++ b/src/submissions/backend/validators/pydant.py
@@ -1497,9 +1497,11 @@ class PydClientSubmission(PydBaseClass):
@field_validator("sample_count")
@classmethod
def enforce_integer(cls, value):
+ if not value['value']:
+ value['value'] = 0
try:
value['value'] = int(value['value'])
- except ValueError:
+ except (ValueError, TypeError):
raise f"sample count value must be an integer"
return value
diff --git a/src/submissions/frontend/visualizations/__init__.py b/src/submissions/frontend/visualizations/__init__.py
index 16f2a3a..3d4541b 100644
--- a/src/submissions/frontend/visualizations/__init__.py
+++ b/src/submissions/frontend/visualizations/__init__.py
@@ -1,10 +1,9 @@
-'''
+"""
Contains all operations for creating charts, graphs and visual effects.
-'''
+"""
from datetime import timedelta, date
from pathlib import Path
from typing import Generator
-
import plotly
from PyQt6.QtWidgets import QWidget
import pandas as pd, logging
@@ -128,13 +127,10 @@ class CustomFigure(Figure):
html = f'
'
if self is not None:
# NOTE: Just cannot get this load from string to freaking work.
- # html += self.to_html(include_plotlyjs='cdn', full_html=False)
html += plotly.offline.plot(self, output_type='div', include_plotlyjs="cdn")
else:
html += "No data was retrieved for the given parameters.
"
html += ''
- # with open("test.html", "w", encoding="utf-8") as f:
- # f.write(html)
return html
diff --git a/src/submissions/frontend/visualizations/concentrations_chart.py b/src/submissions/frontend/visualizations/concentrations_chart.py
index bd26db1..bf248e9 100644
--- a/src/submissions/frontend/visualizations/concentrations_chart.py
+++ b/src/submissions/frontend/visualizations/concentrations_chart.py
@@ -3,10 +3,9 @@ Construct BC control concentration charts
"""
from pprint import pformat
from . import CustomFigure
-import plotly.express as px
+import logging, sys, plotly.express as px
import pandas as pd
from PyQt6.QtWidgets import QWidget
-import logging
from operator import itemgetter
logger = logging.getLogger(f"submissions.{__name__}")
@@ -31,7 +30,6 @@ class ConcentrationsChart(CustomFigure):
self.df = self.df.sort_values(['submitted_date', 'procedure'], ascending=[True, True]).reset_index(
drop=True)
self.df = self.df.reset_index().rename(columns={"index": "idx"})
- # logger.debug(f"DF after changes:\n{self.df}")
scatter = px.scatter(data_frame=self.df, x='procedure', y="concentration",
hover_data=["name", "procedure", "submitted_date", "concentration"],
color="positive", color_discrete_map={"positive": "red", "negative": "green", "sample":"orange"}
diff --git a/src/submissions/frontend/visualizations/irida_charts.py b/src/submissions/frontend/visualizations/irida_charts.py
index eb6336d..7df50b8 100644
--- a/src/submissions/frontend/visualizations/irida_charts.py
+++ b/src/submissions/frontend/visualizations/irida_charts.py
@@ -3,11 +3,9 @@ Functions for constructing irida control graphs using plotly.
"""
from datetime import date
from pprint import pformat
-import plotly.express as px
-import pandas as pd
+import logging, plotly.express as px, pandas as pd
from PyQt6.QtWidgets import QWidget
from . import CustomFigure
-import logging
from tools import get_unique_values_in_df_column
logger = logging.getLogger(f"submissions.{__name__}")
diff --git a/src/submissions/frontend/widgets/app.py b/src/submissions/frontend/widgets/app.py
index b4e5705..ad7960f 100644
--- a/src/submissions/frontend/widgets/app.py
+++ b/src/submissions/frontend/widgets/app.py
@@ -22,9 +22,9 @@ from .date_type_picker import DateTypePicker
from .functions import select_save_file
from .pop_ups import HTMLPop
from .misc import Pagifier
-from .submission_table import SubmissionsSheet, SubmissionsTree, ClientSubmissionRunModel
+from .submission_table import SubmissionsTree, ClientSubmissionRunModel
from .submission_widget import SubmissionFormContainer
-from .controls_chart import ControlsViewer
+# from .controls_chart import ControlsViewer
from .summary import Summary
from .turnaround import TurnaroundTime
from .concentrations import Concentrations
@@ -132,7 +132,7 @@ class App(QMainWindow):
self.table_widget.pager.current_page.textChanged.connect(self.update_data)
self.editReagentAction.triggered.connect(self.edit_reagent)
self.manageOrgsAction.triggered.connect(self.manage_orgs)
- self.manageKitsAction.triggered.connect(self.manage_kits)
+ # self.manageKitsAction.triggered.connect(self.manage_kits)
def showAbout(self):
"""
@@ -195,24 +195,23 @@ class App(QMainWindow):
new_org = dlg.parse_form()
new_org.save()
- def manage_kits(self, *args, **kwargs):
- from frontend.widgets.omni_manager_pydant import ManagerWindow as ManagerWindowPyd
- dlg = ManagerWindowPyd(parent=self, object_type=KitType, extras=[], add_edit='edit', managers=set())
- if dlg.exec():
- # logger.debug("\n\nBeginning parsing\n\n")
- output = dlg.parse_form()
- # logger.debug(f"Kit output: {pformat(output.__dict__)}")
- # logger.debug("\n\nBeginning transformation\n\n")
- sql = output.to_sql()
- assert isinstance(sql, KitType)
- sql.save()
+ # def manage_kits(self, *args, **kwargs):
+ # from frontend.widgets.omni_manager_pydant import ManagerWindow as ManagerWindowPyd
+ # dlg = ManagerWindowPyd(parent=self, object_type=KitType, extras=[], add_edit='edit', managers=set())
+ # if dlg.exec():
+ # output = dlg.parse_form()
+ # sql = output.to_sql()
+ # assert isinstance(sql, KitType)
+ # sql.save()
@under_development
def submissions_to_excel(self, *args, **kwargs):
+ from backend.db.models import Run
dlg = DateTypePicker(self)
if dlg.exec():
output = dlg.parse_form()
- df = BasicRun.archive_submissions(**output)
+ # TODO: Move to ClientSubmissions
+ df = Run.archive_submissions(**output)
filepath = select_save_file(self, f"Submissions {output['start_date']}-{output['end_date']}", "xlsx")
writer = ExcelWriter(filepath, "openpyxl")
df.to_excel(writer)
@@ -254,7 +253,6 @@ class AddSubForm(QWidget):
self.sheetwidget = QWidget(self)
self.sheetlayout = QVBoxLayout(self)
self.sheetwidget.setLayout(self.sheetlayout)
- # self.sub_wid = SubmissionsSheet(parent=parent)
self.sub_wid = SubmissionsTree(parent=parent, model=ClientSubmissionRunModel(self))
self.pager = Pagifier(page_max=self.sub_wid.total_count / page_size)
self.sheetlayout.addWidget(self.sub_wid)
@@ -265,12 +263,10 @@ class AddSubForm(QWidget):
self.tab1.layout.addWidget(self.interior)
self.tab1.layout.addWidget(self.sheetwidget)
self.tab2.layout = QVBoxLayout(self)
- # self.irida_viewer = ControlsViewer(self, archetype="Irida Control")
self.irida_viewer = None
self.tab2.layout.addWidget(self.irida_viewer)
self.tab2.setLayout(self.tab2.layout)
self.tab3.layout = QVBoxLayout(self)
- # self.pcr_viewer = ControlsViewer(self, archetype="PCR Control")
self.pcr_viewer = None
self.tab3.layout.addWidget(self.pcr_viewer)
self.tab3.setLayout(self.tab3.layout)
diff --git a/src/submissions/frontend/widgets/concentrations.py b/src/submissions/frontend/widgets/concentrations.py
index bc11c33..1c48f7f 100644
--- a/src/submissions/frontend/widgets/concentrations.py
+++ b/src/submissions/frontend/widgets/concentrations.py
@@ -43,10 +43,8 @@ class Concentrations(InfoPane):
None
"""
include = self.pos_neg.get_checked()
- # logger.debug(f"Include: {include}")
super().update_data()
months = self.diff_month(self.start_date, self.end_date)
- # logger.debug(f"Box checked: {self.all_box.isChecked()}")
chart_settings = dict(start_date=self.start_date, end_date=self.end_date,
include=include)
self.report_obj = ConcentrationMaker(**chart_settings)
diff --git a/src/submissions/frontend/widgets/controls_chart.py b/src/submissions/frontend/widgets/controls_chart.py
index afd9ffa..2915880 100644
--- a/src/submissions/frontend/widgets/controls_chart.py
+++ b/src/submissions/frontend/widgets/controls_chart.py
@@ -108,7 +108,6 @@ class ControlsViewer(InfoPane):
parent=self,
months=months
)
- # logger.debug(f"Chart settings: {chart_settings}")
self.fig = self.archetype.instance_class.make_chart(chart_settings=chart_settings, parent=self, ctx=self.app.ctx)
self.report_obj = ChartReportMaker(df=self.fig.df, sheet_name=self.archetype.name)
if issubclass(self.fig.__class__, CustomFigure):
diff --git a/src/submissions/frontend/widgets/date_type_picker.py b/src/submissions/frontend/widgets/date_type_picker.py
index 604e1de..9ca8395 100644
--- a/src/submissions/frontend/widgets/date_type_picker.py
+++ b/src/submissions/frontend/widgets/date_type_picker.py
@@ -1,8 +1,14 @@
+"""
+
+"""
from PyQt6.QtWidgets import (
QVBoxLayout, QDialog, QDialogButtonBox
)
from .misc import CheckableComboBox, StartEndDatePicker
from backend.db.models.procedures import SubmissionType
+import logging
+
+logger = logging.getLogger(f"submissions.{__name__}")
class DateTypePicker(QDialog):
@@ -27,10 +33,7 @@ class DateTypePicker(QDialog):
self.setLayout(self.layout)
def parse_form(self):
- # sub_types = [self.typepicker.itemText(i) for i in range(self.typepicker.count()) if self.typepicker.itemChecked(i)]
sub_types = self.typepicker.get_checked()
start_date = self.datepicker.start_date.date().toPyDate()
end_date = self.datepicker.end_date.date().toPyDate()
return dict(submissiontype=sub_types, start_date=start_date, end_date=end_date)
-
-
diff --git a/src/submissions/frontend/widgets/equipment_usage.py b/src/submissions/frontend/widgets/equipment_usage.py
index 919f48e..be2759d 100644
--- a/src/submissions/frontend/widgets/equipment_usage.py
+++ b/src/submissions/frontend/widgets/equipment_usage.py
@@ -1,91 +1,97 @@
-'''
+"""
Creates forms that the user can enter equipment info into.
-'''
+"""
+import sys, logging
from pprint import pformat
-from PyQt6.QtCore import Qt, QSignalBlocker
-from PyQt6.QtWidgets import (
- QDialog, QComboBox, QCheckBox, QLabel, QWidget, QVBoxLayout, QDialogButtonBox, QGridLayout
-)
-from backend.db.models import Equipment, Run, Process, Procedure
-from backend.validators.pydant import PydEquipment, PydEquipmentRole, PydTips
-import logging
from typing import Generator
+from PyQt6.QtCore import Qt, pyqtSlot, QSignalBlocker
+from PyQt6.QtWebChannel import QWebChannel
+from PyQt6.QtWebEngineWidgets import QWebEngineView
+from PyQt6.QtWidgets import (
+ QDialog, QVBoxLayout, QDialogButtonBox, QGridLayout, QWidget, QCheckBox, QComboBox, QLabel
+)
+from backend import Process
+from backend.db.models import Equipment
+from backend.validators.pydant import PydProcedure, PydEquipmentRole, PydTips, PydEquipment
+from tools import get_application_from_parent, render_details_template
logger = logging.getLogger(f"submissions.{__name__}")
class EquipmentUsage(QDialog):
- def __init__(self, parent, procedure: Procedure):
+ def __init__(self, parent, procedure: PydProcedure):
super().__init__(parent)
self.procedure = procedure
self.setWindowTitle(f"Equipment Checklist - {procedure.name}")
self.used_equipment = self.procedure.equipment
- # self.kit = self.procedure.kittype
+ self.kit = self.procedure.kittype
self.opt_equipment = procedure.proceduretype.get_equipment()
self.layout = QVBoxLayout()
+ self.app = get_application_from_parent(parent)
+ self.webview = QWebEngineView(parent=self)
+ self.webview.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu)
+ self.webview.setMinimumSize(1200, 800)
+ self.webview.setMaximumWidth(1200)
+ # NOTE: Decide if exporting should be allowed.
+ self.layout = QGridLayout()
+ # NOTE: button to export a pdf version
+ self.layout.addWidget(self.webview, 1, 0, 10, 10)
self.setLayout(self.layout)
- self.populate_form()
-
- def populate_form(self):
- """
- Create form widgets
- """
+ self.setFixedWidth(self.webview.width() + 20)
+ # NOTE: setup channel
+ self.channel = QWebChannel()
+ self.channel.registerObject('backend', self)
+ html = self.construct_html(procedure=procedure)
+ self.webview.setHtml(html)
+ self.webview.page().setWebChannel(self.channel)
QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
- label = self.LabelRow(parent=self)
- self.layout.addWidget(label)
- for equipment in self.opt_equipment:
- widg = equipment.to_form(parent=self, used=self.used_equipment)
- self.layout.addWidget(widg)
- widg.update_processes()
- self.layout.addWidget(self.buttonBox)
+ self.layout.addWidget(self.buttonBox, 11, 1, 1, 1)
- def parse_form(self) -> Generator[PydEquipment, None, None]:
- """
- Pull info from all RoleComboBox widgets
+ @classmethod
+ def construct_html(cls, procedure: PydProcedure, child: bool = False):
+ proceduretype = procedure.proceduretype
+ proceduretype_dict = proceduretype.details_dict()
+ run = procedure.run
+ html = render_details_template(
+ template_name="support/equipment_usage",
+ css_in=[],
+ js_in=[],
+ proceduretype=proceduretype_dict,
+ run=run.details_dict(),
+ procedure=procedure.__dict__,
+ child=child
+ )
+ return html
- Returns:
- Generator[PydEquipment, None, None]: All equipment pulled from widgets
- """
- for widget in self.findChildren(QWidget):
- match widget:
- case RoleComboBox():
- if widget.check.isChecked():
- item = widget.parse_form()
- if item:
- yield item
- else:
- continue
- else:
- continue
- case _:
- continue
+ @pyqtSlot(str, str, str, str)
+ def update_equipment(self, equipmentrole: str, equipment: str, process: str, tips: str):
+ try:
+ equipment_of_interest = next(
+ (item for item in self.procedure.equipment if item.equipmentrole == equipmentrole))
+ except StopIteration:
+ equipment_of_interest = None
+ equipment = Equipment.query(name=equipment)
+ if equipment_of_interest:
+ eoi = self.procedure.equipment.pop(self.procedure.equipment.index(equipment_of_interest))
+ else:
+ eoi = equipment.to_pydantic(proceduretype=self.procedure.proceduretype)
+ eoi.name = equipment.name
+ eoi.asset_number = equipment.asset_number
+ eoi.nickname = equipment.nickname
+ process = next((prcss for prcss in equipment.process if prcss.name == process))
+ eoi.process = process.to_pydantic()
+ tips = next((tps for tps in equipment.tips if tps.name == tips))
+ eoi.tips = tips.to_pydantic()
+ self.procedure.equipment.append(eoi)
+ logger.debug(f"Updated equipment: {self.procedure.equipment}")
- class LabelRow(QWidget):
- """Provides column headers"""
-
- def __init__(self, parent) -> None:
- super().__init__(parent)
- self.layout = QGridLayout()
- self.check = QCheckBox()
- self.layout.addWidget(self.check, 0, 0)
- self.check.stateChanged.connect(self.check_all)
- for iii, item in enumerate(["Role", "Equipment", "Process", "Tips"], start=1):
- label = QLabel(item)
- label.setMaximumWidth(200)
- label.setMinimumWidth(200)
- self.layout.addWidget(label, 0, iii, alignment=Qt.AlignmentFlag.AlignRight)
- self.setLayout(self.layout)
-
- def check_all(self):
- """
- Toggles all checkboxes in the form
- """
- for object in self.parent().findChildren(QCheckBox):
- object.setChecked(self.check.isChecked())
+ def save_procedure(self):
+ sql, _ = self.procedure.to_sql()
+ sql.save()
class RoleComboBox(QWidget):
@@ -124,7 +130,6 @@ class RoleComboBox(QWidget):
"""
equip = self.box.currentText()
equip2 = next((item for item in self.role.equipment if item.name == equip), self.role.equipment[0])
- logger.debug(f"Equip2: {equip2}")
with QSignalBlocker(self.process) as blocker:
self.process.clear()
self.process.addItems([item for item in equip2.process if item in self.role.process])
@@ -180,7 +185,7 @@ class RoleComboBox(QWidget):
def toggle_checked(self):
"""
If this equipment is disabled, the input fields will be disabled.
- """
+ """
for widget in self.findChildren(QWidget):
match widget:
case QCheckBox():
diff --git a/src/submissions/frontend/widgets/equipment_usage_2.py b/src/submissions/frontend/widgets/equipment_usage_2.py
deleted file mode 100644
index 7dc4755..0000000
--- a/src/submissions/frontend/widgets/equipment_usage_2.py
+++ /dev/null
@@ -1,131 +0,0 @@
-'''
-Creates forms that the user can enter equipment info into.
-'''
-import sys
-from pprint import pformat
-from PyQt6.QtCore import Qt, QSignalBlocker, pyqtSlot
-from PyQt6.QtWebChannel import QWebChannel
-from PyQt6.QtWebEngineWidgets import QWebEngineView
-from PyQt6.QtWidgets import (
- QDialog, QComboBox, QCheckBox, QLabel, QWidget, QVBoxLayout, QDialogButtonBox, QGridLayout
-)
-from backend.db.models import Equipment, Run, Process, Procedure, Tips
-from backend.validators.pydant import PydEquipment, PydEquipmentRole, PydTips, PydProcedure
-import logging
-from typing import Generator
-
-from tools import get_application_from_parent, render_details_template, flatten_list
-
-logger = logging.getLogger(f"submissions.{__name__}")
-
-
-class EquipmentUsage(QDialog):
-
- def __init__(self, parent, procedure: PydProcedure):
- super().__init__(parent)
- self.procedure = procedure
- self.setWindowTitle(f"Equipment Checklist - {procedure.name}")
- self.used_equipment = self.procedure.equipment
- self.kit = self.procedure.kittype
- self.opt_equipment = procedure.proceduretype.get_equipment()
- self.layout = QVBoxLayout()
- self.app = get_application_from_parent(parent)
- self.webview = QWebEngineView(parent=self)
- self.webview.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu)
- self.webview.setMinimumSize(1200, 800)
- self.webview.setMaximumWidth(1200)
- # NOTE: Decide if exporting should be allowed.
- # self.webview.loadFinished.connect(self.activate_export)
- self.layout = QGridLayout()
- # NOTE: button to export a pdf version
- self.layout.addWidget(self.webview, 1, 0, 10, 10)
- self.setLayout(self.layout)
- self.setFixedWidth(self.webview.width() + 20)
- # NOTE: setup channel
- self.channel = QWebChannel()
- self.channel.registerObject('backend', self)
- html = self.construct_html(procedure=procedure)
- self.webview.setHtml(html)
- self.webview.page().setWebChannel(self.channel)
- QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
- self.buttonBox = QDialogButtonBox(QBtn)
- self.buttonBox.accepted.connect(self.accept)
- self.buttonBox.rejected.connect(self.reject)
- self.layout.addWidget(self.buttonBox, 11, 1, 1, 1)
-
- @classmethod
- def construct_html(cls, procedure: PydProcedure, child: bool = False):
- proceduretype = procedure.proceduretype
- proceduretype_dict = proceduretype.details_dict()
- run = procedure.run
- # proceduretype_dict['equipment_json'] = flatten_list([item['equipment_json'] for item in proceduretype_dict['equipment']])
- # proceduretype_dict['equipment_json'] = [
- # {'name': 'Liquid Handler', 'equipment': [
- # {'name': 'Other', 'asset_number': 'XXX', 'processes': [
- # {'name': 'Trust Me', 'tips': ['Blah']},
- # {'name': 'No Me', 'tips': ['Blah', 'Crane']}
- # ]
- # },
- # {'name': 'Biomek', 'asset_number': '5015530', 'processes': [
- # {'name': 'Sample Addition', 'tips': ['Axygen 20uL']
- # }
- # ]
- # }
- # ]
- # }
- # ]
- # if procedure.equipment:
- # for equipmentrole in proceduretype_dict['equipment']:
- # # NOTE: Check if procedure equipment is present and move to head of the list if so.
- # try:
- # relevant_procedure_item = next((equipment for equipment in procedure.equipment if
- # equipment.equipmentrole == equipmentrole['name']))
- # except StopIteration:
- # continue
- # item_in_er_list = next((equipment for equipment in equipmentrole['equipment'] if
- # equipment['name'] == relevant_procedure_item.name))
- # equipmentrole['equipment'].insert(0, equipmentrole['equipment'].pop(
- # equipmentrole['equipment'].index(item_in_er_list)))
- html = render_details_template(
- template_name="support/equipment_usage",
- css_in=[],
- js_in=[],
- proceduretype=proceduretype_dict,
- run=run.details_dict(),
- procedure=procedure.__dict__,
- child=child
- )
- return html
-
- @pyqtSlot(str, str, str, str)
- def update_equipment(self, equipmentrole: str, equipment: str, process: str, tips: str):
-
- try:
- equipment_of_interest = next(
- (item for item in self.procedure.equipment if item.equipmentrole == equipmentrole))
- except StopIteration:
- equipment_of_interest = None
- equipment = Equipment.query(name=equipment)
- if equipment_of_interest:
- eoi = self.procedure.equipment.pop(self.procedure.equipment.index(equipment_of_interest))
- else:
- eoi = equipment.to_pydantic(proceduretype=self.procedure.proceduretype)
- eoi.name = equipment.name
- eoi.asset_number = equipment.asset_number
- eoi.nickname = equipment.nickname
- process = next((prcss for prcss in equipment.process if prcss.name == process))
- eoi.process = process.to_pydantic()
- tips = next((tps for tps in equipment.tips if tps.name == tips))
- eoi.tips = tips.to_pydantic()
- self.procedure.equipment.append(eoi)
- logger.debug(f"Updated equipment: {self.procedure.equipment}")
-
- def save_procedure(self):
- sql, _ = self.procedure.to_sql()
- logger.debug(pformat(sql.__dict__))
- # import pickle
- # with open("sql.pickle", "wb") as f:
- # pickle.dump(sql, f)
- # with open("pyd.pickle", "wb") as f:
- # pickle.dump(self.procedure, f)
- sql.save()
diff --git a/src/submissions/frontend/widgets/functions.py b/src/submissions/frontend/widgets/functions.py
index cb97621..3a564b0 100644
--- a/src/submissions/frontend/widgets/functions.py
+++ b/src/submissions/frontend/widgets/functions.py
@@ -39,7 +39,7 @@ def select_open_file(obj: QMainWindow, file_extension: str | None = None) -> Pat
logger.warning(f"No file selected, cancelling.")
return
obj.last_dir = fname.parent
- logger.debug(f"File selected: {fname}")
+ logger.info(f"File selected: {fname}")
return fname
diff --git a/src/submissions/frontend/widgets/gel_checker.py b/src/submissions/frontend/widgets/gel_checker.py
index a3c23a1..a2fc9d5 100644
--- a/src/submissions/frontend/widgets/gel_checker.py
+++ b/src/submissions/frontend/widgets/gel_checker.py
@@ -5,10 +5,9 @@ from operator import itemgetter
from PyQt6.QtWidgets import (
QWidget, QDialog, QGridLayout, QLabel, QLineEdit, QDialogButtonBox, QTextEdit, QComboBox
)
-import pyqtgraph as pg
from PyQt6.QtGui import QIcon
from PIL import Image
-import logging, numpy as np
+import logging, numpy as np, pyqtgraph as pg
from pprint import pformat
from typing import Tuple, List
from pathlib import Path
diff --git a/src/submissions/frontend/widgets/info_tab.py b/src/submissions/frontend/widgets/info_tab.py
index 69e80ee..49765ca 100644
--- a/src/submissions/frontend/widgets/info_tab.py
+++ b/src/submissions/frontend/widgets/info_tab.py
@@ -34,7 +34,6 @@ class InfoPane(QWidget):
report = Report()
self.start_date = self.datepicker.start_date.date().toPyDate()
self.end_date = self.datepicker.end_date.date().toPyDate()
- # logger.debug(f"Start date: {self.start_date}, End date: {self.end_date}")
if self.datepicker.start_date.date() > self.datepicker.end_date.date():
lastmonth = self.datepicker.end_date.date().addDays(-31)
msg = f"Start date after end date is not allowed! Setting to {lastmonth.toString()}."
diff --git a/src/submissions/frontend/widgets/misc.py b/src/submissions/frontend/widgets/misc.py
index 71eb0e0..ec39af1 100644
--- a/src/submissions/frontend/widgets/misc.py
+++ b/src/submissions/frontend/widgets/misc.py
@@ -1,7 +1,7 @@
"""
Contains miscellaneous widgets for frontend functions
"""
-import math
+import math, logging
from PyQt6.QtGui import QStandardItem, QIcon
from PyQt6.QtWidgets import (
QLabel, QLineEdit, QComboBox, QDateEdit, QPushButton, QWidget,
@@ -10,7 +10,6 @@ from PyQt6.QtWidgets import (
from PyQt6.QtCore import Qt, QDate, QSize
from tools import jinja_template_loading
from backend.db.models import *
-import logging
logger = logging.getLogger(f"submissions.{__name__}")
diff --git a/src/submissions/frontend/widgets/procedure_creation.py b/src/submissions/frontend/widgets/procedure_creation.py
index 99b79fe..3ec2a32 100644
--- a/src/submissions/frontend/widgets/procedure_creation.py
+++ b/src/submissions/frontend/widgets/procedure_creation.py
@@ -8,7 +8,7 @@ from PyQt6.QtCore import pyqtSlot, Qt
from PyQt6.QtWebChannel import QWebChannel
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWidgets import QDialog, QGridLayout, QDialogButtonBox
-from typing import TYPE_CHECKING, Any, List
+from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
from backend.validators import PydProcedure, PydEquipment
from tools import get_application_from_parent, render_details_template, sanitize_object_for_json
@@ -52,7 +52,7 @@ class ProcedureCreation(QDialog):
def set_html(self):
- from .equipment_usage_2 import EquipmentUsage
+ from .equipment_usage import EquipmentUsage
proceduretype_dict = self.proceduretype.details_dict()
# NOTE: Add --New-- as an option for reagents.
for key, value in self.procedure.reagentrole.items():
@@ -88,11 +88,6 @@ class ProcedureCreation(QDialog):
@pyqtSlot(str, str, str, str)
def update_equipment(self, equipmentrole: str, equipment: str, process: str, tips: str):
from backend.db.models import Equipment, ProcessVersion, TipsLot
- logger.debug(f"Updating equipment with"
- f"\n\tEquipment role: {equipmentrole}"
- f"\n\tEquipment: {equipment}"
- f"\n\tProcess: {process}"
- f"\n\tTips: {tips}")
try:
equipment_of_interest = next(
(item for item in self.procedure.equipment if item.equipmentrole == equipmentrole))
@@ -109,19 +104,13 @@ class ProcedureCreation(QDialog):
process_name, version = process.split("-v")
process = ProcessVersion.query(name=process_name, version=version, limit=1)
eoi.process = process
- # sys.exit(f"Process:\n{pformat(eoi.process.__dict__)}")
try:
tips_manufacturer, tipsref, lot = [item if item != "" else None for item in tips.split("-")]
- logger.debug(f"Querying with '{tips_manufacturer}', '{tipsref}', '{lot}'")
tips = TipsLot.query(manufacturer=tips_manufacturer, ref=tipsref, lot=lot)
- logger.debug(f"Found tips: {tips}")
eoi.tips = tips
except ValueError:
logger.warning(f"No tips info to unpack")
- # tips = TipsLot.query(manufacturer=tips_manufacturer, ref=tipsref, lot=lot)
- # eoi.tips = tips
self.procedure.equipment.append(eoi)
- logger.debug(f"Updated equipment:\n{pformat([item.__dict__ for item in self.procedure.equipment])}")
@pyqtSlot(str, str)
def text_changed(self, key: str, new_value: str):
@@ -167,11 +156,9 @@ class ProcedureCreation(QDialog):
@pyqtSlot(str, str)
def update_reagent(self, reagentrole: str, name_lot_expiry: str):
- logger.debug(f"{reagentrole}: {name_lot_expiry}")
try:
name, lot, expiry = name_lot_expiry.split(" - ")
except ValueError as e:
- logger.debug(f"Couldn't perform split due to {e}")
return
self.procedure.update_reagents(reagentrole=reagentrole, name=name, lot=lot, expiry=expiry)
diff --git a/src/submissions/frontend/widgets/sample_checker.py b/src/submissions/frontend/widgets/sample_checker.py
index 368ec6d..761aa63 100644
--- a/src/submissions/frontend/widgets/sample_checker.py
+++ b/src/submissions/frontend/widgets/sample_checker.py
@@ -1,5 +1,7 @@
+"""
+
+"""
import logging
-from pathlib import Path
from typing import List
from PyQt6.QtCore import Qt, pyqtSlot
from PyQt6.QtWebChannel import QWebChannel
@@ -22,7 +24,6 @@ class SampleChecker(QDialog):
self.rsl_plate_number = RSLNamer.construct_new_plate_name(clientsubmission.to_dict())
else:
self.rsl_plate_number = clientsubmission
- logger.debug(f"RSL Plate number: {self.rsl_plate_number}")
self.samples = samples
self.setWindowTitle(title)
self.app = get_application_from_parent(parent)
@@ -35,16 +36,11 @@ class SampleChecker(QDialog):
self.channel = QWebChannel()
self.channel.registerObject('backend', self)
# NOTE: Used to maintain javascript functions.
- # template = env.get_template("sample_checker.html")
- # template_path = Path(template.environment.loader.__getattribute__("searchpath")[0])
- # with open(template_path.joinpath("css", "styles.css"), "r") as f:
- # css = [f.read()]
try:
samples = self.formatted_list
except AttributeError as e:
logger.error(f"Problem getting sample list: {e}")
samples = []
- # html = template.render(samples=samples, css=css, rsl_plate_number=self.rsl_plate_number)
html = render_details_template(template_name="sample_checker", samples=samples, rsl_plate_number=self.rsl_plate_number)
self.webview.setHtml(html)
self.webview.page().setWebChannel(self.channel)
@@ -55,13 +51,8 @@ class SampleChecker(QDialog):
self.layout.addWidget(self.buttonBox, 11, 9, 1, 1, alignment=Qt.AlignmentFlag.AlignRight)
self.setLayout(self.layout)
- # with open("sample_checker_rendered.html", "w") as f:
- # f.write(html)
- logger.debug(f"HTML sample checker written!")
-
@pyqtSlot(str, str, str)
def text_changed(self, submission_rank: str, key: str, new_value: str):
- logger.debug(f"Name: {submission_rank}, Key: {key}, Value: {new_value}")
try:
item = next((sample for sample in self.samples if int(submission_rank) == sample.submission_rank))
except StopIteration:
@@ -71,7 +62,6 @@ class SampleChecker(QDialog):
@pyqtSlot(int, bool)
def enable_sample(self, submission_rank: int, enabled: bool):
- logger.debug(f"Name: {submission_rank}, Enabled: {enabled}")
try:
item = next((sample for sample in self.samples if int(submission_rank) == sample.submission_rank))
except StopIteration:
@@ -81,14 +71,12 @@ class SampleChecker(QDialog):
@pyqtSlot(str)
def set_rsl_plate_number(self, rsl_plate_number: str):
- logger.debug(f"RSL plate num: {rsl_plate_number}")
self.rsl_plate_number = rsl_plate_number
@property
def formatted_list(self) -> List[dict]:
output = []
for sample in self.samples:
- # logger.debug(sample)
s = sample.improved_dict(dictionaries=False)
if s['sample_id'] in [item['sample_id'] for item in output]:
s['color'] = "red"
diff --git a/src/submissions/frontend/widgets/submission_details.py b/src/submissions/frontend/widgets/submission_details.py
index 27f52c6..ebbc890 100644
--- a/src/submissions/frontend/widgets/submission_details.py
+++ b/src/submissions/frontend/widgets/submission_details.py
@@ -62,14 +62,9 @@ class SubmissionDetails(QDialog):
css = f.read()
key = object.__class__.__name__.lower()
d = {key: details}
- # logger.debug(f"Using details: {pformat(d['procedure']['equipment'])}")
html = template.render(**d, css=[css])
self.webview.setHtml(html)
self.setWindowTitle(f"{object.__class__.__name__} Details - {object.name}")
- # with open(f"{object.__class__.__name__}_details_rendered.html", "w") as f:
- # f.write(html)
- # pass
-
def activate_export(self) -> None:
"""
@@ -96,10 +91,10 @@ class SubmissionDetails(QDialog):
@pyqtSlot(str)
def equipment_details(self, equipment: str | Equipment):
- logger.debug(f"Equipment details")
if isinstance(equipment, str):
equipment = Equipment.query(name=equipment)
- base_dict = equipment.to_sub_dict(full_data=True)
+ # base_dict = equipment.to_sub_dict(full_data=True)
+ base_dict = equipment.details_dict()
template = equipment.details_template
template_path = Path(template.environment.loader.__getattribute__("searchpath")[0])
with open(template_path.joinpath("css", "styles.css"), "r") as f:
@@ -110,10 +105,10 @@ class SubmissionDetails(QDialog):
@pyqtSlot(str)
def process_details(self, process: str | Process):
- logger.debug(f"Process details")
if isinstance(process, str):
process = Process.query(name=process)
- base_dict = process.to_sub_dict(full_data=True)
+ # base_dict = process.to_sub_dict(full_data=True)
+ base_dict = process.details_dict()
template = process.details_template
template_path = Path(template.environment.loader.__getattribute__("searchpath")[0])
with open(template_path.joinpath("css", "styles.css"), "r") as f:
@@ -124,10 +119,10 @@ class SubmissionDetails(QDialog):
@pyqtSlot(str)
def tips_details(self, tips: str | Tips):
- logger.debug(f"Equipment details: {tips}")
if isinstance(tips, str):
tips = Tips.query(lot=tips)
- base_dict = tips.to_sub_dict(full_data=True)
+ # base_dict = tips.to_sub_dict(full_data=True)
+ base_dict = tips.details_dict()
template = tips.details_template
template_path = Path(template.environment.loader.__getattribute__("searchpath")[0])
with open(template_path.joinpath("css", "styles.css"), "r") as f:
@@ -144,10 +139,10 @@ class SubmissionDetails(QDialog):
Args:
sample (str): Submitter Id of the sample.
"""
- logger.debug(f"Sample details.")
if isinstance(sample, str):
sample = Sample.query(sample_id=sample)
- base_dict = sample.to_sub_dict(full_data=True)
+ # base_dict = sample.to_sub_dict(full_data=True)
+ base_dict = sample.details_dict()
exclude = ['procedure', 'excluded', 'colour', 'tooltip']
base_dict['excluded'] = exclude
template = sample.details_template
@@ -155,8 +150,6 @@ class SubmissionDetails(QDialog):
with open(template_path.joinpath("css", "styles.css"), "r") as f:
css = f.read()
html = template.render(sample=base_dict, css=css)
- # with open(f"{sample.sample_id}.html", 'w') as f:
- # f.write(html)
self.webview.setHtml(html)
self.setWindowTitle(f"Sample Details - {sample.sample_id}")
@@ -169,13 +162,13 @@ class SubmissionDetails(QDialog):
kit (str | KitType): Name of kittype.
reagent (str | Reagent): Lot number of the reagent
"""
- logger.debug(f"Reagent details.")
if isinstance(reagent, str):
reagent = Reagent.query(lot=reagent)
if isinstance(proceduretype, str):
self.proceduretype = ProcedureType.query(name=proceduretype)
- base_dict = reagent.to_sub_dict(proceduretype=self.proceduretype, full_data=True)
+ # base_dict = reagent.to_sub_dict(proceduretype=self.proceduretype, full_data=True)
# base_dict = reagent.details_dict(proceduretype=self.proceduretype, full_data=True)
+ base_dict = reagent.details_dict()
env = jinja_template_loading()
temp_name = "reagent_details.html"
try:
@@ -221,7 +214,6 @@ class SubmissionDetails(QDialog):
Args:
run (str | BasicRun): Submission of interest.
"""
- logger.debug(f"Run details.")
if isinstance(run, str):
run = Run.query(name=run)
self.rsl_plate_number = run.rsl_plate_number
@@ -234,7 +226,6 @@ class SubmissionDetails(QDialog):
template_path = Path(self.template.environment.loader.__getattribute__("searchpath")[0])
with open(template_path.joinpath("css", "styles.css"), "r") as f:
css = f.read()
- # logger.debug(f"Base dictionary of procedure {self.name}: {pformat(self.base_dict)}")
self.html = self.template.render(sub=self.base_dict, permission=is_power_user(), css=css)
self.webview.setHtml(self.html)
diff --git a/src/submissions/frontend/widgets/submission_table.py b/src/submissions/frontend/widgets/submission_table.py
index 4230cd7..b6c827e 100644
--- a/src/submissions/frontend/widgets/submission_table.py
+++ b/src/submissions/frontend/widgets/submission_table.py
@@ -4,13 +4,11 @@ Contains widgets specific to the procedure summary and procedure details.
import sys, logging, re
from pprint import pformat
-
from PyQt6.QtWidgets import QTableView, QMenu, QTreeView, QStyledItemDelegate, QStyle, QStyleOptionViewItem, \
QHeaderView, QAbstractItemView, QWidget, QTreeWidgetItemIterator
from PyQt6.QtCore import Qt, QAbstractTableModel, QSortFilterProxyModel, pyqtSlot, QModelIndex
from PyQt6.QtGui import QAction, QCursor, QStandardItemModel, QStandardItem, QIcon, QColor, QContextMenuEvent
from typing import Dict, List
-
# from backend import Procedure
from backend.db.models.submissions import Run, ClientSubmission
from backend.db.models.procedures import Procedure
@@ -91,7 +89,6 @@ class SubmissionsSheet(QTableView):
"""
sets data in model
"""
- # self.data = ClientSubmission.submissions_to_df(page=page, page_size=page_size)
self.data = Run.submissions_to_df(page=page, page_size=page_size)
try:
self.data['Id'] = self.data['Id'].apply(str)
@@ -232,29 +229,6 @@ class SubmissionsSheet(QTableView):
return report
-# class ClientSubmissionDelegate(QStyledItemDelegate):
-#
-# def __init__(self, parent=None):
-# super(ClientSubmissionDelegate, self).__init__(parent)
-# pixmapi = QStyle.StandardPixmap.SP_ToolBarHorizontalExtensionButton
-# icon1 = QWidget().style().standardIcon(pixmapi)
-# pixmapi = QStyle.StandardPixmap.SP_ToolBarVerticalExtensionButton
-# icon2 = QWidget().style().standardIcon(pixmapi)
-# self._plus_icon = icon1
-# self._minus_icon = icon2
-#
-# def initStyleOption(self, option, index):
-# super(ClientSubmissionDelegate, self).initStyleOption(option, index)
-# if not index.parent().isValid():
-# is_open = bool(option.state & QStyle.StateFlag.State_Open)
-# option.features |= QStyleOptionViewItem.ViewItemFeature.HasDecoration
-# option.icon = self._minus_icon if is_open else self._plus_icon
-
-
-# class RunDelegate(ClientSubmissionDelegate):
-# pass
-
-
class SubmissionsTree(QTreeView):
"""
https://stackoverflow.com/questions/54385437/how-can-i-make-a-table-that-can-collapse-its-rows-into-categories-in-qt
@@ -264,20 +238,12 @@ class SubmissionsTree(QTreeView):
super(SubmissionsTree, self).__init__(parent)
self.app = get_application_from_parent(parent)
self.total_count = ClientSubmission.__database_session__.query(ClientSubmission).count()
- # self.setIndentation(0)
self.setExpandsOnDoubleClick(False)
- # self.clicked.connect(self.on_clicked)
- # delegate1 = ClientSubmissionDelegate(self)
- # self.setItemDelegateForColumn(0, delegate1)
self.model = model
self.setModel(self.model)
- # self.header().setSectionResizeMode(0, QHeaderView.sectionResizeMode(self,0).ResizeToContents)
self.setSelectionBehavior(QAbstractItemView.selectionBehavior(self).SelectRows)
- # self.setStyleSheet("background-color: #0D1225;")
self.set_data()
self.doubleClicked.connect(self.show_details)
- # self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
- # self.customContextMenuRequested.connect(self.open_menu)
self.setStyleSheet("""
QTreeView {
background-color: #f5f5f5;
@@ -294,20 +260,13 @@ class SubmissionsTree(QTreeView):
}
""")
- # Enable alternating row colors
+ # Note: Enable alternating row colors
self.setAlternatingRowColors(True)
self.setIndentation(20)
self.setItemsExpandable(True)
- # self.expanded.connect(self.expand_item)
-
for ii in range(2):
self.resizeColumnToContents(ii)
- # @pyqtSlot(QModelIndex)
- # def on_clicked(self, index):
- # if not index.parent().isValid() and index.column() == 0:
- # self.setExpanded(index, not self.isExpanded(index))
-
def expand_item(self, event: QModelIndex):
logger.debug(f"Data: {event.data()}")
logger.debug(f"Parent {event.parent().data()}")
@@ -327,18 +286,11 @@ class SubmissionsTree(QTreeView):
"""
indexes = self.selectedIndexes()
dicto = next((item.data(1) for item in indexes if item.data(1)))
- logger.debug(f"Dicto: {pformat(dicto)}")
query_obj = dicto['item_type'].query(name=dicto['query_str'], limit=1)
- logger.debug(f"Querying: {query_obj}")
# NOTE: Convert to data in id column (i.e. column 0)
- # id = id.sibling(id.row(), 0).data()
- # logger.debug(id.model().query_group_object(id.row()))
- # clientsubmission = id.model().query_group_object(id.row())
self.menu = QMenu(self)
self.con_actions = query_obj.custom_context_events
- logger.debug(f"Context menu actions: {self.con_actions}")
for key in self.con_actions.keys():
- logger.debug(key)
match key.lower():
case "add procedure":
action = QMenu(self.menu)
@@ -362,7 +314,7 @@ class SubmissionsTree(QTreeView):
action = QAction(key, self)
action.triggered.connect(lambda _, action_name=key: self.con_actions[action_name](obj=self))
self.menu.addAction(action)
- # # NOTE: add other required actions
+ # NOTE: add other required actions
self.menu.popup(QCursor.pos())
def set_data(self, page: int = 1, page_size: int = 250) -> None:
@@ -372,8 +324,6 @@ class SubmissionsTree(QTreeView):
self.clear()
self.data = [item.to_dict(full_data=True) for item in
ClientSubmission.query(chronologic=True, page=page, page_size=page_size)]
- # logger.debug(f"setting data:\n {pformat(self.data)}")
- # sys.exit()
root = self.model.invisibleRootItem()
for submission in self.data:
group_str = f"{submission['submissiontype']}-{submission['submitter_plate_id']}-{submission['submitted_date']}"
@@ -382,26 +332,21 @@ class SubmissionsTree(QTreeView):
query_str=submission['submitter_plate_id'],
item_type=ClientSubmission
))
- # logger.debug(f"Added {submission_item}")
for run in submission['run']:
- # self.model.append_element_to_group(group_item=group_item, element=run)
run_item = self.model.add_child(parent=submission_item, child=dict(
name=run['plate_number'],
query_str=run['plate_number'],
item_type=Run
))
- # logger.debug(f"Added {run_item}")
for procedure in run['procedures']:
procedure_item = self.model.add_child(parent=run_item, child=dict(
name=procedure['name'],
query_str=procedure['name'],
item_type=Procedure
))
- # logger.debug(f"Added {procedure_item}")
def _populateTree(self, children, parent):
for child in children:
- logger.debug(child)
child_item = QStandardItem(child['name'])
parent.appendRow(child_item)
if isinstance(children, List):
@@ -409,22 +354,13 @@ class SubmissionsTree(QTreeView):
def clear(self):
if self.model != None:
- # self.model.clear() # works
self.model.setRowCount(0) # works
def show_details(self, sel: QModelIndex):
- # id = self.selectionModel().currentIndex()
# NOTE: Convert to data in id column (i.e. column 0)
- # id = id.sibling(id.row(), 1)
indexes = self.selectedIndexes()
dicto = next((item.data(1) for item in indexes if item.data(1)))
- # try:
- # id = int(id.data())
- # except ValueError:
- # return
- # Run.query(id=id).show_details(self)
obj = dicto['item_type'].query(name=dicto['query_str'], limit=1)
- logger.debug(obj)
obj.show_details(self)
def link_extractions(self):
@@ -437,14 +373,9 @@ class SubmissionsTree(QTreeView):
class ClientSubmissionRunModel(QStandardItemModel):
- def __init__(self, parent=None):
- super(ClientSubmissionRunModel, self).__init__(parent)
- # headers = ["", "id", "Plate Number", "Started Date", "Completed Date", "Signed By"]
- # self.setColumnCount(len(headers))
- # self.setHorizontalHeaderLabels(headers)
-
-
-
+ # def __init__(self, parent=None):
+ # super(ClientSubmissionRunModel, self).__init__(parent)
+ #
def add_child(self, parent: QStandardItem, child:dict):
item = QStandardItem(child['name'])
item.setData(dict(item_type=child['item_type'], query_str=child['query_str']), 1)
@@ -453,4 +384,4 @@ class ClientSubmissionRunModel(QStandardItemModel):
return item
def edit_item(self):
- pass
\ No newline at end of file
+ pass
diff --git a/src/submissions/frontend/widgets/submission_widget.py b/src/submissions/frontend/widgets/submission_widget.py
index 37c19f5..5843526 100644
--- a/src/submissions/frontend/widgets/submission_widget.py
+++ b/src/submissions/frontend/widgets/submission_widget.py
@@ -1,15 +1,13 @@
"""
Contains all procedure related frontend functions
"""
-import sys
-
+import sys, logging
from PyQt6.QtWidgets import (
QWidget, QPushButton, QVBoxLayout,
QComboBox, QDateEdit, QLineEdit, QLabel, QCheckBox, QHBoxLayout, QGridLayout
)
from PyQt6.QtCore import pyqtSignal, Qt, QSignalBlocker
from .functions import select_open_file, select_save_file
-import logging
from pathlib import Path
from tools import Report, Result, check_not_nan, main_form_style, report_result, get_application_from_parent
from backend.validators import PydReagent, PydClientSubmission, PydSample
@@ -121,37 +119,16 @@ class SubmissionFormContainer(QWidget):
report.add_result(Result(msg=f"File {fname.__str__()} not found.", status="critical"))
return report
# NOTE: create sheetparser using excel sheet and context from gui
- # try:
- # self.clientsubmissionparser = ClientSubmissionInfoParser(filepath=fname)
- # except PermissionError:
- # logger.error(f"Couldn't get permission to access file: {fname}")
- # return
- # except AttributeError:
- # self.clientsubmissionparser = ClientSubmissionInfoParser(filepath=fname)
- # try:
- # # self.prsr = SheetParser(filepath=fname)
- # self.sampleparser = ClientSubmissionSampleParser(filepath=fname)
- # except PermissionError:
- # logger.error(f"Couldn't get permission to access file: {fname}")
- # return
- # except AttributeError:
- # self.sampleparser = ClientSubmissionSampleParser(filepath=fname)
-
- # self.pydclientsubmission = self.clientsubmissionparser.to_pydantic()
- # self.pydsamples = self.sampleparser.to_pydantic()
- # logger.debug(f"Samples: {pformat(self.pydclientsubmission.sample)}")
self.clientsubmission_manager = DefaultClientSubmissionManager(parent=self, input_object=fname)
self.pydclientsubmission = self.clientsubmission_manager.to_pydantic()
checker = SampleChecker(self, "Sample Checker", self.pydclientsubmission.sample)
if checker.exec():
- # logger.debug(pformat(self.pydclientsubmission.sample))
try:
assert isinstance(self.pydclientsubmission, PydClientSubmission)
except AssertionError as e:
logger.error(f"Got wrong type for {self.pydclientsubmission}: {type(self.pydclientsubmission)}")
raise e
self.form = self.pydclientsubmission.to_form(parent=self)
- # self.form.samples = self.pydsamples
self.layout().addWidget(self.form)
else:
message = "Submission cancelled."
@@ -195,14 +172,11 @@ class SubmissionFormWidget(QWidget):
self.pyd = pyd
self.missing_info = []
self.submissiontype = SubmissionType.query(name=self.pyd.submissiontype['value'])
- # basic_submission_class = self.submission_type.submission_class
- # logger.debug(f"Basic procedure class: {basic_submission_class}")
defaults = Run.get_default_info("form_recover", "form_ignore", submissiontype=self.pyd.submissiontype['value'])
self.recover = defaults['form_recover']
self.ignore = defaults['form_ignore']
self.layout = QVBoxLayout()
for k in list(self.pyd.model_fields.keys()):# + list(self.pyd.model_extra.keys()):
- logger.debug(f"Pydantic field: {k}")
if k in self.ignore:
logger.warning(f"{k} in form_ignore {self.ignore}, not creating widget")
continue
@@ -218,7 +192,6 @@ class SubmissionFormWidget(QWidget):
value = self.pyd.model_extra[k]
except KeyError:
value = dict(value=None, missing=True)
- logger.debug(f"Pydantic value: {value}")
add_widget = self.create_widget(key=k, value=value, submission_type=self.submissiontype,
run_object=Run(), disable=check)
if add_widget is not None:
@@ -230,7 +203,6 @@ class SubmissionFormWidget(QWidget):
self.layout.addWidget(self.disabler)
self.disabler.checkbox.checkStateChanged.connect(self.disable_reagents)
self.setStyleSheet(main_form_style)
- # self.scrape_reagents(self.kittype)
self.setLayout(self.layout)
def disable_reagents(self):
@@ -298,7 +270,6 @@ class SubmissionFormWidget(QWidget):
if isinstance(reagent, self.ReagentFormWidget) or isinstance(reagent, QPushButton):
reagent.setParent(None)
reagents, integrity_report, missing_reagents = self.pyd.check_kit_integrity(extraction_kit=self.extraction_kit)
- # logger.debug(f"Reagents: {reagents}")
expiry_report = self.pyd.check_reagent_expiries(exempt=missing_reagents)
for reagent in reagents:
add_widget = self.ReagentFormWidget(parent=self, reagent=reagent, extraction_kit=self.extraction_kit)
@@ -364,34 +335,6 @@ class SubmissionFormWidget(QWidget):
return report
base_submission = self.pyd.to_sql()
# NOTE: check output message for issues
- # try:
- # trigger = result.results[-1]
- # code = trigger.code
- # except IndexError as e:
- # logger.error(result.results)
- # logger.error(f"Problem getting error code: {e}")
- # code = 0
- # match code:
- # # NOTE: code 0: everything is fine.
- # case 0:
- # pass
- # # NOTE: code 1: ask for overwrite
- # case 1:
- # dlg = QuestionAsker(title=f"Review {base_submission.rsl_plate_number}?", message=trigger.msg)
- # if dlg.exec():
- # # NOTE: Do not add duplicate reagents.
- # pass
- # else:
- # self.app.ctx.database_session.rollback()
- # report.add_result(Result(msg="Overwrite cancelled", status="Information"))
- # return report
- # # NOTE: code 2: No RSL plate number given
- # case 2:
- # report.add_result(result)
- # return report
- # case _:
- # pass
- # NOTE: add reagents to procedure object
if base_submission is None:
return
for reagent in base_submission.reagents:
@@ -450,7 +393,6 @@ class SubmissionFormWidget(QWidget):
if field is not None:
info[field] = value
self.pyd.reagents = reagents
- # logger.debug(f"Reagents from form: {reagents}")
for item in self.recover:
if hasattr(self, item):
value = getattr(self, item)
@@ -558,29 +500,29 @@ class SubmissionFormWidget(QWidget):
# NOTE: set combobox values to lookedup values
add_widget.addItems(labs)
add_widget.setToolTip("Select submitting lab.")
- case 'kittype':
- # NOTE: if extraction kittype not available, all other values fail
- if not check_not_nan(value):
- msg = AlertPop(message="Make sure to check your extraction kittype in the excel sheet!",
- status="warning")
- msg.exec()
- # NOTE: create combobox to hold looked up kits
- add_widget = MyQComboBox(scrollWidget=parent)
- # NOTE: lookup existing kits by 'proceduretype' decided on by sheetparser
- uses = [item.name for item in submission_type.kit_types]
- obj.uses = uses
- if check_not_nan(value):
- try:
- uses.insert(0, uses.pop(uses.index(value)))
- except ValueError:
- logger.warning(f"Couldn't find kittype in list, skipping move to top of list.")
- obj.ext_kit = value
- else:
- logger.error(f"Couldn't find {obj.prsr.sub['kittype']}")
- obj.ext_kit = uses[0]
- add_widget.addItems(uses)
- add_widget.setToolTip("Select extraction kittype.")
- parent.extraction_kit = add_widget.currentText()
+ # case 'kittype':
+ # # NOTE: if extraction kittype not available, all other values fail
+ # if not check_not_nan(value):
+ # msg = AlertPop(message="Make sure to check your extraction kittype in the excel sheet!",
+ # status="warning")
+ # msg.exec()
+ # # NOTE: create combobox to hold looked up kits
+ # add_widget = MyQComboBox(scrollWidget=parent)
+ # # NOTE: lookup existing kits by 'proceduretype' decided on by sheetparser
+ # uses = [item.name for item in submission_type.kit_types]
+ # obj.uses = uses
+ # if check_not_nan(value):
+ # try:
+ # uses.insert(0, uses.pop(uses.index(value)))
+ # except ValueError:
+ # logger.warning(f"Couldn't find kittype in list, skipping move to top of list.")
+ # obj.ext_kit = value
+ # else:
+ # logger.error(f"Couldn't find {obj.prsr.sub['kittype']}")
+ # obj.ext_kit = uses[0]
+ # add_widget.addItems(uses)
+ # add_widget.setToolTip("Select extraction kittype.")
+ # parent.extraction_kit = add_widget.currentText()
case 'submission_category':
add_widget = MyQComboBox(scrollWidget=parent)
categories = ['Diagnostic', "Surveillance", "Research"]
@@ -813,11 +755,8 @@ class ClientSubmissionFormWidget(SubmissionFormWidget):
self.disabler.setHidden(True)
except AttributeError:
pass
- # save_btn = QPushButton("Save")
self.sample = samples
- logger.debug(f"Samples: {self.sample}")
start_run_btn = QPushButton("Save")
- # self.layout.addWidget(save_btn)
self.layout.addWidget(start_run_btn)
start_run_btn.clicked.connect(self.create_new_submission)
@@ -846,7 +785,6 @@ class ClientSubmissionFormWidget(SubmissionFormWidget):
field, value = widget.parse_form()
if field is not None:
info[field] = value
- # logger.debug(f"Reagents from form: {reagents}")
for item in self.recover:
if hasattr(self, item):
value = getattr(self, item)
@@ -865,7 +803,6 @@ class ClientSubmissionFormWidget(SubmissionFormWidget):
@report_result
def create_new_submission(self, *args) -> Report:
pyd = self.to_pydantic()
- logger.debug(f"Pydantic: {pyd}")
sql = pyd.to_sql()
for sample in pyd.sample:
if isinstance(sample, PydSample):
@@ -874,9 +811,7 @@ class ClientSubmissionFormWidget(SubmissionFormWidget):
if sample.sample_id.lower() in ["", "blank"]:
continue
sample.save()
- # if sample not in sql.sample:
sql.add_sample(sample=sample)
- logger.debug(pformat(sql.__dict__))
try:
del sql._misc_info['sample']
except KeyError: