moved frontend function check_not_nan to tools
This commit is contained in:
@@ -55,8 +55,8 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne
|
|||||||
# are written from script.py.mako
|
# are written from script.py.mako
|
||||||
# output_encoding = utf-8
|
# output_encoding = utf-8
|
||||||
|
|
||||||
sqlalchemy.url = sqlite:///L:\Robotics Laboratory Support\Submissions\submissions.db
|
; sqlalchemy.url = sqlite:///L:\Robotics Laboratory Support\Submissions\submissions.db
|
||||||
; sqlalchemy.url = sqlite:///C:\Users\lwark\Documents\Archives\DB_backups\submissions-20230130.db
|
sqlalchemy.url = sqlite:///C:\Users\lwark\Documents\Archives\DB_backups\submissions-20230213.db
|
||||||
|
|
||||||
|
|
||||||
[post_write_hooks]
|
[post_write_hooks]
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from alembic import context
|
|||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
sys.path.append(Path(__file__).parents[1].joinpath("src").resolve().__str__())
|
sys.path.append(Path(__file__).parents[1].joinpath("src").resolve().__str__())
|
||||||
|
sys.path.append(Path(__file__).parents[1].joinpath("src", "submissions").resolve().__str__())
|
||||||
print(sys.path)
|
print(sys.path)
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# __init__.py
|
# __init__.py
|
||||||
|
|
||||||
# Version of the realpython-reader package
|
# Version of the realpython-reader package
|
||||||
__version__ = "1.2.3"
|
__version__ = "1.3.0"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import json
|
|||||||
# from dateutil.relativedelta import relativedelta
|
# from dateutil.relativedelta import relativedelta
|
||||||
from getpass import getuser
|
from getpass import getuser
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from tools import check_not_nan
|
||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
@@ -101,8 +102,13 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
|||||||
# convert submission type into model name
|
# convert submission type into model name
|
||||||
query = info_dict['submission_type'].replace(" ", "")
|
query = info_dict['submission_type'].replace(" ", "")
|
||||||
# check database for existing object
|
# check database for existing object
|
||||||
|
if info_dict["rsl_plate_num"] == 'nan' or info_dict["rsl_plate_num"] == None or not check_not_nan(info_dict["rsl_plate_num"]):
|
||||||
|
code = 2
|
||||||
|
instance = None
|
||||||
|
msg = "A proper RSL plate number is required."
|
||||||
|
return instance, {'code': 2, 'message': "A proper RSL plate number is required."}
|
||||||
instance = ctx['database_session'].query(models.BasicSubmission).filter(models.BasicSubmission.rsl_plate_num==info_dict['rsl_plate_num']).first()
|
instance = ctx['database_session'].query(models.BasicSubmission).filter(models.BasicSubmission.rsl_plate_num==info_dict['rsl_plate_num']).first()
|
||||||
msg = "This submission already exists.\nWould you like to overwrite?"
|
|
||||||
# get model based on submission type converted above
|
# get model based on submission type converted above
|
||||||
logger.debug(f"Looking at models for submission type: {query}")
|
logger.debug(f"Looking at models for submission type: {query}")
|
||||||
model = getattr(models, query)
|
model = getattr(models, query)
|
||||||
@@ -113,6 +119,10 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
|||||||
instance = model()
|
instance = model()
|
||||||
logger.debug(f"Submission doesn't exist yet, creating new instance: {instance}")
|
logger.debug(f"Submission doesn't exist yet, creating new instance: {instance}")
|
||||||
msg = None
|
msg = None
|
||||||
|
code =0
|
||||||
|
else:
|
||||||
|
code = 1
|
||||||
|
msg = "This submission already exists.\nWould you like to overwrite?"
|
||||||
for item in info_dict:
|
for item in info_dict:
|
||||||
logger.debug(f"Setting {item} to {info_dict[item]}")
|
logger.debug(f"Setting {item} to {info_dict[item]}")
|
||||||
# set fields based on keys in dictionary
|
# set fields based on keys in dictionary
|
||||||
@@ -151,9 +161,14 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
|||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError):
|
||||||
logger.debug(f"Looks like that kit doesn't have cost breakdown yet, using full plate cost.")
|
logger.debug(f"Looks like that kit doesn't have cost breakdown yet, using full plate cost.")
|
||||||
instance.run_cost = instance.extraction_kit.cost_per_run
|
instance.run_cost = instance.extraction_kit.cost_per_run
|
||||||
|
# We need to make sure there's a proper rsl plate number
|
||||||
|
|
||||||
|
try:
|
||||||
logger.debug(f"Constructed instance: {instance.to_string()}")
|
logger.debug(f"Constructed instance: {instance.to_string()}")
|
||||||
|
except AttributeError as e:
|
||||||
|
logger.debug(f"Something went wrong constructing instance {info_dict['rsl_plate_num']}: {e}")
|
||||||
logger.debug(msg)
|
logger.debug(msg)
|
||||||
return instance, {'message':msg}
|
return instance, {'code':code, 'message':msg}
|
||||||
|
|
||||||
|
|
||||||
def construct_reagent(ctx:dict, info_dict:dict) -> models.Reagent:
|
def construct_reagent(ctx:dict, info_dict:dict) -> models.Reagent:
|
||||||
@@ -244,7 +259,7 @@ def lookup_kittype_by_use(ctx:dict, used_by:str) -> list[models.KitType]:
|
|||||||
Returns:
|
Returns:
|
||||||
list[models.KitType]: list of kittypes that have that sample type in their uses
|
list[models.KitType]: list of kittypes that have that sample type in their uses
|
||||||
"""
|
"""
|
||||||
return ctx['database_session'].query(models.KitType).filter(models.KitType.used_for.contains(used_by))
|
return ctx['database_session'].query(models.KitType).filter(models.KitType.used_for.contains(used_by)).all()
|
||||||
|
|
||||||
def lookup_kittype_by_name(ctx:dict, name:str) -> models.KitType:
|
def lookup_kittype_by_name(ctx:dict, name:str) -> models.KitType:
|
||||||
"""
|
"""
|
||||||
@@ -278,7 +293,7 @@ def lookup_regent_by_type_name(ctx:dict, type_name:str) -> list[models.Reagent]:
|
|||||||
|
|
||||||
def lookup_regent_by_type_name_and_kit_name(ctx:dict, type_name:str, kit_name:str) -> list[models.Reagent]:
|
def lookup_regent_by_type_name_and_kit_name(ctx:dict, type_name:str, kit_name:str) -> list[models.Reagent]:
|
||||||
"""
|
"""
|
||||||
Lookup reagents by their type name and kits they belong to (Broken)
|
Lookup reagents by their type name and kits they belong to (Broken... maybe cursed, I'm not sure.)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ctx (dict): settings pass by gui
|
ctx (dict): settings pass by gui
|
||||||
@@ -292,10 +307,6 @@ def lookup_regent_by_type_name_and_kit_name(ctx:dict, type_name:str, kit_name:st
|
|||||||
# Hang on, this is going to be a long one.
|
# Hang on, this is going to be a long one.
|
||||||
# by_type = ctx['database_session'].query(models.Reagent).join(models.Reagent.type, aliased=True).filter(models.ReagentType.name.endswith(type_name)).all()
|
# by_type = ctx['database_session'].query(models.Reagent).join(models.Reagent.type, aliased=True).filter(models.ReagentType.name.endswith(type_name)).all()
|
||||||
rt_types = ctx['database_session'].query(models.ReagentType).filter(models.ReagentType.name.endswith(type_name))
|
rt_types = ctx['database_session'].query(models.ReagentType).filter(models.ReagentType.name.endswith(type_name))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# add filter for kit name... which I can not get to work.
|
# add filter for kit name... which I can not get to work.
|
||||||
# add_in = by_type.join(models.ReagentType.kits).filter(models.KitType.name==kit_name)
|
# add_in = by_type.join(models.ReagentType.kits).filter(models.KitType.name==kit_name)
|
||||||
try:
|
try:
|
||||||
@@ -315,7 +326,7 @@ def lookup_regent_by_type_name_and_kit_name(ctx:dict, type_name:str, kit_name:st
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def lookup_all_submissions_by_type(ctx:dict, type:str|None=None) -> list[models.BasicSubmission]:
|
def lookup_all_submissions_by_type(ctx:dict, sub_type:str|None=None) -> list[models.BasicSubmission]:
|
||||||
"""
|
"""
|
||||||
Get all submissions, filtering by type if given
|
Get all submissions, filtering by type if given
|
||||||
|
|
||||||
@@ -326,10 +337,10 @@ def lookup_all_submissions_by_type(ctx:dict, type:str|None=None) -> list[models.
|
|||||||
Returns:
|
Returns:
|
||||||
_type_: list of retrieved submissions
|
_type_: list of retrieved submissions
|
||||||
"""
|
"""
|
||||||
if type == None:
|
if sub_type == None:
|
||||||
subs = ctx['database_session'].query(models.BasicSubmission).all()
|
subs = ctx['database_session'].query(models.BasicSubmission).all()
|
||||||
else:
|
else:
|
||||||
subs = ctx['database_session'].query(models.BasicSubmission).filter(models.BasicSubmission.submission_type==type.lower().replace(" ", "_")).all()
|
subs = ctx['database_session'].query(models.BasicSubmission).filter(models.BasicSubmission.submission_type==sub_type.lower().replace(" ", "_")).all()
|
||||||
return subs
|
return subs
|
||||||
|
|
||||||
def lookup_all_orgs(ctx:dict) -> list[models.Organization]:
|
def lookup_all_orgs(ctx:dict) -> list[models.Organization]:
|
||||||
@@ -358,7 +369,7 @@ def lookup_org_by_name(ctx:dict, name:str|None) -> models.Organization:
|
|||||||
logger.debug(f"Querying organization: {name}")
|
logger.debug(f"Querying organization: {name}")
|
||||||
return ctx['database_session'].query(models.Organization).filter(models.Organization.name==name).first()
|
return ctx['database_session'].query(models.Organization).filter(models.Organization.name==name).first()
|
||||||
|
|
||||||
def submissions_to_df(ctx:dict, type:str|None=None) -> pd.DataFrame:
|
def submissions_to_df(ctx:dict, sub_type:str|None=None) -> pd.DataFrame:
|
||||||
"""
|
"""
|
||||||
Convert submissions looked up by type to dataframe
|
Convert submissions looked up by type to dataframe
|
||||||
|
|
||||||
@@ -369,9 +380,9 @@ def submissions_to_df(ctx:dict, type:str|None=None) -> pd.DataFrame:
|
|||||||
Returns:
|
Returns:
|
||||||
pd.DataFrame: dataframe constructed from retrieved submissions
|
pd.DataFrame: dataframe constructed from retrieved submissions
|
||||||
"""
|
"""
|
||||||
logger.debug(f"Type: {type}")
|
logger.debug(f"Type: {sub_type}")
|
||||||
# pass to lookup function
|
# pass to lookup function
|
||||||
subs = [item.to_dict() for item in lookup_all_submissions_by_type(ctx=ctx, type=type)]
|
subs = [item.to_dict() for item in lookup_all_submissions_by_type(ctx=ctx, sub_type=sub_type)]
|
||||||
df = pd.DataFrame.from_records(subs)
|
df = pd.DataFrame.from_records(subs)
|
||||||
# logger.debug(f"Pre: {df['Technician']}")
|
# logger.debug(f"Pre: {df['Technician']}")
|
||||||
try:
|
try:
|
||||||
@@ -435,13 +446,16 @@ def get_all_Control_Types_names(ctx:dict) -> list[models.ControlType]:
|
|||||||
return conTypes
|
return conTypes
|
||||||
|
|
||||||
|
|
||||||
def create_kit_from_yaml(ctx:dict, exp:dict) -> None:
|
def create_kit_from_yaml(ctx:dict, exp:dict) -> dict:
|
||||||
"""
|
"""
|
||||||
Create and store a new kit in the database based on a .yml file
|
Create and store a new kit in the database based on a .yml file
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ctx (dict): Context dictionary passed down from frontend
|
ctx (dict): Context dictionary passed down from frontend
|
||||||
exp (dict): Experiment dictionary created from yaml file
|
exp (dict): Experiment dictionary created from yaml file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: a dictionary containing results of db addition
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
power_users = ctx['power_users']
|
power_users = ctx['power_users']
|
||||||
@@ -474,6 +488,44 @@ def create_kit_from_yaml(ctx:dict, exp:dict) -> None:
|
|||||||
ctx['database_session'].commit()
|
ctx['database_session'].commit()
|
||||||
return {'code':0, 'message':'Kit has been added'}
|
return {'code':0, 'message':'Kit has been added'}
|
||||||
|
|
||||||
|
def create_org_from_yaml(ctx:dict, org:dict) -> dict:
|
||||||
|
"""
|
||||||
|
Create and store a new organization based on a .yml file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ctx (dict): Context dictionary passed down from frontend
|
||||||
|
org (dict): Dictionary containing organization info.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: dictionary containing results of db addition
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
power_users = ctx['power_users']
|
||||||
|
except KeyError:
|
||||||
|
logger.debug("This user does not have permission to add kits.")
|
||||||
|
return {'code':1,'message':"This user does not have permission to add organizations."}
|
||||||
|
logger.debug(f"Adding organization for user: {getuser()}")
|
||||||
|
if getuser() not in power_users:
|
||||||
|
logger.debug(f"{getuser()} does not have permission to add kits.")
|
||||||
|
return {'code':1, 'message':"This user does not have permission to add organizations."}
|
||||||
|
for client in org:
|
||||||
|
cli_org = models.Organization(name=client.replace(" ", "_").lower(), cost_centre=org[client]['cost centre'])
|
||||||
|
for contact in org[client]['contacts']:
|
||||||
|
cont_name = list(contact.keys())[0]
|
||||||
|
look_up = ctx['database_session'].query(models.Contact).filter(models.Contact.name==cont_name).first()
|
||||||
|
if look_up == None:
|
||||||
|
cli_cont = models.Contact(name=cont_name, phone=contact[cont_name]['phone'], email=contact[cont_name]['email'], organization=[cli_org])
|
||||||
|
else:
|
||||||
|
cli_cont = look_up
|
||||||
|
cli_cont.organization.append(cli_org)
|
||||||
|
# cli_org.contacts.append(cli_cont)
|
||||||
|
# cli_org.contact_ids.append_foreign_key(cli_cont.id)
|
||||||
|
ctx['database_session'].add(cli_cont)
|
||||||
|
logger.debug(cli_cont.__dict__)
|
||||||
|
ctx['database_session'].add(cli_org)
|
||||||
|
ctx["database_session"].commit()
|
||||||
|
return {"code":0, "message":"Organization has been added."}
|
||||||
|
|
||||||
|
|
||||||
def lookup_all_sample_types(ctx:dict) -> list[str]:
|
def lookup_all_sample_types(ctx:dict) -> list[str]:
|
||||||
"""
|
"""
|
||||||
@@ -511,7 +563,7 @@ def get_all_available_modes(ctx:dict) -> list[str]:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_controls_by_type(ctx:dict, con_type:str, start_date:date|None=None, end_date:date|None=None) -> list:
|
def get_all_controls_by_type(ctx:dict, con_type:str, start_date:date|None=None, end_date:date|None=None) -> list[models.Control]:
|
||||||
"""
|
"""
|
||||||
Returns a list of control objects that are instances of the input controltype.
|
Returns a list of control objects that are instances of the input controltype.
|
||||||
|
|
||||||
@@ -571,4 +623,4 @@ def lookup_submission_by_rsl_num(ctx:dict, rsl_num:str):
|
|||||||
|
|
||||||
|
|
||||||
def lookup_submissions_using_reagent(ctx:dict, reagent:models.Reagent) -> list[models.BasicSubmission]:
|
def lookup_submissions_using_reagent(ctx:dict, reagent:models.Reagent) -> list[models.BasicSubmission]:
|
||||||
return ctx['database_session'].query(models.BasicSubmission).join(reagents_submissions).filter(reagents_submissions.c.reagent_id==reagent.id)
|
return ctx['database_session'].query(models.BasicSubmission).join(reagents_submissions).filter(reagents_submissions.c.reagent_id==reagent.id).all()
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
from ..models import *
|
# from ..models import *
|
||||||
import logging
|
# import logging
|
||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
# logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
def check_kit_integrity(sub:BasicSubmission):
|
# def check_kit_integrity(sub:BasicSubmission):
|
||||||
ext_kit_rtypes = [reagenttype.name for reagenttype in sub.extraction_kit.reagent_types]
|
# ext_kit_rtypes = [reagenttype.name for reagenttype in sub.extraction_kit.reagent_types]
|
||||||
logger.debug(f"Kit reagents: {ext_kit_rtypes}")
|
# logger.debug(f"Kit reagents: {ext_kit_rtypes}")
|
||||||
reagenttypes = [reagent.type.name for reagent in sub.reagents]
|
# reagenttypes = [reagent.type.name for reagent in sub.reagents]
|
||||||
logger.debug(f"Submission reagents: {reagenttypes}")
|
# logger.debug(f"Submission reagents: {reagenttypes}")
|
||||||
check = set(ext_kit_rtypes) == set(reagenttypes)
|
# check = set(ext_kit_rtypes) == set(reagenttypes)
|
||||||
logger.debug(f"Checking if reagents match kit contents: {check}")
|
# logger.debug(f"Checking if reagents match kit contents: {check}")
|
||||||
common = list(set(ext_kit_rtypes).intersection(reagenttypes))
|
# common = list(set(ext_kit_rtypes).intersection(reagenttypes))
|
||||||
logger.debug(f"common reagents types: {common}")
|
# logger.debug(f"common reagents types: {common}")
|
||||||
if check:
|
# if check:
|
||||||
result = None
|
# result = None
|
||||||
else:
|
# else:
|
||||||
result = {'message' : f"Couldn't verify reagents match listed kit components.\n\nIt looks like you are missing: {[x.upper for x in ext_kit_rtypes if x not in common]}\n\nAlternatively, you may have set the wrong extraction kit."}
|
# result = {'message' : f"Couldn't verify reagents match listed kit components.\n\nIt looks like you are missing: {[x.upper for x in ext_kit_rtypes if x not in common]}\n\nAlternatively, you may have set the wrong extraction kit."}
|
||||||
return result
|
# return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class Contact(Base):
|
|||||||
"""
|
"""
|
||||||
__tablename__ = "_contacts"
|
__tablename__ = "_contacts"
|
||||||
|
|
||||||
id = id = Column(INTEGER, primary_key=True) #: primary key
|
id = Column(INTEGER, primary_key=True) #: primary key
|
||||||
name = Column(String(64)) #: contact name
|
name = Column(String(64)) #: contact name
|
||||||
email = Column(String(64)) #: contact email
|
email = Column(String(64)) #: contact email
|
||||||
phone = Column(String(32)) #: contact phone number
|
phone = Column(String(32)) #: contact phone number
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from . import Base
|
from . import Base
|
||||||
from sqlalchemy import Column, String, TIMESTAMP, text, JSON, INTEGER, ForeignKey, FLOAT, BOOLEAN
|
from sqlalchemy import Column, String, TIMESTAMP, INTEGER, ForeignKey, FLOAT, BOOLEAN
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class BasicSubmission(Base):
|
|||||||
__tablename__ = "_submissions"
|
__tablename__ = "_submissions"
|
||||||
|
|
||||||
id = Column(INTEGER, primary_key=True) #: primary key
|
id = Column(INTEGER, primary_key=True) #: primary key
|
||||||
rsl_plate_num = Column(String(32), unique=True) #: RSL name (e.g. RSL-22-0012)
|
rsl_plate_num = Column(String(32), unique=True, nullable=False) #: RSL name (e.g. RSL-22-0012)
|
||||||
submitter_plate_num = Column(String(127), unique=True) #: The number given to the submission by the submitting lab
|
submitter_plate_num = Column(String(127), unique=True) #: The number given to the submission by the submitting lab
|
||||||
submitted_date = Column(TIMESTAMP) #: Date submission received
|
submitted_date = Column(TIMESTAMP) #: Date submission received
|
||||||
submitting_lab = relationship("Organization", back_populates="submissions") #: client org
|
submitting_lab = relationship("Organization", back_populates="submissions") #: client org
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from backend.db.models.samples import WWSample, BCSample
|
from backend.db.models import WWSample, BCSample
|
||||||
import logging
|
import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import re
|
import re
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from datetime import date
|
from datetime import date
|
||||||
import uuid
|
import uuid
|
||||||
from frontend.functions import check_not_nan
|
from tools import check_not_nan
|
||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ class SheetParser(object):
|
|||||||
"""
|
"""
|
||||||
object to pull and contain data from excel file
|
object to pull and contain data from excel file
|
||||||
"""
|
"""
|
||||||
def __init__(self, filepath:Path|None = None, **kwargs) -> None:
|
def __init__(self, filepath:Path|None = None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
filepath (Path | None, optional): file path to excel sheet. Defaults to None.
|
filepath (Path | None, optional): file path to excel sheet. Defaults to None.
|
||||||
@@ -77,12 +77,12 @@ class SheetParser(object):
|
|||||||
"""
|
"""
|
||||||
submission_info = self.xl.parse(sheet_name=sheet_name, dtype=object)
|
submission_info = self.xl.parse(sheet_name=sheet_name, dtype=object)
|
||||||
|
|
||||||
self.sub['submitter_plate_num'] = submission_info.iloc[0][1] #if pd.isnull(submission_info.iloc[0][1]) else string_formatter(submission_info.iloc[0][1])
|
self.sub['submitter_plate_num'] = submission_info.iloc[0][1]
|
||||||
self.sub['rsl_plate_num'] = submission_info.iloc[10][1] #if pd.isnull(submission_info.iloc[10][1]) else string_formatter(submission_info.iloc[10][1])
|
self.sub['rsl_plate_num'] = submission_info.iloc[10][1]
|
||||||
self.sub['submitted_date'] = submission_info.iloc[1][1] #if pd.isnull(submission_info.iloc[1][1]) else submission_info.iloc[1][1].date()#.strftime("%Y-%m-%d")
|
self.sub['submitted_date'] = submission_info.iloc[1][1]
|
||||||
self.sub['submitting_lab'] = submission_info.iloc[0][3] #if pd.isnull(submission_info.iloc[0][3]) else string_formatter(submission_info.iloc[0][3])
|
self.sub['submitting_lab'] = submission_info.iloc[0][3]
|
||||||
self.sub['sample_count'] = submission_info.iloc[2][3] #if pd.isnull(submission_info.iloc[2][3]) else string_formatter(submission_info.iloc[2][3])
|
self.sub['sample_count'] = submission_info.iloc[2][3]
|
||||||
self.sub['extraction_kit'] = submission_info.iloc[3][3] #if #pd.isnull(submission_info.iloc[3][3]) else string_formatter(submission_info.iloc[3][3])
|
self.sub['extraction_kit'] = submission_info.iloc[3][3]
|
||||||
|
|
||||||
return submission_info
|
return submission_info
|
||||||
|
|
||||||
@@ -93,6 +93,12 @@ class SheetParser(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def _parse_reagents(df:pd.DataFrame) -> None:
|
def _parse_reagents(df:pd.DataFrame) -> None:
|
||||||
|
"""
|
||||||
|
Pulls reagents from the bacterial sub-dataframe
|
||||||
|
|
||||||
|
Args:
|
||||||
|
df (pd.DataFrame): input sub dataframe
|
||||||
|
"""
|
||||||
for ii, row in df.iterrows():
|
for ii, row in df.iterrows():
|
||||||
# skip positive control
|
# skip positive control
|
||||||
if ii == 11:
|
if ii == 11:
|
||||||
@@ -119,16 +125,15 @@ class SheetParser(object):
|
|||||||
# self.sub[f"lot_{reagent_type}"] = output_var
|
# self.sub[f"lot_{reagent_type}"] = output_var
|
||||||
# update 2023-02-10 to above allowing generation of expiry date in adding reagent to db.
|
# update 2023-02-10 to above allowing generation of expiry date in adding reagent to db.
|
||||||
logger.debug(f"Expiry date for imported reagent: {row[3]}")
|
logger.debug(f"Expiry date for imported reagent: {row[3]}")
|
||||||
try:
|
# try:
|
||||||
check = not np.isnan(row[3])
|
# check = not np.isnan(row[3])
|
||||||
except TypeError:
|
# except TypeError:
|
||||||
check = True
|
# check = True
|
||||||
if check:
|
if check_not_nan(row[3]):
|
||||||
expiry = row[3].date()
|
expiry = row[3].date()
|
||||||
else:
|
else:
|
||||||
expiry = date.today()
|
expiry = date.today()
|
||||||
self.sub[f"lot_{reagent_type}"] = {'lot':output_var, 'exp':expiry}
|
self.sub[f"lot_{reagent_type}"] = {'lot':output_var, 'exp':expiry}
|
||||||
|
|
||||||
submission_info = self._parse_generic("Sample List")
|
submission_info = self._parse_generic("Sample List")
|
||||||
# iloc is [row][column] and the first row is set as header row so -2
|
# iloc is [row][column] and the first row is set as header row so -2
|
||||||
tech = str(submission_info.iloc[11][1])
|
tech = str(submission_info.iloc[11][1])
|
||||||
@@ -161,32 +166,38 @@ class SheetParser(object):
|
|||||||
self.sub['samples'] = sample_parse()
|
self.sub['samples'] = sample_parse()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_wastewater(self) -> None:
|
def _parse_wastewater(self) -> None:
|
||||||
"""
|
"""
|
||||||
pulls info specific to wastewater sample type
|
pulls info specific to wastewater sample type
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _parse_reagents(df:pd.DataFrame) -> None:
|
def _parse_reagents(df:pd.DataFrame) -> None:
|
||||||
logger.debug(df)
|
"""
|
||||||
|
Pulls reagents from the bacterial sub-dataframe
|
||||||
|
|
||||||
|
Args:
|
||||||
|
df (pd.DataFrame): input sub dataframe
|
||||||
|
"""
|
||||||
|
# logger.debug(df)
|
||||||
for ii, row in df.iterrows():
|
for ii, row in df.iterrows():
|
||||||
try:
|
# try:
|
||||||
check = not np.isnan(row[5])
|
# check = not np.isnan(row[5])
|
||||||
except TypeError:
|
# except TypeError:
|
||||||
check = True
|
# check = True
|
||||||
if not isinstance(row[5], float) and check:
|
if not isinstance(row[5], float) and check_not_nan(row[5]):
|
||||||
# must be prefixed with 'lot_' to be recognized by gui
|
# must be prefixed with 'lot_' to be recognized by gui
|
||||||
|
# regex below will remove 80% from 80% ethanol in the Wastewater kit.
|
||||||
output_key = re.sub(r"\d{1,3}%", "", row[0].lower().strip().replace(' ', '_'))
|
output_key = re.sub(r"\d{1,3}%", "", row[0].lower().strip().replace(' ', '_'))
|
||||||
try:
|
try:
|
||||||
output_var = row[5].upper()
|
output_var = row[5].upper()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
logger.debug(f"Couldn't upperize {row[2]}, must be a number")
|
logger.debug(f"Couldn't upperize {row[5]}, must be a number")
|
||||||
output_var = row[5]
|
output_var = row[5]
|
||||||
self.sub[f"lot_{output_key}"] = output_var
|
if check_not_nan(row[7]):
|
||||||
|
expiry = row[7].date()
|
||||||
# submission_info = self.xl.parse("WW Submissions (ENTER HERE)")
|
else:
|
||||||
|
expiry = date.today()
|
||||||
|
self.sub[f"lot_{output_key}"] = {'lot':output_var, 'exp':expiry}
|
||||||
submission_info = self._parse_generic("WW Submissions (ENTER HERE)")
|
submission_info = self._parse_generic("WW Submissions (ENTER HERE)")
|
||||||
enrichment_info = self.xl.parse("Enrichment Worksheet", dtype=object)
|
enrichment_info = self.xl.parse("Enrichment Worksheet", dtype=object)
|
||||||
enr_reagent_range = enrichment_info.iloc[0:4, 9:20]
|
enr_reagent_range = enrichment_info.iloc[0:4, 9:20]
|
||||||
@@ -214,18 +225,12 @@ class SheetParser(object):
|
|||||||
# self.sub['lot_pre_mix_2'] = qprc_info.iloc[2][14] #if pd.isnull(qprc_info.iloc[2][14]) else string_formatter(qprc_info.iloc[2][14])
|
# self.sub['lot_pre_mix_2'] = qprc_info.iloc[2][14] #if pd.isnull(qprc_info.iloc[2][14]) else string_formatter(qprc_info.iloc[2][14])
|
||||||
# self.sub['lot_positive_control'] = qprc_info.iloc[3][14] #if pd.isnull(qprc_info.iloc[3][14]) else string_formatter(qprc_info.iloc[3][14])
|
# self.sub['lot_positive_control'] = qprc_info.iloc[3][14] #if pd.isnull(qprc_info.iloc[3][14]) else string_formatter(qprc_info.iloc[3][14])
|
||||||
# self.sub['lot_ddh2o'] = qprc_info.iloc[4][14] #if pd.isnull(qprc_info.iloc[4][14]) else string_formatter(qprc_info.iloc[4][14])
|
# self.sub['lot_ddh2o'] = qprc_info.iloc[4][14] #if pd.isnull(qprc_info.iloc[4][14]) else string_formatter(qprc_info.iloc[4][14])
|
||||||
# gt individual sample info
|
# get individual sample info
|
||||||
sample_parser = SampleParser(submission_info.iloc[16:40])
|
sample_parser = SampleParser(submission_info.iloc[16:40])
|
||||||
sample_parse = getattr(sample_parser, f"parse_{self.sub['submission_type'].lower()}_samples")
|
sample_parse = getattr(sample_parser, f"parse_{self.sub['submission_type'].lower()}_samples")
|
||||||
self.sub['samples'] = sample_parse()
|
self.sub['samples'] = sample_parse()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SampleParser(object):
|
class SampleParser(object):
|
||||||
"""
|
"""
|
||||||
object to pull data for samples in excel sheet and construct individual sample objects
|
object to pull data for samples in excel sheet and construct individual sample objects
|
||||||
@@ -242,6 +247,7 @@ class SampleParser(object):
|
|||||||
Returns:
|
Returns:
|
||||||
list[BCSample]: list of sample objects
|
list[BCSample]: list of sample objects
|
||||||
"""
|
"""
|
||||||
|
# logger.debug(f"Samples: {self.samples}")
|
||||||
new_list = []
|
new_list = []
|
||||||
for sample in self.samples:
|
for sample in self.samples:
|
||||||
new = BCSample()
|
new = BCSample()
|
||||||
@@ -297,13 +303,3 @@ class SampleParser(object):
|
|||||||
new.well_number = sample['Unnamed: 1']
|
new.well_number = sample['Unnamed: 1']
|
||||||
new_list.append(new)
|
new_list.append(new)
|
||||||
return new_list
|
return new_list
|
||||||
|
|
||||||
|
|
||||||
# def string_formatter(input):
|
|
||||||
# logger.debug(f"{input} : {type(input)}")
|
|
||||||
# match input:
|
|
||||||
# case int() | float() | np.float64:
|
|
||||||
# return "{:0.0f}".format(input)
|
|
||||||
# case _:
|
|
||||||
# return input
|
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
|
# set path of templates depending on pyinstaller/raw python
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
loader_path = Path(sys._MEIPASS).joinpath("files", "templates")
|
loader_path = Path(sys._MEIPASS).joinpath("files", "templates")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -19,21 +19,23 @@ from xhtml2pdf import pisa
|
|||||||
# import plotly.express as px
|
# import plotly.express as px
|
||||||
import yaml
|
import yaml
|
||||||
import pprint
|
import pprint
|
||||||
import numpy as np
|
|
||||||
from backend.excel.parser import SheetParser
|
from backend.excel.parser import SheetParser
|
||||||
from backend.excel.reports import convert_control_by_mode, convert_data_list_to_df
|
from backend.excel.reports import convert_control_by_mode, convert_data_list_to_df
|
||||||
from backend.db import (construct_submission_info, lookup_reagent,
|
from backend.db import (construct_submission_info, lookup_reagent,
|
||||||
construct_reagent, store_reagent, store_submission, lookup_kittype_by_use,
|
construct_reagent, store_reagent, store_submission, lookup_kittype_by_use,
|
||||||
lookup_regent_by_type_name, lookup_all_orgs, lookup_submissions_by_date_range,
|
lookup_regent_by_type_name, lookup_all_orgs, lookup_submissions_by_date_range,
|
||||||
get_all_Control_Types_names, create_kit_from_yaml, get_all_available_modes, get_all_controls_by_type,
|
get_all_Control_Types_names, create_kit_from_yaml, get_all_available_modes, get_all_controls_by_type,
|
||||||
get_control_subtypes, lookup_all_submissions_by_type, get_all_controls, lookup_submission_by_rsl_num
|
get_control_subtypes, lookup_all_submissions_by_type, get_all_controls, lookup_submission_by_rsl_num,
|
||||||
|
create_org_from_yaml
|
||||||
)
|
)
|
||||||
from .functions import check_kit_integrity, check_not_nan
|
|
||||||
|
from .functions import check_kit_integrity
|
||||||
|
from tools import check_not_nan
|
||||||
from backend.excel.reports import make_report_xlsx, make_report_html
|
from backend.excel.reports import make_report_xlsx, make_report_html
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
from frontend.custom_widgets.sub_details import SubmissionsSheet
|
from frontend.custom_widgets.sub_details import SubmissionsSheet
|
||||||
from frontend.custom_widgets.pop_ups import AddReagentQuestion, OverwriteSubQuestion, AlertPop
|
from frontend.custom_widgets.pop_ups import AlertPop, QuestionAsker
|
||||||
from frontend.custom_widgets import AddReagentForm, ReportDatePicker, KitAdder, ControlsDatePicker
|
from frontend.custom_widgets import AddReagentForm, ReportDatePicker, KitAdder, ControlsDatePicker
|
||||||
import logging
|
import logging
|
||||||
import difflib
|
import difflib
|
||||||
@@ -96,6 +98,7 @@ class App(QMainWindow):
|
|||||||
self.addToolBar(toolbar)
|
self.addToolBar(toolbar)
|
||||||
toolbar.addAction(self.addReagentAction)
|
toolbar.addAction(self.addReagentAction)
|
||||||
toolbar.addAction(self.addKitAction)
|
toolbar.addAction(self.addKitAction)
|
||||||
|
toolbar.addAction(self.addOrgAction)
|
||||||
|
|
||||||
def _createActions(self):
|
def _createActions(self):
|
||||||
"""
|
"""
|
||||||
@@ -105,6 +108,7 @@ class App(QMainWindow):
|
|||||||
self.addReagentAction = QAction("Add Reagent", self)
|
self.addReagentAction = QAction("Add Reagent", self)
|
||||||
self.generateReportAction = QAction("Make Report", self)
|
self.generateReportAction = QAction("Make Report", self)
|
||||||
self.addKitAction = QAction("Add Kit", self)
|
self.addKitAction = QAction("Add Kit", self)
|
||||||
|
self.addOrgAction = QAction("Add Org", self)
|
||||||
self.joinControlsAction = QAction("Link Controls")
|
self.joinControlsAction = QAction("Link Controls")
|
||||||
self.joinExtractionAction = QAction("Link Ext Logs")
|
self.joinExtractionAction = QAction("Link Ext Logs")
|
||||||
|
|
||||||
@@ -117,6 +121,7 @@ class App(QMainWindow):
|
|||||||
self.addReagentAction.triggered.connect(self.add_reagent)
|
self.addReagentAction.triggered.connect(self.add_reagent)
|
||||||
self.generateReportAction.triggered.connect(self.generateReport)
|
self.generateReportAction.triggered.connect(self.generateReport)
|
||||||
self.addKitAction.triggered.connect(self.add_kit)
|
self.addKitAction.triggered.connect(self.add_kit)
|
||||||
|
self.addOrgAction.triggered.connect(self.add_org)
|
||||||
self.table_widget.control_typer.currentIndexChanged.connect(self._controls_getter)
|
self.table_widget.control_typer.currentIndexChanged.connect(self._controls_getter)
|
||||||
self.table_widget.mode_typer.currentIndexChanged.connect(self._controls_getter)
|
self.table_widget.mode_typer.currentIndexChanged.connect(self._controls_getter)
|
||||||
self.table_widget.datepicker.start_date.dateChanged.connect(self._controls_getter)
|
self.table_widget.datepicker.start_date.dateChanged.connect(self._controls_getter)
|
||||||
@@ -183,7 +188,7 @@ class App(QMainWindow):
|
|||||||
# create label
|
# create label
|
||||||
self.table_widget.formlayout.addWidget(QLabel(item.replace("_", " ").title()))
|
self.table_widget.formlayout.addWidget(QLabel(item.replace("_", " ").title()))
|
||||||
# if extraction kit not available, all other values fail
|
# if extraction kit not available, all other values fail
|
||||||
if np.isnan(prsr.sub[item]):
|
if not check_not_nan(prsr.sub[item]):
|
||||||
msg = AlertPop(message="Make sure to check your extraction kit!", status="warning")
|
msg = AlertPop(message="Make sure to check your extraction kit!", status="warning")
|
||||||
msg.exec()
|
msg.exec()
|
||||||
# create combobox to hold looked up kits
|
# create combobox to hold looked up kits
|
||||||
@@ -231,7 +236,7 @@ class App(QMainWindow):
|
|||||||
elif isinstance(reagent, str):
|
elif isinstance(reagent, str):
|
||||||
output_reg.append(reagent)
|
output_reg.append(reagent)
|
||||||
relevant_reagents = output_reg
|
relevant_reagents = output_reg
|
||||||
logger.debug(f"Relevant reagents: {relevant_reagents}")
|
logger.debug(f"Relevant reagents for {prsr.sub[item]}: {relevant_reagents}")
|
||||||
# if reagent in sheet is not found insert it into items
|
# if reagent in sheet is not found insert it into items
|
||||||
if str(prsr.sub[item]['lot']) not in relevant_reagents and prsr.sub[item]['lot'] != 'nan':
|
if str(prsr.sub[item]['lot']) not in relevant_reagents and prsr.sub[item]['lot'] != 'nan':
|
||||||
if check_not_nan(prsr.sub[item]['lot']):
|
if check_not_nan(prsr.sub[item]['lot']):
|
||||||
@@ -272,11 +277,13 @@ class App(QMainWindow):
|
|||||||
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:
|
||||||
dlg = AddReagentQuestion(reagent_type=reagent, reagent_lot=reagents[reagent])
|
# dlg = AddReagentQuestion(reagent_type=reagent, reagent_lot=reagents[reagent])
|
||||||
|
r_lot = reagents[reagent]
|
||||||
|
dlg = QuestionAsker(title=f"Add {r_lot}?", message=f"Couldn't find reagent type {reagent.replace('_', ' ').title().strip('Lot')}: {r_lot} in the database.\n\nWould you like to add it?")
|
||||||
if dlg.exec():
|
if dlg.exec():
|
||||||
logger.debug(f"checking reagent: {reagent} in self.reagents. Result: {self.reagents[reagent]}")
|
logger.debug(f"checking reagent: {reagent} in self.reagents. Result: {self.reagents[reagent]}")
|
||||||
expiry_date = self.reagents[reagent]['exp']
|
expiry_date = self.reagents[reagent]['exp']
|
||||||
wanted_reagent = self.add_reagent(reagent_lot=reagents[reagent], reagent_type=reagent.replace("lot_", ""), expiry=expiry_date)
|
wanted_reagent = self.add_reagent(reagent_lot=r_lot, reagent_type=reagent.replace("lot_", ""), expiry=expiry_date)
|
||||||
else:
|
else:
|
||||||
logger.debug("Will not add reagent.")
|
logger.debug("Will not add reagent.")
|
||||||
if wanted_reagent != None:
|
if wanted_reagent != None:
|
||||||
@@ -287,14 +294,23 @@ class App(QMainWindow):
|
|||||||
info['uploaded_by'] = getuser()
|
info['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)}")
|
||||||
base_submission, output = construct_submission_info(ctx=self.ctx, info_dict=info)
|
base_submission, result = construct_submission_info(ctx=self.ctx, info_dict=info)
|
||||||
# check output message for issues
|
# check output message for issues
|
||||||
if output['message'] != None:
|
match result['code']:
|
||||||
dlg = OverwriteSubQuestion(output['message'], base_submission.rsl_plate_num)
|
case 1:
|
||||||
|
# if output['code'] > 0:
|
||||||
|
# dlg = OverwriteSubQuestion(output['message'], base_submission.rsl_plate_num)
|
||||||
|
dlg = QuestionAsker(title=f"Review {base_submission.rsl_plate_num}?", message=result['message'])
|
||||||
if dlg.exec():
|
if dlg.exec():
|
||||||
base_submission.reagents = []
|
base_submission.reagents = []
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
case 2:
|
||||||
|
dlg = AlertPop(message=result['message'], status='critical')
|
||||||
|
dlg.exec()
|
||||||
|
return
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
# add reagents to submission object
|
# add reagents to submission object
|
||||||
for reagent in parsed_reagents:
|
for reagent in parsed_reagents:
|
||||||
base_submission.reagents.append(reagent)
|
base_submission.reagents.append(reagent)
|
||||||
@@ -447,20 +463,59 @@ class App(QMainWindow):
|
|||||||
return
|
return
|
||||||
# send to kit creator function
|
# send to kit creator function
|
||||||
result = create_kit_from_yaml(ctx=self.ctx, exp=exp)
|
result = create_kit_from_yaml(ctx=self.ctx, exp=exp)
|
||||||
msg = QMessageBox()
|
# msg = QMessageBox()
|
||||||
# msg.setIcon(QMessageBox.critical)
|
# msg.setIcon(QMessageBox.critical)
|
||||||
match result['code']:
|
match result['code']:
|
||||||
case 0:
|
case 0:
|
||||||
msg.setText("Kit added")
|
msg = AlertPop(message=result['message'], status='info')
|
||||||
msg.setInformativeText(result['message'])
|
# msg.setText("Kit added")
|
||||||
msg.setWindowTitle("Kit added")
|
# msg.setInformativeText(result['message'])
|
||||||
|
# msg.setWindowTitle("Kit added")
|
||||||
case 1:
|
case 1:
|
||||||
msg.setText("Permission Error")
|
msg = AlertPop(message=result['message'], status='critical')
|
||||||
msg.setInformativeText(result['message'])
|
# msg.setText("Permission Error")
|
||||||
msg.setWindowTitle("Permission Error")
|
# msg.setInformativeText(result['message'])
|
||||||
|
# msg.setWindowTitle("Permission Error")
|
||||||
msg.exec()
|
msg.exec()
|
||||||
|
|
||||||
|
|
||||||
|
def add_org(self):
|
||||||
|
"""
|
||||||
|
Constructs new kit from yaml and adds to DB.
|
||||||
|
"""
|
||||||
|
# setup file dialog to find yaml flie
|
||||||
|
home_dir = str(Path(self.ctx["directory_path"]))
|
||||||
|
fname = Path(QFileDialog.getOpenFileName(self, 'Open file', home_dir, filter = "yml(*.yml)")[0])
|
||||||
|
assert fname.exists()
|
||||||
|
# read yaml file
|
||||||
|
try:
|
||||||
|
with open(fname.__str__(), "r") as stream:
|
||||||
|
try:
|
||||||
|
org = yaml.load(stream, Loader=yaml.Loader)
|
||||||
|
except yaml.YAMLError as exc:
|
||||||
|
logger.error(f'Error reading yaml file {fname}: {exc}')
|
||||||
|
return {}
|
||||||
|
except PermissionError:
|
||||||
|
return
|
||||||
|
# send to kit creator function
|
||||||
|
result = create_org_from_yaml(ctx=self.ctx, org=org)
|
||||||
|
# msg = QMessageBox()
|
||||||
|
# msg.setIcon(QMessageBox.critical)
|
||||||
|
match result['code']:
|
||||||
|
case 0:
|
||||||
|
msg = AlertPop(message=result['message'], status='information')
|
||||||
|
# msg.setText("Organization added")
|
||||||
|
# msg.setInformativeText(result['message'])
|
||||||
|
# msg.setWindowTitle("Kit added")
|
||||||
|
case 1:
|
||||||
|
msg = AlertPop(message=result['message'], status='critical')
|
||||||
|
# msg.setText("Permission Error")
|
||||||
|
# msg.setInformativeText(result['message'])
|
||||||
|
# msg.setWindowTitle("Permission Error")
|
||||||
|
msg.exec()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _controls_getter(self):
|
def _controls_getter(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -22,50 +22,67 @@ loader = FileSystemLoader(loader_path)
|
|||||||
env = Environment(loader=loader)
|
env = Environment(loader=loader)
|
||||||
|
|
||||||
|
|
||||||
class AddReagentQuestion(QDialog):
|
# class AddReagentQuestion(QDialog):
|
||||||
|
# """
|
||||||
|
# dialog to ask about adding a new reagne to db
|
||||||
|
# """
|
||||||
|
# def __init__(self, reagent_type:str, reagent_lot:str) -> QDialog:
|
||||||
|
# super().__init__()
|
||||||
|
|
||||||
|
# self.setWindowTitle(f"Add {reagent_lot}?")
|
||||||
|
|
||||||
|
# QBtn = QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
|
||||||
|
|
||||||
|
# self.buttonBox = QDialogButtonBox(QBtn)
|
||||||
|
# self.buttonBox.accepted.connect(self.accept)
|
||||||
|
# self.buttonBox.rejected.connect(self.reject)
|
||||||
|
|
||||||
|
# self.layout = QVBoxLayout()
|
||||||
|
# message = QLabel(f"Couldn't find reagent type {reagent_type.replace('_', ' ').title().strip('Lot')}: {reagent_lot} in the database.\n\nWould you like to add it?")
|
||||||
|
# self.layout.addWidget(message)
|
||||||
|
# self.layout.addWidget(self.buttonBox)
|
||||||
|
# self.setLayout(self.layout)
|
||||||
|
|
||||||
|
|
||||||
|
# class OverwriteSubQuestion(QDialog):
|
||||||
|
# """
|
||||||
|
# dialog to ask about overwriting existing submission
|
||||||
|
# """
|
||||||
|
# def __init__(self, message:str, rsl_plate_num:str) -> QDialog:
|
||||||
|
# super().__init__()
|
||||||
|
|
||||||
|
# self.setWindowTitle(f"Overwrite {rsl_plate_num}?")
|
||||||
|
|
||||||
|
# QBtn = QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
|
||||||
|
|
||||||
|
# self.buttonBox = QDialogButtonBox(QBtn)
|
||||||
|
# self.buttonBox.accepted.connect(self.accept)
|
||||||
|
# self.buttonBox.rejected.connect(self.reject)
|
||||||
|
|
||||||
|
# self.layout = QVBoxLayout()
|
||||||
|
# message = QLabel(message)
|
||||||
|
# self.layout.addWidget(message)
|
||||||
|
# self.layout.addWidget(self.buttonBox)
|
||||||
|
# self.setLayout(self.layout)
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionAsker(QDialog):
|
||||||
"""
|
"""
|
||||||
dialog to ask about adding a new reagne to db
|
dialog to ask yes/no questions
|
||||||
"""
|
"""
|
||||||
def __init__(self, reagent_type:str, reagent_lot:str) -> QDialog:
|
def __init__(self, title:str, message:str) -> QDialog:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.setWindowTitle(title)
|
||||||
self.setWindowTitle(f"Add {reagent_lot}?")
|
|
||||||
|
|
||||||
QBtn = QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
|
QBtn = QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
|
||||||
|
|
||||||
self.buttonBox = QDialogButtonBox(QBtn)
|
self.buttonBox = QDialogButtonBox(QBtn)
|
||||||
self.buttonBox.accepted.connect(self.accept)
|
self.buttonBox.accepted.connect(self.accept)
|
||||||
self.buttonBox.rejected.connect(self.reject)
|
self.buttonBox.rejected.connect(self.reject)
|
||||||
|
|
||||||
self.layout = QVBoxLayout()
|
|
||||||
message = QLabel(f"Couldn't find reagent type {reagent_type.replace('_', ' ').title().strip('Lot')}: {reagent_lot} in the database.\n\nWould you like to add it?")
|
|
||||||
self.layout.addWidget(message)
|
|
||||||
self.layout.addWidget(self.buttonBox)
|
|
||||||
self.setLayout(self.layout)
|
|
||||||
|
|
||||||
|
|
||||||
class OverwriteSubQuestion(QDialog):
|
|
||||||
"""
|
|
||||||
dialog to ask about overwriting existing submission
|
|
||||||
"""
|
|
||||||
def __init__(self, message:str, rsl_plate_num:str) -> QDialog:
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
self.setWindowTitle(f"Overwrite {rsl_plate_num}?")
|
|
||||||
|
|
||||||
QBtn = QDialogButtonBox.StandardButton.Yes | QDialogButtonBox.StandardButton.No
|
|
||||||
|
|
||||||
self.buttonBox = QDialogButtonBox(QBtn)
|
|
||||||
self.buttonBox.accepted.connect(self.accept)
|
|
||||||
self.buttonBox.rejected.connect(self.reject)
|
|
||||||
|
|
||||||
self.layout = QVBoxLayout()
|
self.layout = QVBoxLayout()
|
||||||
message = QLabel(message)
|
message = QLabel(message)
|
||||||
self.layout.addWidget(message)
|
self.layout.addWidget(message)
|
||||||
self.layout.addWidget(self.buttonBox)
|
self.layout.addWidget(self.buttonBox)
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
|
||||||
class AlertPop(QMessageBox):
|
class AlertPop(QMessageBox):
|
||||||
|
|
||||||
def __init__(self, message:str, status:str) -> QMessageBox:
|
def __init__(self, message:str, status:str) -> QMessageBox:
|
||||||
|
|||||||
@@ -21,11 +21,3 @@ def check_kit_integrity(sub:BasicSubmission):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def check_not_nan(cell_contents) -> bool:
|
|
||||||
try:
|
|
||||||
return not np.isnan(cell_contents)
|
|
||||||
except ValueError:
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
logger.debug(f"Check encounteded unknown error: {e}")
|
|
||||||
return False
|
|
||||||
13
src/submissions/tools/__init__.py
Normal file
13
src/submissions/tools/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import numpy as np
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
|
def check_not_nan(cell_contents) -> bool:
|
||||||
|
try:
|
||||||
|
return not np.isnan(cell_contents)
|
||||||
|
except TypeError:
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Check encounteded unknown error: {type(e).__name__} - {e}")
|
||||||
|
return False
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from sqlalchemy import create_engine
|
|
||||||
from sqlalchemy.orm import Session
|
|
||||||
from src.submissions.backend.db.models import *
|
|
||||||
from src.submissions.backend.db import get_kits_by_use
|
|
||||||
|
|
||||||
engine = create_engine("sqlite+pysqlite:///:memory:", echo=True, future=True)
|
|
||||||
session = Session(engine)
|
|
||||||
metadata.create_all(engine)
|
|
||||||
Reference in New Issue
Block a user