commit before refactor to use pyqt6 input field names

This commit is contained in:
Landon Wark
2023-03-14 13:13:10 -05:00
parent 285ccecd73
commit fc334155ff
11 changed files with 193 additions and 150 deletions

View File

@@ -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:
"""

View File

@@ -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}}

View File

@@ -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")
}

View File

@@ -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"

View File

@@ -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,

View File

@@ -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]