commit before refactor to use pyqt6 input field names
This commit is contained in:
@@ -92,7 +92,7 @@ def store_reagent(ctx:dict, reagent:models.Reagent) -> None|dict:
|
||||
|
||||
def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmission:
|
||||
"""
|
||||
Construct submission obejct from dictionary
|
||||
Construct submission object from dictionary
|
||||
|
||||
Args:
|
||||
ctx (dict): settings passed down from gui
|
||||
@@ -110,7 +110,6 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
||||
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()
|
||||
|
||||
# get model based on submission type converted above
|
||||
logger.debug(f"Looking at models for submission type: {query}")
|
||||
model = getattr(models, query)
|
||||
@@ -121,7 +120,7 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
||||
instance = model()
|
||||
logger.debug(f"Submission doesn't exist yet, creating new instance: {instance}")
|
||||
msg = None
|
||||
code =0
|
||||
code = 0
|
||||
else:
|
||||
code = 1
|
||||
msg = "This submission already exists.\nWould you like to overwrite?"
|
||||
@@ -164,7 +163,6 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
||||
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
|
||||
# We need to make sure there's a proper rsl plate number
|
||||
|
||||
try:
|
||||
logger.debug(f"Constructed instance: {instance.to_string()}")
|
||||
except AttributeError as e:
|
||||
@@ -196,12 +194,13 @@ def construct_reagent(ctx:dict, info_dict:dict) -> models.Reagent:
|
||||
case "type":
|
||||
reagent.type = lookup_reagenttype_by_name(ctx=ctx, rt_name=info_dict[item].replace(" ", "_").lower())
|
||||
# add end-of-life extension from reagent type to expiry date
|
||||
try:
|
||||
reagent.expiry = reagent.expiry + reagent.type.eol_ext
|
||||
except TypeError as e:
|
||||
logger.debug(f"We got a type error: {e}.")
|
||||
except AttributeError:
|
||||
pass
|
||||
# Edit: this will now be done only in the reporting phase to account for potential changes in end-of-life extensions
|
||||
# try:
|
||||
# reagent.expiry = reagent.expiry + reagent.type.eol_ext
|
||||
# except TypeError as e:
|
||||
# logger.debug(f"We got a type error: {e}.")
|
||||
# except AttributeError:
|
||||
# pass
|
||||
return reagent
|
||||
|
||||
|
||||
@@ -465,7 +464,7 @@ def create_kit_from_yaml(ctx:dict, exp:dict) -> dict:
|
||||
# except KeyError:
|
||||
if not check_is_power_user(ctx=ctx):
|
||||
logger.debug(f"{getuser()} does not have permission to add kits.")
|
||||
return {'code':1, 'message':"This user does not have permission to add kits."}
|
||||
return {'code':1, 'message':"This user does not have permission to add kits.", "status":"warning"}
|
||||
for type in exp:
|
||||
if type == "password":
|
||||
continue
|
||||
@@ -486,7 +485,7 @@ def create_kit_from_yaml(ctx:dict, exp:dict) -> dict:
|
||||
logger.debug(kit.__dict__)
|
||||
ctx['database_session'].add(kit)
|
||||
ctx['database_session'].commit()
|
||||
return {'code':0, 'message':'Kit has been added'}
|
||||
return {'code':0, 'message':'Kit has been added', 'status': 'information'}
|
||||
|
||||
def create_org_from_yaml(ctx:dict, org:dict) -> dict:
|
||||
"""
|
||||
|
||||
@@ -39,9 +39,9 @@ class Control(Base):
|
||||
# UniqueConstraint('name', name='uq_control_name')
|
||||
submission_id = Column(INTEGER, ForeignKey("_submissions.id")) #: parent submission id
|
||||
submission = relationship("BacterialCulture", back_populates="controls", foreign_keys=[submission_id]) #: parent submission
|
||||
refseq_version = Column(String(16))
|
||||
kraken2_version = Column(String(16))
|
||||
kraken2_db_version = Column(String(32))
|
||||
refseq_version = Column(String(16)) #: version of refseq used in fastq parsing
|
||||
kraken2_version = Column(String(16)) #: version of kraken2 used in fastq parsing
|
||||
kraken2_db_version = Column(String(32)) #: folder name of kraken2 db
|
||||
|
||||
|
||||
def to_sub_dict(self) -> dict:
|
||||
@@ -51,17 +51,22 @@ class Control(Base):
|
||||
Returns:
|
||||
dict: output dictionary containing: Name, Type, Targets, Top Kraken results
|
||||
"""
|
||||
# load json string into dict
|
||||
kraken = json.loads(self.kraken)
|
||||
# calculate kraken count total to use in percentage
|
||||
kraken_cnt_total = sum([kraken[item]['kraken_count'] for item in kraken])
|
||||
new_kraken = []
|
||||
for item in kraken:
|
||||
# calculate kraken percent (overwrites what's already been scraped)
|
||||
kraken_percent = kraken[item]['kraken_count'] / kraken_cnt_total
|
||||
new_kraken.append({'name': item, 'kraken_count':kraken[item]['kraken_count'], 'kraken_percent':"{0:.0%}".format(kraken_percent)})
|
||||
new_kraken = sorted(new_kraken, key=itemgetter('kraken_count'), reverse=True)
|
||||
# set targets
|
||||
if self.controltype.targets == []:
|
||||
targets = ["None"]
|
||||
else:
|
||||
targets = self.controltype.targets
|
||||
# construct output dictionary
|
||||
output = {
|
||||
"name" : self.name,
|
||||
"type" : self.controltype.name,
|
||||
@@ -72,36 +77,43 @@ class Control(Base):
|
||||
|
||||
def convert_by_mode(self, mode:str) -> list[dict]:
|
||||
"""
|
||||
split control object into analysis types
|
||||
split control object into analysis types for controls graphs
|
||||
|
||||
Args:
|
||||
control (models.Control): control to be parsed into list
|
||||
mode (str): analysis type
|
||||
mode (str): analysis type, 'contains', etc
|
||||
|
||||
Returns:
|
||||
list[dict]: list of records
|
||||
"""
|
||||
output = []
|
||||
# load json string for mode (i.e. contains, matches, kraken2)
|
||||
data = json.loads(getattr(self, mode))
|
||||
# if len(data) == 0:
|
||||
# data = self.create_dummy_data(mode)
|
||||
logger.debug(f"Length of data: {len(data)}")
|
||||
# dict keys are genera of bacteria, e.g. 'Streptococcus'
|
||||
for genus in data:
|
||||
_dict = {}
|
||||
_dict['name'] = self.name
|
||||
_dict['submitted_date'] = self.submitted_date
|
||||
_dict['genus'] = genus
|
||||
# get Target or Off-target of genus
|
||||
_dict['target'] = 'Target' if genus.strip("*") in self.controltype.targets else "Off-target"
|
||||
|
||||
# set 'contains_hashes', etc for genus,
|
||||
for key in data[genus]:
|
||||
_dict[key] = data[genus][key]
|
||||
if _dict[key] == {}:
|
||||
print(self.name, mode)
|
||||
output.append(_dict)
|
||||
# logger.debug(output)
|
||||
return output
|
||||
|
||||
def create_dummy_data(self, mode):
|
||||
def create_dummy_data(self, mode:str) -> dict:
|
||||
"""
|
||||
Create non-zero length data to maintain entry of zero length 'contains' (depreciated)
|
||||
|
||||
Args:
|
||||
mode (str): analysis type, 'contains', etc
|
||||
|
||||
Returns:
|
||||
dict: dictionary of 'Nothing' genus
|
||||
"""
|
||||
match mode:
|
||||
case "contains":
|
||||
data = {"Nothing": {"contains_hashes":"0/400", "contains_ratio":0.0}}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from copy import deepcopy
|
||||
from . import Base
|
||||
from sqlalchemy import Column, String, TIMESTAMP, JSON, INTEGER, ForeignKey, Interval, Table, FLOAT
|
||||
from sqlalchemy.orm import relationship
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(f'submissions.{__name__}')
|
||||
|
||||
|
||||
# Table containing reagenttype-kittype relationships
|
||||
@@ -44,7 +48,6 @@ class ReagentType(Base):
|
||||
kit_id = Column(INTEGER, ForeignKey("_kits.id", ondelete="SET NULL", use_alter=True, name="fk_RT_kits_id")) #: id of joined kit type
|
||||
kits = relationship("KitType", back_populates="reagent_types", uselist=True, foreign_keys=[kit_id]) #: kits this reagent is used in
|
||||
instances = relationship("Reagent", back_populates="type") #: concrete instances of this reagent type
|
||||
# instances_id = Column(INTEGER, ForeignKey("_reagents.id", ondelete='SET NULL'))
|
||||
eol_ext = Column(Interval()) #: extension of life interval
|
||||
|
||||
def __str__(self) -> str:
|
||||
@@ -76,9 +79,11 @@ class Reagent(Base):
|
||||
string representing this object
|
||||
|
||||
Returns:
|
||||
str: string representing this object's lot number
|
||||
"""
|
||||
return str(self.lot)
|
||||
str: string representing this object's type and lot number
|
||||
"""
|
||||
lot = str(self.lot)
|
||||
r_type = str(self.type)
|
||||
return f"{r_type} - {lot}"
|
||||
|
||||
def to_sub_dict(self) -> dict:
|
||||
"""
|
||||
@@ -91,8 +96,15 @@ class Reagent(Base):
|
||||
type = self.type.name.replace("_", " ").title()
|
||||
except AttributeError:
|
||||
type = "Unknown"
|
||||
try:
|
||||
place_holder = self.expiry + self.type.eol_ext
|
||||
# logger.debug(f"EOL_ext for {self.lot} -- {self.expiry} + {self.type.eol_ext} = {place_holder}")
|
||||
except TypeError as e:
|
||||
logger.debug(f"We got a type error setting {self.lot} expiry: {e}.")
|
||||
except AttributeError as e:
|
||||
logger.debug(f"We got an attribute error setting {self.lot} expiry: {e}.")
|
||||
return {
|
||||
"type": type,
|
||||
"lot": self.lot,
|
||||
"expiry": self.expiry.strftime("%Y-%m-%d")
|
||||
"expiry": place_holder.strftime("%Y-%m-%d")
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
from . import Base
|
||||
from sqlalchemy import Column, String, TIMESTAMP, JSON, Float, INTEGER, ForeignKey, UniqueConstraint, Table
|
||||
from sqlalchemy.orm import relationship, validates
|
||||
from sqlalchemy import Column, String, INTEGER, ForeignKey, Table
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
|
||||
# table containing organization/contact relationship
|
||||
@@ -32,7 +32,7 @@ class Organization(Base):
|
||||
|
||||
class Contact(Base):
|
||||
"""
|
||||
Base of Contace
|
||||
Base of Contact
|
||||
"""
|
||||
__tablename__ = "_contacts"
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ class WWSample(Base):
|
||||
__tablename__ = "_ww_samples"
|
||||
|
||||
id = Column(INTEGER, primary_key=True) #: primary key
|
||||
ww_processing_num = Column(String(64))
|
||||
ww_processing_num = Column(String(64)) #: wastewater processing number
|
||||
ww_sample_full_id = Column(String(64), nullable=False)
|
||||
rsl_number = Column(String(64)) #: rsl plate identification number
|
||||
rsl_plate = relationship("Wastewater", back_populates="samples") #: relationship to parent plate
|
||||
rsl_plate_id = Column(INTEGER, ForeignKey("_submissions.id", ondelete="SET NULL", name="fk_WWS_submission_id"))
|
||||
collection_date = Column(TIMESTAMP) #: Date submission received
|
||||
testing_type = Column(String(64))
|
||||
testing_type = Column(String(64))
|
||||
site_status = Column(String(64))
|
||||
notes = Column(String(2000))
|
||||
ct_n1 = Column(FLOAT(2))
|
||||
@@ -40,7 +40,7 @@ class WWSample(Base):
|
||||
gui friendly dictionary
|
||||
|
||||
Returns:
|
||||
dict: well location and id
|
||||
dict: well location and id NOTE: keys must sync with BCSample to_sub_dict below
|
||||
"""
|
||||
return {
|
||||
"well": self.well_number,
|
||||
@@ -76,7 +76,7 @@ class BCSample(Base):
|
||||
gui friendly dictionary
|
||||
|
||||
Returns:
|
||||
dict: well location and name (sample id, organism)
|
||||
dict: well location and name (sample id, organism) NOTE: keys must sync with WWSample to_sub_dict above
|
||||
"""
|
||||
return {
|
||||
"well": self.well_number,
|
||||
|
||||
@@ -22,18 +22,18 @@ class BasicSubmission(Base):
|
||||
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
|
||||
submitting_lab = relationship("Organization", back_populates="submissions") #: client org
|
||||
submitting_lab_id = Column(INTEGER, ForeignKey("_organizations.id", ondelete="SET NULL", name="fk_BS_sublab_id"))
|
||||
submitting_lab_id = Column(INTEGER, ForeignKey("_organizations.id", ondelete="SET NULL", name="fk_BS_sublab_id")) #: client lab id from _organizations
|
||||
sample_count = Column(INTEGER) #: Number of samples in the submission
|
||||
extraction_kit = relationship("KitType", back_populates="submissions") #: The extraction kit used
|
||||
extraction_kit_id = Column(INTEGER, ForeignKey("_kits.id", ondelete="SET NULL", name="fk_BS_extkit_id"))
|
||||
submission_type = Column(String(32)) #: submission type (should be string in D3 of excel sheet)
|
||||
technician = Column(String(64)) #: initials of processing tech
|
||||
technician = Column(String(64)) #: initials of processing tech(s)
|
||||
# Move this into custom types?
|
||||
reagents = relationship("Reagent", back_populates="submissions", secondary=reagents_submissions) #: relationship to reagents
|
||||
reagents_id = Column(String, ForeignKey("_reagents.id", ondelete="SET NULL", name="fk_BS_reagents_id")) #: id of used reagents
|
||||
extraction_info = Column(JSON) #: unstructured output from the extraction table logger.
|
||||
run_cost = Column(FLOAT(2))
|
||||
uploaded_by = Column(String(32))
|
||||
run_cost = Column(FLOAT(2)) #: total cost of running the plate. Set from kit costs at time of creation.
|
||||
uploaded_by = Column(String(32)) #: user name of person who submitted the submission to the database.
|
||||
|
||||
__mapper_args__ = {
|
||||
"polymorphic_identity": "basic_submission",
|
||||
@@ -71,6 +71,7 @@ class BasicSubmission(Base):
|
||||
ext_kit = self.extraction_kit.name
|
||||
except AttributeError:
|
||||
ext_kit = None
|
||||
# load scraped extraction info
|
||||
try:
|
||||
ext_info = json.loads(self.extraction_info)
|
||||
except TypeError:
|
||||
@@ -80,7 +81,8 @@ class BasicSubmission(Base):
|
||||
logger.debug(f"Json error in {self.rsl_plate_num}: {e}")
|
||||
try:
|
||||
reagents = [item.to_sub_dict() for item in self.reagents]
|
||||
except:
|
||||
except Exception as e:
|
||||
logger.error(f"We got an error retrieving reagents: {e}")
|
||||
reagents = None
|
||||
try:
|
||||
samples = [item.to_sub_dict() for item in self.samples]
|
||||
|
||||
Reference in New Issue
Block a user