Pre- pydsubmission toForm method.
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -1,3 +1,5 @@
|
|||||||
|
- [ ] Make the kit verifier make more sense.
|
||||||
|
- [ ] Slim down the Import and Submit functions in main_window_functions.
|
||||||
- [x] Create custom store methods for submission, reagent and sample.
|
- [x] Create custom store methods for submission, reagent and sample.
|
||||||
- [x] Make pydantic models for other things that use constructors.
|
- [x] Make pydantic models for other things that use constructors.
|
||||||
- [x] Move backend.db.functions.constructor functions into Pydantic models.
|
- [x] Move backend.db.functions.constructor functions into Pydantic models.
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ def lookup_reagent_types(ctx:Settings,
|
|||||||
assert reagent.type != []
|
assert reagent.type != []
|
||||||
logger.debug(f"Looking up reagent type for {type(kit_type)} {kit_type} and {type(reagent)} {reagent}")
|
logger.debug(f"Looking up reagent type for {type(kit_type)} {kit_type} and {type(reagent)} {reagent}")
|
||||||
logger.debug(f"Kit reagent types: {kit_type.reagent_types}")
|
logger.debug(f"Kit reagent types: {kit_type.reagent_types}")
|
||||||
logger.debug(f"Reagent reagent types: {reagent._sa_instance_state}")
|
# logger.debug(f"Reagent reagent types: {reagent._sa_instance_state}")
|
||||||
result = list(set(kit_type.reagent_types).intersection(reagent.type))
|
result = list(set(kit_type.reagent_types).intersection(reagent.type))
|
||||||
logger.debug(f"Result: {result}")
|
logger.debug(f"Result: {result}")
|
||||||
return result[0]
|
return result[0]
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from sqlalchemy.orm import relationship, validates
|
|||||||
from sqlalchemy.ext.associationproxy import association_proxy
|
from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
from datetime import date
|
from datetime import date
|
||||||
import logging
|
import logging
|
||||||
|
from tools import Settings, check_authorization
|
||||||
|
|
||||||
logger = logging.getLogger(f'submissions.{__name__}')
|
logger = logging.getLogger(f'submissions.{__name__}')
|
||||||
|
|
||||||
@@ -100,6 +101,11 @@ class KitType(Base):
|
|||||||
map['info'] = {}
|
map['info'] = {}
|
||||||
return map
|
return map
|
||||||
|
|
||||||
|
@check_authorization
|
||||||
|
def save(self, ctx:Settings):
|
||||||
|
ctx.database_session.add(self)
|
||||||
|
ctx.database_session.commit()
|
||||||
|
|
||||||
class ReagentType(Base):
|
class ReagentType(Base):
|
||||||
"""
|
"""
|
||||||
Base of reagent type abstract
|
Base of reagent type abstract
|
||||||
@@ -265,12 +271,21 @@ class Reagent(Base):
|
|||||||
rtype = reagent_role.name
|
rtype = reagent_role.name
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
rtype = "Unknown"
|
rtype = "Unknown"
|
||||||
|
try:
|
||||||
|
expiry = self.expiry.strftime("%Y-%m-%d")
|
||||||
|
except:
|
||||||
|
expiry = date.today()
|
||||||
return {
|
return {
|
||||||
"name":self.name,
|
"name":self.name,
|
||||||
"type": rtype,
|
"type": rtype,
|
||||||
"lot": self.lot,
|
"lot": self.lot,
|
||||||
"expiry": self.expiry.strftime("%Y-%m-%d")
|
"expiry": self.expiry.strftime("%Y-%m-%d")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def save(self, ctx:Settings):
|
||||||
|
ctx.database_session.add(self)
|
||||||
|
ctx.database_session.commit()
|
||||||
|
|
||||||
|
|
||||||
class Discount(Base):
|
class Discount(Base):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -853,7 +853,6 @@ class WastewaterSample(BasicSample):
|
|||||||
output_dict["submitter_id"] = output_dict['ww_full_sample_id']
|
output_dict["submitter_id"] = output_dict['ww_full_sample_id']
|
||||||
return output_dict
|
return output_dict
|
||||||
|
|
||||||
|
|
||||||
class BacterialCultureSample(BasicSample):
|
class BacterialCultureSample(BasicSample):
|
||||||
"""
|
"""
|
||||||
base of bacterial culture sample
|
base of bacterial culture sample
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ class SheetParser(object):
|
|||||||
kit = lookup_kit_types(ctx=self.ctx, name=self.sub['extraction_kit']['value'])
|
kit = lookup_kit_types(ctx=self.ctx, name=self.sub['extraction_kit']['value'])
|
||||||
allowed_reagents = [item.name for item in kit.get_reagents()]
|
allowed_reagents = [item.name for item in kit.get_reagents()]
|
||||||
logger.debug(f"List of reagents for comparison with allowed_reagents: {pprint.pformat(self.sub['reagents'])}")
|
logger.debug(f"List of reagents for comparison with allowed_reagents: {pprint.pformat(self.sub['reagents'])}")
|
||||||
self.sub['reagents'] = [reagent for reagent in self.sub['reagents'] if reagent['value'].type in allowed_reagents]
|
# self.sub['reagents'] = [reagent for reagent in self.sub['reagents'] if reagent['value'].type in allowed_reagents]
|
||||||
|
self.sub['reagents'] = [reagent for reagent in self.sub['reagents'] if reagent.type in allowed_reagents]
|
||||||
|
|
||||||
def to_pydantic(self) -> PydSubmission:
|
def to_pydantic(self) -> PydSubmission:
|
||||||
"""
|
"""
|
||||||
@@ -231,8 +232,9 @@ class ReagentParser(object):
|
|||||||
lot = df.iat[relevant[item]['lot']['row']-1, relevant[item]['lot']['column']-1]
|
lot = df.iat[relevant[item]['lot']['row']-1, relevant[item]['lot']['column']-1]
|
||||||
expiry = df.iat[relevant[item]['expiry']['row']-1, relevant[item]['expiry']['column']-1]
|
expiry = df.iat[relevant[item]['expiry']['row']-1, relevant[item]['expiry']['column']-1]
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
listo.append(dict(value=PydReagent(ctx=self.ctx, type=item.strip(), lot=None, exp=None, name=None), parsed=False))
|
listo.append(PydReagent(ctx=self.ctx, type=item.strip(), lot=None, exp=None, name=None, parsed=False))
|
||||||
continue
|
continue
|
||||||
|
# If the cell is blank tell the PydReagent
|
||||||
if check_not_nan(lot):
|
if check_not_nan(lot):
|
||||||
parsed = True
|
parsed = True
|
||||||
else:
|
else:
|
||||||
@@ -240,7 +242,7 @@ class ReagentParser(object):
|
|||||||
# logger.debug(f"Got lot for {item}-{name}: {lot} as {type(lot)}")
|
# logger.debug(f"Got lot for {item}-{name}: {lot} as {type(lot)}")
|
||||||
lot = str(lot)
|
lot = str(lot)
|
||||||
logger.debug(f"Going into pydantic: name: {name}, lot: {lot}, expiry: {expiry}, type: {item.strip()}")
|
logger.debug(f"Going into pydantic: name: {name}, lot: {lot}, expiry: {expiry}, type: {item.strip()}")
|
||||||
listo.append(dict(value=PydReagent(ctx=self.ctx, type=item.strip(), lot=lot, exp=expiry, name=name), parsed=parsed))
|
listo.append(PydReagent(ctx=self.ctx, type=item.strip(), lot=lot, expiry=expiry, name=name, parsed=parsed))
|
||||||
logger.debug(f"Returning listo: {listo}")
|
logger.debug(f"Returning listo: {listo}")
|
||||||
return listo
|
return listo
|
||||||
|
|
||||||
@@ -387,7 +389,11 @@ class SampleParser(object):
|
|||||||
# Set row in lookup table to blank values to prevent multipe lookups.
|
# Set row in lookup table to blank values to prevent multipe lookups.
|
||||||
try:
|
try:
|
||||||
self.lookup_table.loc[self.lookup_table['Sample #']==addition['Sample #']] = np.nan
|
self.lookup_table.loc[self.lookup_table['Sample #']==addition['Sample #']] = np.nan
|
||||||
except ValueError:
|
except (ValueError, KeyError):
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
self.lookup_table.loc[self.lookup_table['Well']==addition['Well']] = np.nan
|
||||||
|
except (ValueError, KeyError):
|
||||||
pass
|
pass
|
||||||
logger.debug(f"Output sample dict: {sample}")
|
logger.debug(f"Output sample dict: {sample}")
|
||||||
logger.debug(f"Final lookup_table: \n\n {self.lookup_table}")
|
logger.debug(f"Final lookup_table: \n\n {self.lookup_table}")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Contains pydantic models and accompanying validators
|
Contains pydantic models and accompanying validators
|
||||||
'''
|
'''
|
||||||
import uuid
|
import uuid
|
||||||
|
from PyQt6 import QtCore
|
||||||
from pydantic import BaseModel, field_validator, Field
|
from pydantic import BaseModel, field_validator, Field
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from dateutil.parser import parse
|
from dateutil.parser import parse
|
||||||
@@ -18,6 +19,7 @@ from backend.db.functions import (lookup_submissions, lookup_reagent_types, look
|
|||||||
)
|
)
|
||||||
from backend.db.models import *
|
from backend.db.models import *
|
||||||
from sqlalchemy.exc import InvalidRequestError, StatementError
|
from sqlalchemy.exc import InvalidRequestError, StatementError
|
||||||
|
from PyQt6.QtWidgets import QComboBox, QWidget, QLabel, QVBoxLayout
|
||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
@@ -25,8 +27,9 @@ class PydReagent(BaseModel):
|
|||||||
ctx: Settings
|
ctx: Settings
|
||||||
lot: str|None
|
lot: str|None
|
||||||
type: str|None
|
type: str|None
|
||||||
exp: date|None
|
expiry: date|None
|
||||||
name: str|None
|
name: str|None
|
||||||
|
parsed: bool = Field(default=False)
|
||||||
|
|
||||||
@field_validator("type", mode='before')
|
@field_validator("type", mode='before')
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -61,7 +64,7 @@ class PydReagent(BaseModel):
|
|||||||
return value.upper()
|
return value.upper()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@field_validator("exp", mode="before")
|
@field_validator("expiry", mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def enforce_date(cls, value):
|
def enforce_date(cls, value):
|
||||||
if value != None:
|
if value != None:
|
||||||
@@ -86,7 +89,7 @@ class PydReagent(BaseModel):
|
|||||||
else:
|
else:
|
||||||
return values.data['type']
|
return values.data['type']
|
||||||
|
|
||||||
def toSQL(self):# -> Tuple[Reagent, dict]:
|
def toSQL(self) -> Tuple[Reagent, dict]:
|
||||||
result = None
|
result = None
|
||||||
logger.debug(f"Reagent SQL constructor is looking up type: {self.type}, lot: {self.lot}")
|
logger.debug(f"Reagent SQL constructor is looking up type: {self.type}, lot: {self.lot}")
|
||||||
reagent = lookup_reagents(ctx=self.ctx, lot_number=self.lot)
|
reagent = lookup_reagents(ctx=self.ctx, lot_number=self.lot)
|
||||||
@@ -113,6 +116,10 @@ class PydReagent(BaseModel):
|
|||||||
# NOTE: this will now be done only in the reporting phase to account for potential changes in end-of-life extensions
|
# NOTE: this will now be done only in the reporting phase to account for potential changes in end-of-life extensions
|
||||||
return reagent, result
|
return reagent, result
|
||||||
|
|
||||||
|
def toForm(self, parent:QWidget, extraction_kit:str) -> QComboBox:
|
||||||
|
from frontend.custom_widgets.misc import ReagentFormWidget
|
||||||
|
return ReagentFormWidget(parent=parent, reagent=self, extraction_kit=extraction_kit)
|
||||||
|
|
||||||
class PydSample(BaseModel, extra='allow'):
|
class PydSample(BaseModel, extra='allow'):
|
||||||
|
|
||||||
submitter_id: str
|
submitter_id: str
|
||||||
@@ -127,13 +134,6 @@ class PydSample(BaseModel, extra='allow'):
|
|||||||
return [value]
|
return [value]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
# @field_validator(column)
|
|
||||||
# @classmethod
|
|
||||||
# def column_int_to_list(cls, value):
|
|
||||||
# if isinstance(value, int):
|
|
||||||
# return [value]
|
|
||||||
# return value
|
|
||||||
|
|
||||||
def toSQL(self, ctx:Settings, submission):
|
def toSQL(self, ctx:Settings, submission):
|
||||||
result = None
|
result = None
|
||||||
self.__dict__.update(self.model_extra)
|
self.__dict__.update(self.model_extra)
|
||||||
@@ -302,6 +302,22 @@ class PydSubmission(BaseModel, extra='allow'):
|
|||||||
value['value'] = values.data['submission_type']['value']
|
value['value'] = values.data['submission_type']['value']
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def handle_duplicate_samples(self):
|
||||||
|
submitter_ids = list(set([sample.submitter_id for sample in self.samples]))
|
||||||
|
output = []
|
||||||
|
for id in submitter_ids:
|
||||||
|
relevants = [item for item in self.samples if item.submitter_id==id]
|
||||||
|
if len(relevants) <= 1:
|
||||||
|
output += relevants
|
||||||
|
else:
|
||||||
|
rows = [item.row[0] for item in relevants]
|
||||||
|
columns = [item.column[0] for item in relevants]
|
||||||
|
dummy = relevants[0]
|
||||||
|
dummy.row = rows
|
||||||
|
dummy.column = columns
|
||||||
|
output.append(dummy)
|
||||||
|
self.samples = output
|
||||||
|
|
||||||
def toSQL(self):
|
def toSQL(self):
|
||||||
code = 0
|
code = 0
|
||||||
msg = None
|
msg = None
|
||||||
@@ -380,21 +396,7 @@ class PydSubmission(BaseModel, extra='allow'):
|
|||||||
logger.debug(f"Constructed submissions message: {msg}")
|
logger.debug(f"Constructed submissions message: {msg}")
|
||||||
return instance, {'code':code, 'message':msg}
|
return instance, {'code':code, 'message':msg}
|
||||||
|
|
||||||
def handle_duplicate_samples(self):
|
def toForm(self):
|
||||||
submitter_ids = list(set([sample.submitter_id for sample in self.samples]))
|
|
||||||
output = []
|
|
||||||
for id in submitter_ids:
|
|
||||||
relevants = [item for item in self.samples if item.submitter_id==id]
|
|
||||||
if len(relevants) <= 1:
|
|
||||||
output += relevants
|
|
||||||
else:
|
|
||||||
rows = [item.row[0] for item in relevants]
|
|
||||||
columns = [item.column[0] for item in relevants]
|
|
||||||
dummy = relevants[0]
|
|
||||||
dummy.row = rows
|
|
||||||
dummy.column = columns
|
|
||||||
output.append(dummy)
|
|
||||||
self.samples = output
|
|
||||||
|
|
||||||
class PydContact(BaseModel):
|
class PydContact(BaseModel):
|
||||||
|
|
||||||
@@ -447,19 +449,21 @@ class PydReagentType(BaseModel):
|
|||||||
assoc = None
|
assoc = None
|
||||||
if assoc == None:
|
if assoc == None:
|
||||||
assoc = KitTypeReagentTypeAssociation(kit_type=kit, reagent_type=instance, uses=self.uses, required=self.required)
|
assoc = KitTypeReagentTypeAssociation(kit_type=kit, reagent_type=instance, uses=self.uses, required=self.required)
|
||||||
kit.kit_reagenttype_associations.append(assoc)
|
# kit.kit_reagenttype_associations.append(assoc)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
class PydKit(BaseModel):
|
class PydKit(BaseModel):
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
reagent_types: List[PydReagentType]|None
|
reagent_types: List[PydReagentType] = []
|
||||||
|
|
||||||
def toSQL(self, ctx):
|
def toSQL(self, ctx):
|
||||||
|
result = dict(message=None, status='Information')
|
||||||
instance = lookup_kit_types(ctx=ctx, name=self.name)
|
instance = lookup_kit_types(ctx=ctx, name=self.name)
|
||||||
if instance == None:
|
if instance == None:
|
||||||
instance = KitType(name=self.name)
|
instance = KitType(name=self.name)
|
||||||
instance.reagent_types = [item.toSQL(ctx, instance) for item in self.reagent_types]
|
# instance.reagent_types = [item.toSQL(ctx, instance) for item in self.reagent_types]
|
||||||
return instance
|
[item.toSQL(ctx, instance) for item in self.reagent_types]
|
||||||
|
return instance, result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,22 @@ Constructs main application.
|
|||||||
'''
|
'''
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
import sys
|
import sys
|
||||||
from typing import Tuple
|
|
||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QMainWindow, QToolBar,
|
QMainWindow, QToolBar,
|
||||||
QTabWidget, QWidget, QVBoxLayout,
|
QTabWidget, QWidget, QVBoxLayout,
|
||||||
QComboBox, QHBoxLayout,
|
QComboBox, QHBoxLayout,
|
||||||
QScrollArea, QLineEdit, QDateEdit
|
QScrollArea, QLineEdit, QDateEdit
|
||||||
)
|
)
|
||||||
from PyQt6.QtCore import Qt, pyqtSignal
|
from PyQt6.QtCore import pyqtSignal
|
||||||
from PyQt6.QtGui import QAction
|
from PyQt6.QtGui import QAction
|
||||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from backend.db import (
|
from backend.db import (
|
||||||
store_object, lookup_control_types, lookup_modes, #construct_reagent
|
lookup_control_types, lookup_modes
|
||||||
)
|
)
|
||||||
from backend.validators import PydSubmission, PydReagent
|
from backend.validators import PydSubmission, PydReagent
|
||||||
from tools import check_if_app, Settings
|
from tools import check_if_app, Settings
|
||||||
from frontend.custom_widgets import SubmissionsSheet, AlertPop, AddReagentForm, KitAdder, ControlsDatePicker, ImportReagent
|
from frontend.custom_widgets import SubmissionsSheet, AlertPop, AddReagentForm, KitAdder, ControlsDatePicker, ImportReagent, ReagentFormWidget
|
||||||
import logging
|
import logging
|
||||||
from datetime import date
|
from datetime import date
|
||||||
import webbrowser
|
import webbrowser
|
||||||
@@ -225,7 +224,9 @@ class App(QMainWindow):
|
|||||||
reagent = PydReagent(ctx=self.ctx, **info)
|
reagent = PydReagent(ctx=self.ctx, **info)
|
||||||
# send reagent to db
|
# send reagent to db
|
||||||
# store_reagent(ctx=self.ctx, reagent=reagent)
|
# store_reagent(ctx=self.ctx, reagent=reagent)
|
||||||
result = store_object(ctx=self.ctx, object=reagent.toSQL()[0])
|
sqlobj, result = reagent.toSQL()
|
||||||
|
sqlobj.save(ctx=self.ctx)
|
||||||
|
# result = store_object(ctx=self.ctx, object=reagent.toSQL()[0])
|
||||||
self.result_reporter(result=result)
|
self.result_reporter(result=result)
|
||||||
return reagent
|
return reagent
|
||||||
|
|
||||||
@@ -320,7 +321,7 @@ class App(QMainWindow):
|
|||||||
|
|
||||||
class AddSubForm(QWidget):
|
class AddSubForm(QWidget):
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent:QWidget):
|
||||||
logger.debug(f"Initializating subform...")
|
logger.debug(f"Initializating subform...")
|
||||||
super(QWidget, self).__init__(parent)
|
super(QWidget, self).__init__(parent)
|
||||||
self.layout = QVBoxLayout(self)
|
self.layout = QVBoxLayout(self)
|
||||||
@@ -337,7 +338,7 @@ class AddSubForm(QWidget):
|
|||||||
self.tabs.addTab(self.tab2,"Controls")
|
self.tabs.addTab(self.tab2,"Controls")
|
||||||
self.tabs.addTab(self.tab3, "Add Kit")
|
self.tabs.addTab(self.tab3, "Add Kit")
|
||||||
# Create submission adder form
|
# Create submission adder form
|
||||||
self.formwidget = SubmissionFormWidget(self)
|
self.formwidget = SubmissionFormContainer(self)
|
||||||
self.formlayout = QVBoxLayout(self)
|
self.formlayout = QVBoxLayout(self)
|
||||||
self.formwidget.setLayout(self.formlayout)
|
self.formwidget.setLayout(self.formlayout)
|
||||||
self.formwidget.setFixedWidth(300)
|
self.formwidget.setFixedWidth(300)
|
||||||
@@ -391,7 +392,7 @@ class AddSubForm(QWidget):
|
|||||||
self.layout.addWidget(self.tabs)
|
self.layout.addWidget(self.tabs)
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
class SubmissionFormWidget(QWidget):
|
class SubmissionFormContainer(QWidget):
|
||||||
|
|
||||||
import_drag = pyqtSignal(Path)
|
import_drag = pyqtSignal(Path)
|
||||||
|
|
||||||
@@ -399,9 +400,7 @@ class SubmissionFormWidget(QWidget):
|
|||||||
logger.debug(f"Setting form widget...")
|
logger.debug(f"Setting form widget...")
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.ignore = [None, "", "qt_spinbox_lineedit", "qt_scrollarea_viewport", "qt_scrollarea_hcontainer",
|
|
||||||
"qt_scrollarea_vcontainer", "submit_btn"
|
|
||||||
]
|
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
|
|
||||||
def dragEnterEvent(self, event):
|
def dragEnterEvent(self, event):
|
||||||
@@ -414,6 +413,10 @@ class SubmissionFormWidget(QWidget):
|
|||||||
fname = Path([u.toLocalFile() for u in event.mimeData().urls()][0])
|
fname = Path([u.toLocalFile() for u in event.mimeData().urls()][0])
|
||||||
self.import_drag.emit(fname)
|
self.import_drag.emit(fname)
|
||||||
|
|
||||||
|
def clear_form(self):
|
||||||
|
for item in self.findChildren(QWidget):
|
||||||
|
item.setParent(None)
|
||||||
|
|
||||||
def parse_form(self) -> PydSubmission:
|
def parse_form(self) -> PydSubmission:
|
||||||
logger.debug(f"Hello from form parser!")
|
logger.debug(f"Hello from form parser!")
|
||||||
info = {}
|
info = {}
|
||||||
@@ -421,11 +424,15 @@ class SubmissionFormWidget(QWidget):
|
|||||||
samples = self.parent.parent.samples
|
samples = self.parent.parent.samples
|
||||||
logger.debug(f"Using samples: {pformat(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) if widget.objectName() not in self.ignore]
|
||||||
|
# widgets = [widget for widget in self.findChildren(QWidget)]
|
||||||
for widget in widgets:
|
for widget in widgets:
|
||||||
logger.debug(f"Parsed widget: {widget.objectName()} of type {type(widget)}")
|
logger.debug(f"Parsed widget: {widget.objectName()} of type {type(widget)}")
|
||||||
match widget:
|
match widget:
|
||||||
|
case ReagentFormWidget():
|
||||||
|
reagent, _ = widget.parse_form()
|
||||||
|
reagents.append(reagent)
|
||||||
case ImportReagent():
|
case ImportReagent():
|
||||||
reagent = dict(name=widget.objectName().replace("lot_", ""), lot=widget.currentText(), type=None, exp=None)
|
reagent = dict(name=widget.objectName().replace("lot_", ""), lot=widget.currentText(), type=None, expiry=None)
|
||||||
reagents.append(PydReagent(ctx=self.parent.parent.ctx, **reagent))
|
reagents.append(PydReagent(ctx=self.parent.parent.ctx, **reagent))
|
||||||
case QLineEdit():
|
case QLineEdit():
|
||||||
info[widget.objectName()] = dict(value=widget.text())
|
info[widget.objectName()] = dict(value=widget.text())
|
||||||
@@ -435,5 +442,6 @@ class SubmissionFormWidget(QWidget):
|
|||||||
info[widget.objectName()] = dict(value=widget.date().toPyDate())
|
info[widget.objectName()] = dict(value=widget.date().toPyDate())
|
||||||
logger.debug(f"Info: {pformat(info)}")
|
logger.debug(f"Info: {pformat(info)}")
|
||||||
logger.debug(f"Reagents: {pformat(reagents)}")
|
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)
|
submission = PydSubmission(ctx=self.parent.parent.ctx, filepath=self.parent.parent.current_file, reagents=reagents, samples=samples, **info)
|
||||||
return submission
|
return submission
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ from backend.db.models import SubmissionTypeKitTypeAssociation
|
|||||||
from sqlalchemy import FLOAT, INTEGER
|
from sqlalchemy import FLOAT, INTEGER
|
||||||
import logging
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from .pop_ups import AlertPop
|
from .pop_ups import AlertPop, QuestionAsker
|
||||||
from backend.validators import PydReagent
|
from backend.validators import PydReagent, PydKit, PydReagentType, PydSubmission
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
from pprint import pformat
|
||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ class AddReagentForm(QDialog):
|
|||||||
def parse_form(self):
|
def parse_form(self):
|
||||||
return dict(name=self.name_input.currentText(),
|
return dict(name=self.name_input.currentText(),
|
||||||
lot=self.lot_input.text(),
|
lot=self.lot_input.text(),
|
||||||
exp=self.exp_input.date().toPyDate(),
|
expiry=self.exp_input.date().toPyDate(),
|
||||||
type=self.type_input.currentText())
|
type=self.type_input.currentText())
|
||||||
|
|
||||||
def update_names(self):
|
def update_names(self):
|
||||||
@@ -242,21 +243,22 @@ class KitAdder(QWidget):
|
|||||||
logger.debug(f"kit info: {pformat(info)}")
|
logger.debug(f"kit info: {pformat(info)}")
|
||||||
logger.debug(f"kit reagents: {pformat(reagents)}")
|
logger.debug(f"kit reagents: {pformat(reagents)}")
|
||||||
info['reagent_types'] = reagents
|
info['reagent_types'] = reagents
|
||||||
# for reagent in reagents:
|
|
||||||
# new_dict = {}
|
|
||||||
# for k,v in reagent.items():
|
|
||||||
# if "_" in k:
|
|
||||||
# key, sub_key = k.split("_")
|
|
||||||
# if key not in new_dict.keys():
|
|
||||||
# new_dict[key] = {}
|
|
||||||
# logger.debug(f"Adding key {key}, {sub_key} and value {v} to {new_dict}")
|
|
||||||
# new_dict[key][sub_key] = v
|
|
||||||
# else:
|
|
||||||
# new_dict[k] = v
|
|
||||||
# info['reagent_types'].append(new_dict)
|
|
||||||
logger.debug(pformat(info))
|
logger.debug(pformat(info))
|
||||||
# send to kit constructor
|
# send to kit constructor
|
||||||
result = construct_kit_from_yaml(ctx=self.ctx, kit_dict=info)
|
kit = PydKit(name=info['kit_name'])
|
||||||
|
for reagent in info['reagent_types']:
|
||||||
|
uses = {
|
||||||
|
info['used_for']:
|
||||||
|
{'sheet':reagent['sheet'],
|
||||||
|
'name':reagent['name'],
|
||||||
|
'lot':reagent['lot'],
|
||||||
|
'expiry':reagent['expiry']
|
||||||
|
}}
|
||||||
|
kit.reagent_types.append(PydReagentType(name=reagent['rtname'], eol_ext=reagent['eol'], uses=uses))
|
||||||
|
logger.debug(f"Output pyd object: {kit.__dict__}")
|
||||||
|
# result = construct_kit_from_yaml(ctx=self.ctx, kit_dict=info)
|
||||||
|
sqlobj, result = kit.toSQL(self.ctx)
|
||||||
|
sqlobj.save(ctx=self.ctx)
|
||||||
msg = AlertPop(message=result['message'], status=result['status'])
|
msg = AlertPop(message=result['message'], status=result['status'])
|
||||||
msg.exec()
|
msg.exec()
|
||||||
self.__init__(self.ctx)
|
self.__init__(self.ctx)
|
||||||
@@ -521,5 +523,149 @@ class FirstStrandPlateList(QDialog):
|
|||||||
output.append(plate.currentText())
|
output.append(plate.currentText())
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
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')}")
|
||||||
|
self.reagent = reagent
|
||||||
|
self.extraction_kit = extraction_kit
|
||||||
|
self.ctx = reagent.ctx
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
self.label = self.ReagentParsedLabel(reagent=reagent)
|
||||||
|
layout.addWidget(self.label)
|
||||||
|
self.lot = self.ReagentLot(reagent=reagent, extraction_kit=extraction_kit)
|
||||||
|
layout.addWidget(self.lot)
|
||||||
|
self.setLayout(layout)
|
||||||
|
self.setObjectName(reagent.name)
|
||||||
|
self.missing = not reagent.parsed
|
||||||
|
|
||||||
|
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 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)
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
class ReagentParsedLabel(QLabel):
|
||||||
|
|
||||||
|
def __init__(self, reagent:PydReagent):
|
||||||
|
super().__init__()
|
||||||
|
try:
|
||||||
|
check = reagent.parsed
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
self.setObjectName(f"{reagent.type}_label")
|
||||||
|
if check:
|
||||||
|
self.setText(f"Parsed {reagent.type}")
|
||||||
|
else:
|
||||||
|
self.setText(f"MISSING {reagent.type}")
|
||||||
|
|
||||||
|
class ReagentLot(QComboBox):
|
||||||
|
|
||||||
|
def __init__(self, reagent, extraction_kit:str) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.ctx = reagent.ctx
|
||||||
|
self.setEditable(True)
|
||||||
|
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)
|
||||||
|
relevant_reagents = [item.__str__() for item in lookup]
|
||||||
|
output_reg = []
|
||||||
|
for rel_reagent in relevant_reagents:
|
||||||
|
# extract strings from any sets.
|
||||||
|
if isinstance(rel_reagent, set):
|
||||||
|
for thing in rel_reagent:
|
||||||
|
output_reg.append(thing)
|
||||||
|
elif isinstance(rel_reagent, str):
|
||||||
|
output_reg.append(rel_reagent)
|
||||||
|
relevant_reagents = output_reg
|
||||||
|
# if reagent in sheet is not found insert it into the front of relevant reagents so it shows
|
||||||
|
logger.debug(f"Relevant reagents for {reagent.lot}: {relevant_reagents}")
|
||||||
|
if str(reagent.lot) not in relevant_reagents:
|
||||||
|
if check_not_nan(reagent.lot):
|
||||||
|
relevant_reagents.insert(0, str(reagent.lot))
|
||||||
|
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}")
|
||||||
|
if looked_up_reg != None:
|
||||||
|
relevant_reagents.remove(str(looked_up_reg.lot))
|
||||||
|
relevant_reagents.insert(0, str(looked_up_reg.lot))
|
||||||
|
else:
|
||||||
|
if len(relevant_reagents) > 1:
|
||||||
|
logger.debug(f"Found {reagent.lot} in relevant reagents: {relevant_reagents}. Moving to front of list.")
|
||||||
|
idx = relevant_reagents.index(str(reagent.lot))
|
||||||
|
logger.debug(f"The index we got for {reagent.lot} in {relevant_reagents} was {idx}")
|
||||||
|
moved_reag = relevant_reagents.pop(idx)
|
||||||
|
relevant_reagents.insert(0, moved_reag)
|
||||||
|
else:
|
||||||
|
logger.debug(f"Found {reagent.lot} in relevant reagents: {relevant_reagents}. But no need to move due to short list.")
|
||||||
|
logger.debug(f"New relevant reagents: {relevant_reagents}")
|
||||||
|
self.setObjectName(f"lot_{reagent.type}")
|
||||||
|
self.addItems(relevant_reagents)
|
||||||
|
|
||||||
|
class SubmissionFormWidget(QWidget):
|
||||||
|
|
||||||
|
def __init__(self, parent: QWidget) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.ignore = [None, "", "qt_spinbox_lineedit", "qt_scrollarea_viewport", "qt_scrollarea_hcontainer",
|
||||||
|
"qt_scrollarea_vcontainer", "submit_btn"
|
||||||
|
]
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -393,7 +393,6 @@ class BarcodeWindow(QDialog):
|
|||||||
painter.drawPixmap(120, -20, image)
|
painter.drawPixmap(120, -20, image)
|
||||||
painter.end()
|
painter.end()
|
||||||
|
|
||||||
|
|
||||||
class SubmissionComment(QDialog):
|
class SubmissionComment(QDialog):
|
||||||
"""
|
"""
|
||||||
a window for adding comment text to a submission
|
a window for adding comment text to a submission
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ from .custom_widgets import ReportDatePicker
|
|||||||
from .custom_widgets.misc import ImportReagent, ParsedQLabel
|
from .custom_widgets.misc import ImportReagent, ParsedQLabel
|
||||||
from .visualizations.control_charts import create_charts, construct_html
|
from .visualizations.control_charts import create_charts, construct_html
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from frontend.custom_widgets.misc import FirstStrandSalvage, FirstStrandPlateList
|
from frontend.custom_widgets.misc import FirstStrandSalvage, FirstStrandPlateList, ReagentFormWidget
|
||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
@@ -78,8 +78,7 @@ def import_submission_function(obj:QMainWindow, fname:Path|None=None) -> Tuple[Q
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return obj, dict(message= f"Problem creating pydantic model:\n\n{e}", status="critical")
|
return obj, dict(message= f"Problem creating pydantic model:\n\n{e}", status="critical")
|
||||||
# destroy any widgets from previous imports
|
# destroy any widgets from previous imports
|
||||||
for item in obj.table_widget.formlayout.parentWidget().findChildren(QWidget):
|
obj.table_widget.formwidget.clear_form()
|
||||||
item.setParent(None)
|
|
||||||
obj.current_submission_type = pyd.submission_type['value']
|
obj.current_submission_type = pyd.submission_type['value']
|
||||||
obj.current_file = pyd.filepath
|
obj.current_file = pyd.filepath
|
||||||
# Get list of fields from pydantic model.
|
# Get list of fields from pydantic model.
|
||||||
@@ -216,24 +215,26 @@ def kit_integrity_completion_function(obj:QMainWindow) -> Tuple[QMainWindow, dic
|
|||||||
logger.debug(f"Kit selector: {kit_widget}")
|
logger.debug(f"Kit selector: {kit_widget}")
|
||||||
# get current kit being used
|
# get current kit being used
|
||||||
obj.ext_kit = kit_widget.currentText()
|
obj.ext_kit = kit_widget.currentText()
|
||||||
for item in obj.reagents:
|
for reagent in obj.reagents:
|
||||||
obj.table_widget.formlayout.addWidget(ParsedQLabel({'parsed':True}, item.type, title=False, label_name=f"lot_{item.type}"))
|
# 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, exp=item.exp, name=item.name)
|
# 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)
|
# 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)
|
obj.table_widget.formlayout.addWidget(add_widget)
|
||||||
logger.debug(f"Checking integrity of {obj.ext_kit}")
|
logger.debug(f"Checking integrity of {obj.ext_kit}")
|
||||||
# see if there are any missing reagents
|
# see if there are any missing reagents
|
||||||
if len(obj.missing_reagents) > 0:
|
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")
|
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")
|
||||||
for item in obj.missing_reagents:
|
# for item in obj.missing_reagents:
|
||||||
# Add label that has parsed as False to show "MISSING" label.
|
# # 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}"))
|
# obj.table_widget.formlayout.addWidget(ParsedQLabel({'parsed':False}, item.type, title=False, label_name=f"missing_{item.type}"))
|
||||||
# Set default parameters for the empty reagent.
|
# # Set default parameters for the empty reagent.
|
||||||
reagent = dict(type=item.type, lot=None, exp=date.today(), name=None)
|
# reagent = dict(type=item.type, lot=None, expiry=date.today(), name=None)
|
||||||
# create and add widget
|
# # create and add widget
|
||||||
# add_widget = ImportReagent(ctx=obj.ctx, reagent=PydReagent(**reagent), extraction_kit=obj.ext_kit)
|
# # add_widget = ImportReagent(ctx=obj.ctx, reagent=PydReagent(**reagent), extraction_kit=obj.ext_kit)
|
||||||
add_widget = ImportReagent(ctx=obj.ctx, reagent=reagent, extraction_kit=obj.ext_kit)
|
# add_widget = ImportReagent(ctx=obj.ctx, reagent=reagent, extraction_kit=obj.ext_kit)
|
||||||
obj.table_widget.formlayout.addWidget(add_widget)
|
# obj.table_widget.formlayout.addWidget(add_widget)
|
||||||
# Add submit button to the form.
|
# Add submit button to the form.
|
||||||
submit_btn = QPushButton("Submit")
|
submit_btn = QPushButton("Submit")
|
||||||
submit_btn.setObjectName("submit_btn")
|
submit_btn.setObjectName("submit_btn")
|
||||||
@@ -264,34 +265,34 @@ def submit_new_sample_function(obj:QMainWindow) -> Tuple[QMainWindow, dict]:
|
|||||||
# info, reagents = obj.table_widget.formwidget.parse_form()
|
# info, reagents = obj.table_widget.formwidget.parse_form()
|
||||||
submission: PydSubmission = obj.table_widget.formwidget.parse_form()
|
submission: PydSubmission = obj.table_widget.formwidget.parse_form()
|
||||||
logger.debug(f"Submission: {pprint.pformat(submission)}")
|
logger.debug(f"Submission: {pprint.pformat(submission)}")
|
||||||
parsed_reagents = []
|
# parsed_reagents = []
|
||||||
# compare reagents in form to reagent database
|
# compare reagents in form to reagent database
|
||||||
for reagent in submission.reagents:
|
# for reagent in submission.reagents:
|
||||||
# Lookup any existing reagent of this type with this lot number
|
# # 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)
|
# wanted_reagent = lookup_reagents(ctx=obj.ctx, lot_number=reagent.lot, reagent_type=reagent.name)
|
||||||
logger.debug(f"Looked up reagent: {wanted_reagent}")
|
# logger.debug(f"Looked up reagent: {wanted_reagent}")
|
||||||
# if reagent not found offer to add to database
|
# # if reagent not found offer to add to database
|
||||||
if wanted_reagent == None:
|
# if wanted_reagent == None:
|
||||||
# r_lot = reagent[reagent]
|
# # 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?")
|
# 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():
|
# if dlg.exec():
|
||||||
logger.debug(f"Looking through {pprint.pformat(obj.reagents)} for reagent {reagent.name}")
|
# logger.debug(f"Looking through {pprint.pformat(obj.reagents)} for reagent {reagent.name}")
|
||||||
try:
|
# try:
|
||||||
picked_reagent = [item for item in obj.reagents if item.type == reagent.name][0]
|
# picked_reagent = [item for item in obj.reagents if item.type == reagent.name][0]
|
||||||
except IndexError:
|
# except IndexError:
|
||||||
logger.error(f"Couldn't find {reagent.name} in obj.reagents. Checking missing reagents {pprint.pformat(obj.missing_reagents)}")
|
# 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]
|
# 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}")
|
# logger.debug(f"checking reagent: {reagent.name} in obj.reagents. Result: {picked_reagent}")
|
||||||
expiry_date = picked_reagent.exp
|
# 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)
|
# wanted_reagent = obj.add_reagent(reagent_lot=reagent.lot, reagent_type=reagent.name.replace("lot_", ""), expiry=expiry_date, name=picked_reagent.name)
|
||||||
else:
|
# else:
|
||||||
# In this case we will have an empty reagent and the submission will fail kit integrity check
|
# # In this case we will have an empty reagent and the submission will fail kit integrity check
|
||||||
logger.debug("Will not add reagent.")
|
# logger.debug("Will not add reagent.")
|
||||||
return obj, dict(message="Failed integrity check", status="critical")
|
# return obj, dict(message="Failed integrity check", status="critical")
|
||||||
# Append the PydReagent object o be added to the submission
|
# # Append the PydReagent object o be added to the submission
|
||||||
parsed_reagents.append(reagent)
|
# parsed_reagents.append(reagent)
|
||||||
# move samples into preliminary submission dict
|
# # move samples into preliminary submission dict
|
||||||
submission.reagents = parsed_reagents
|
# submission.reagents = parsed_reagents
|
||||||
# submission.uploaded_by = getuser()
|
# submission.uploaded_by = getuser()
|
||||||
# construct submission object
|
# construct submission object
|
||||||
# logger.debug(f"Here is the info_dict: {pprint.pformat(info)}")
|
# logger.debug(f"Here is the info_dict: {pprint.pformat(info)}")
|
||||||
@@ -1020,16 +1021,17 @@ def scrape_reagents(obj:QMainWindow, extraction_kit:str) -> Tuple[QMainWindow, d
|
|||||||
obj.reagents = []
|
obj.reagents = []
|
||||||
obj.missing_reagents = []
|
obj.missing_reagents = []
|
||||||
# Remove previous reagent widgets
|
# 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(QWidget) if item.objectName().startswith("lot_") or item.objectName().startswith("missing_")]
|
||||||
[item.setParent(None) for item in obj.table_widget.formlayout.parentWidget().findChildren(QPushButton)]
|
# [item.setParent(None) for item in obj.table_widget.formlayout.parentWidget().findChildren(QPushButton)]
|
||||||
reagents = obj.prsr.parse_reagents(extraction_kit=extraction_kit)
|
reagents = obj.prsr.parse_reagents(extraction_kit=extraction_kit)
|
||||||
logger.debug(f"Got reagents: {reagents}")
|
logger.debug(f"Got reagents: {reagents}")
|
||||||
for reagent in obj.prsr.sub['reagents']:
|
# for reagent in obj.prsr.sub['reagents']:
|
||||||
# create label
|
# # create label
|
||||||
if reagent['parsed']:
|
# if reagent.parsed:
|
||||||
obj.reagents.append(reagent['value'])
|
# obj.reagents.append(reagent)
|
||||||
else:
|
# else:
|
||||||
obj.missing_reagents.append(reagent['value'])
|
# obj.missing_reagents.append(reagent)
|
||||||
|
obj.reagents = obj.prsr.sub['reagents']
|
||||||
logger.debug(f"Imported reagents: {obj.reagents}")
|
logger.debug(f"Imported reagents: {obj.reagents}")
|
||||||
logger.debug(f"Missing reagents: {obj.missing_reagents}")
|
logger.debug(f"Missing reagents: {obj.missing_reagents}")
|
||||||
return obj, None
|
return obj, None
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ def check_not_nan(cell_contents) -> bool:
|
|||||||
cell_contents = np.nan
|
cell_contents = np.nan
|
||||||
if cell_contents == None:
|
if cell_contents == None:
|
||||||
cell_contents = np.nan
|
cell_contents = np.nan
|
||||||
|
if str(cell_contents).lower() == "none":
|
||||||
|
cell_contents = np.nan
|
||||||
try:
|
try:
|
||||||
if pd.isnull(cell_contents):
|
if pd.isnull(cell_contents):
|
||||||
cell_contents = np.nan
|
cell_contents = np.nan
|
||||||
|
|||||||
Reference in New Issue
Block a user