logging and scrollable form
This commit is contained in:
@@ -6,12 +6,11 @@ if getattr(sys, 'frozen', False):
|
|||||||
else :
|
else :
|
||||||
pass
|
pass
|
||||||
from configure import get_config, create_database_session, setup_logger
|
from configure import get_config, create_database_session, setup_logger
|
||||||
|
logger = setup_logger(verbosity=3)
|
||||||
ctx = get_config(None)
|
ctx = get_config(None)
|
||||||
from PyQt6.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
from frontend import App
|
from frontend import App
|
||||||
|
|
||||||
logger = setup_logger(verbose=True)
|
|
||||||
|
|
||||||
ctx["database_session"] = create_database_session(Path(ctx['database']))
|
ctx["database_session"] = create_database_session(Path(ctx['database']))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from sqlalchemy import JSON
|
|||||||
import json
|
import json
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
def get_kits_by_use( ctx:dict, kittype_str:str|None) -> list:
|
def get_kits_by_use( ctx:dict, kittype_str:str|None) -> list:
|
||||||
pass
|
pass
|
||||||
@@ -35,7 +35,7 @@ def store_submission(ctx:dict, base_submission:models.BasicSubmission) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def store_reagent(ctx:dict, reagent:models.Reagent) -> None:
|
def store_reagent(ctx:dict, reagent:models.Reagent) -> None:
|
||||||
print(reagent.__dict__)
|
logger.debug(reagent.__dict__)
|
||||||
ctx['database_session'].add(reagent)
|
ctx['database_session'].add(reagent)
|
||||||
ctx['database_session'].commit()
|
ctx['database_session'].commit()
|
||||||
|
|
||||||
@@ -46,18 +46,18 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
|||||||
info_dict['submission_type'] = info_dict['submission_type'].replace(" ", "_").lower()
|
info_dict['submission_type'] = info_dict['submission_type'].replace(" ", "_").lower()
|
||||||
instance = model()
|
instance = model()
|
||||||
for item in info_dict:
|
for item in info_dict:
|
||||||
print(f"Setting {item} to {info_dict[item]}")
|
logger.debug(f"Setting {item} to {info_dict[item]}")
|
||||||
match item:
|
match item:
|
||||||
case "extraction_kit":
|
case "extraction_kit":
|
||||||
q_str = info_dict[item]
|
q_str = info_dict[item]
|
||||||
print(f"Looking up kit {q_str}")
|
logger.debug(f"Looking up kit {q_str}")
|
||||||
field_value = lookup_kittype_by_name(ctx=ctx, name=q_str)
|
field_value = lookup_kittype_by_name(ctx=ctx, name=q_str)
|
||||||
print(f"Got {field_value} for kit {q_str}")
|
logger.debug(f"Got {field_value} for kit {q_str}")
|
||||||
case "submitting_lab":
|
case "submitting_lab":
|
||||||
q_str = info_dict[item].replace(" ", "_").lower()
|
q_str = info_dict[item].replace(" ", "_").lower()
|
||||||
print(f"looking up organization: {q_str}")
|
logger.debug(f"looking up organization: {q_str}")
|
||||||
field_value = lookup_org_by_name(ctx=ctx, name=q_str)
|
field_value = lookup_org_by_name(ctx=ctx, name=q_str)
|
||||||
print(f"Got {field_value} for organization {q_str}")
|
logger.debug(f"Got {field_value} for organization {q_str}")
|
||||||
case "submitter_plate_num":
|
case "submitter_plate_num":
|
||||||
# Because of unique constraint, the submitter plate number cannot be None, so...
|
# Because of unique constraint, the submitter plate number cannot be None, so...
|
||||||
if info_dict[item] == None:
|
if info_dict[item] == None:
|
||||||
@@ -72,16 +72,16 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
|||||||
try:
|
try:
|
||||||
setattr(instance, item, field_value)
|
setattr(instance, item, field_value)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print(f"Could not set attribute: {item} to {info_dict[item]}")
|
logger.debug(f"Could not set attribute: {item} to {info_dict[item]}")
|
||||||
continue
|
continue
|
||||||
# print(instance.__dict__)
|
# logger.debug(instance.__dict__)
|
||||||
return instance
|
return instance
|
||||||
# looked_up = []
|
# looked_up = []
|
||||||
# for reagent in reagents:
|
# for reagent in reagents:
|
||||||
# my_reagent = lookup_reagent(reagent)
|
# my_reagent = lookup_reagent(reagent)
|
||||||
# print(my_reagent)
|
# logger.debug(my_reagent)
|
||||||
# looked_up.append(my_reagent)
|
# looked_up.append(my_reagent)
|
||||||
# print(looked_up)
|
# logger.debug(looked_up)
|
||||||
# instance.reagents = looked_up
|
# instance.reagents = looked_up
|
||||||
# ctx['database_session'].add(instance)
|
# ctx['database_session'].add(instance)
|
||||||
# ctx['database_session'].commit()
|
# ctx['database_session'].commit()
|
||||||
@@ -89,7 +89,7 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
|
|||||||
def construct_reagent(ctx:dict, info_dict:dict) -> models.Reagent:
|
def construct_reagent(ctx:dict, info_dict:dict) -> models.Reagent:
|
||||||
reagent = models.Reagent()
|
reagent = models.Reagent()
|
||||||
for item in info_dict:
|
for item in info_dict:
|
||||||
print(f"Reagent info item: {item}")
|
logger.debug(f"Reagent info item: {item}")
|
||||||
match item:
|
match item:
|
||||||
case "lot":
|
case "lot":
|
||||||
reagent.lot = info_dict[item].upper()
|
reagent.lot = info_dict[item].upper()
|
||||||
@@ -100,7 +100,7 @@ def construct_reagent(ctx:dict, info_dict:dict) -> models.Reagent:
|
|||||||
try:
|
try:
|
||||||
reagent.expiry = reagent.expiry + reagent.type.eol_ext
|
reagent.expiry = reagent.expiry + reagent.type.eol_ext
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
print(f"WE got a type error: {e}.")
|
logger.debug(f"WE got a type error: {e}.")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
return reagent
|
return reagent
|
||||||
@@ -116,9 +116,9 @@ def get_all_reagenttype_names(ctx:dict) -> list[str]:
|
|||||||
return lookedup
|
return lookedup
|
||||||
|
|
||||||
def lookup_reagenttype_by_name(ctx:dict, rt_name:str) -> models.ReagentType:
|
def lookup_reagenttype_by_name(ctx:dict, rt_name:str) -> models.ReagentType:
|
||||||
print(f"Looking up ReagentType by name: {rt_name}")
|
logger.debug(f"Looking up ReagentType by name: {rt_name}")
|
||||||
lookedup = ctx['database_session'].query(models.ReagentType).filter(models.ReagentType.name==rt_name).first()
|
lookedup = ctx['database_session'].query(models.ReagentType).filter(models.ReagentType.name==rt_name).first()
|
||||||
print(f"Found ReagentType: {lookedup}")
|
logger.debug(f"Found ReagentType: {lookedup}")
|
||||||
return lookedup
|
return lookedup
|
||||||
|
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ def lookup_kittype_by_use(ctx:dict, used_by:str) -> list[models.KitType]:
|
|||||||
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))
|
||||||
|
|
||||||
def lookup_kittype_by_name(ctx:dict, name:str) -> models.KitType:
|
def lookup_kittype_by_name(ctx:dict, name:str) -> models.KitType:
|
||||||
print(f"Querying kittype: {name}")
|
logger.debug(f"Querying kittype: {name}")
|
||||||
return ctx['database_session'].query(models.KitType).filter(models.KitType.name==name).first()
|
return ctx['database_session'].query(models.KitType).filter(models.KitType.name==name).first()
|
||||||
|
|
||||||
|
|
||||||
@@ -154,11 +154,11 @@ def lookup_all_orgs(ctx:dict) -> list[models.Organization]:
|
|||||||
return ctx['database_session'].query(models.Organization).all()
|
return ctx['database_session'].query(models.Organization).all()
|
||||||
|
|
||||||
def lookup_org_by_name(ctx:dict, name:str|None) -> models.Organization:
|
def lookup_org_by_name(ctx:dict, name:str|None) -> models.Organization:
|
||||||
print(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):
|
def submissions_to_df(ctx:dict, type:str|None=None):
|
||||||
print(f"Type: {type}")
|
logger.debug(f"Type: {type}")
|
||||||
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, type=type)]
|
||||||
df = pd.DataFrame.from_records(subs)
|
df = pd.DataFrame.from_records(subs)
|
||||||
return df
|
return df
|
||||||
@@ -205,7 +205,7 @@ def create_kit_from_yaml(ctx:dict, exp:dict) -> None:
|
|||||||
except (UnicodeDecodeError, AttributeError):
|
except (UnicodeDecodeError, AttributeError):
|
||||||
exp['password'] = exp['password'].encode()
|
exp['password'] = exp['password'].encode()
|
||||||
if base64.b64encode(exp['password']) != b'cnNsX3N1Ym1pNTVpb25z':
|
if base64.b64encode(exp['password']) != b'cnNsX3N1Ym1pNTVpb25z':
|
||||||
print(f"Not the correct password.")
|
logger.debug(f"Not the correct password.")
|
||||||
return
|
return
|
||||||
for type in exp:
|
for type in exp:
|
||||||
if type == "password":
|
if type == "password":
|
||||||
@@ -220,8 +220,8 @@ def create_kit_from_yaml(ctx:dict, exp:dict) -> None:
|
|||||||
rt = look_up
|
rt = look_up
|
||||||
rt.kits.append(kit)
|
rt.kits.append(kit)
|
||||||
ctx['database_session'].add(rt)
|
ctx['database_session'].add(rt)
|
||||||
print(rt.__dict__)
|
logger.debug(rt.__dict__)
|
||||||
print(kit.__dict__)
|
logger.debug(kit.__dict__)
|
||||||
ctx['database_session'].add(kit)
|
ctx['database_session'].add(kit)
|
||||||
ctx['database_session'].commit()
|
ctx['database_session'].commit()
|
||||||
|
|
||||||
@@ -252,7 +252,7 @@ def get_all_controls_by_type(ctx:dict, con_type:str, start_date:date|None=None,
|
|||||||
list: Control instances.
|
list: Control instances.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# print(f"Using dates: {start_date} to {end_date}")
|
# logger.debug(f"Using dates: {start_date} to {end_date}")
|
||||||
query = ctx['database_session'].query(models.ControlType).filter_by(name=con_type)
|
query = ctx['database_session'].query(models.ControlType).filter_by(name=con_type)
|
||||||
try:
|
try:
|
||||||
output = query.first().instances
|
output = query.first().instances
|
||||||
@@ -261,7 +261,7 @@ def get_all_controls_by_type(ctx:dict, con_type:str, start_date:date|None=None,
|
|||||||
# Hacky solution to my not being able to get the sql query to work.
|
# Hacky solution to my not being able to get the sql query to work.
|
||||||
if start_date != None and end_date != None:
|
if start_date != None and end_date != None:
|
||||||
output = [item for item in output if item.submitted_date.date() > start_date and item.submitted_date.date() < end_date]
|
output = [item for item in output if item.submitted_date.date() > start_date and item.submitted_date.date() < end_date]
|
||||||
# print(f"Type {con_type}: {query.first()}")
|
# logger.debug(f"Type {con_type}: {query.first()}")
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
@@ -271,7 +271,7 @@ def get_control_subtypes(ctx:dict, type:str, mode:str):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
return []
|
return []
|
||||||
jsoner = json.loads(getattr(outs, mode))
|
jsoner = json.loads(getattr(outs, mode))
|
||||||
print(f"JSON out: {jsoner}")
|
logger.debug(f"JSON out: {jsoner}")
|
||||||
try:
|
try:
|
||||||
genera = list(jsoner.keys())[0]
|
genera = list(jsoner.keys())[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from . import Base
|
from . import Base
|
||||||
from sqlalchemy import Column, String, TIMESTAMP, text, JSON, INTEGER, ForeignKey, UniqueConstraint, Table
|
from sqlalchemy import Column, String, TIMESTAMP, INTEGER, ForeignKey, Table
|
||||||
from sqlalchemy.orm import relationship, relationships
|
from sqlalchemy.orm import relationship
|
||||||
from datetime import datetime as dt
|
from datetime import datetime as dt
|
||||||
|
|
||||||
reagents_submissions = Table("_reagents_submissions", Base.metadata, Column("reagent_id", INTEGER, ForeignKey("_reagents.id")), Column("submission_id", INTEGER, ForeignKey("_submissions.id")))
|
reagents_submissions = Table("_reagents_submissions", Base.metadata, Column("reagent_id", INTEGER, ForeignKey("_reagents.id")), Column("submission_id", INTEGER, ForeignKey("_submissions.id")))
|
||||||
|
|
||||||
class BasicSubmission(Base):
|
class BasicSubmission(Base):
|
||||||
|
|
||||||
# TODO: Figure out if I want seperate tables for different sample types.
|
|
||||||
__tablename__ = "_submissions"
|
__tablename__ = "_submissions"
|
||||||
|
|
||||||
id = Column(INTEGER, primary_key=True) #: primary key
|
id = Column(INTEGER, primary_key=True) #: primary key
|
||||||
@@ -32,7 +31,6 @@ class BasicSubmission(Base):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
print(self.submitting_lab)
|
|
||||||
try:
|
try:
|
||||||
sub_lab = self.submitting_lab.name
|
sub_lab = self.submitting_lab.name
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
|||||||
@@ -13,11 +13,14 @@ logger = logging.getLogger(f"submissions.{__name__}")
|
|||||||
class SheetParser(object):
|
class SheetParser(object):
|
||||||
|
|
||||||
def __init__(self, filepath:Path|None = None, **kwargs):
|
def __init__(self, filepath:Path|None = None, **kwargs):
|
||||||
|
logger.debug(f"Parsing {filepath.__str__()}")
|
||||||
for kwarg in kwargs:
|
for kwarg in kwargs:
|
||||||
setattr(self, f"_{kwarg}", kwargs[kwarg])
|
setattr(self, f"_{kwarg}", kwargs[kwarg])
|
||||||
if filepath == None:
|
if filepath == None:
|
||||||
|
logger.debug(f"No filepath.")
|
||||||
self.xl = None
|
self.xl = None
|
||||||
else:
|
else:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.xl = pd.ExcelFile(filepath.__str__())
|
self.xl = pd.ExcelFile(filepath.__str__())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -76,6 +79,7 @@ class SheetParser(object):
|
|||||||
self.sub['lot_plate'] = submission_info.iloc[12][6]
|
self.sub['lot_plate'] = submission_info.iloc[12][6]
|
||||||
sample_parser = SampleParser(submission_info.iloc[15:111])
|
sample_parser = SampleParser(submission_info.iloc[15:111])
|
||||||
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")
|
||||||
|
logger.debug(f"Parser result: {self.sub}")
|
||||||
self.sub['samples'] = sample_parse()
|
self.sub['samples'] = sample_parse()
|
||||||
|
|
||||||
|
|
||||||
@@ -121,9 +125,10 @@ class SampleParser(object):
|
|||||||
new.sample_id = sample['Unnamed: 1']
|
new.sample_id = sample['Unnamed: 1']
|
||||||
new.organism = sample['Unnamed: 2']
|
new.organism = sample['Unnamed: 2']
|
||||||
new.concentration = sample['Unnamed: 3']
|
new.concentration = sample['Unnamed: 3']
|
||||||
# print(f"Sample object: {new.sample_id} = {type(new.sample_id)}")
|
# logger.debug(f"Sample object: {new.sample_id} = {type(new.sample_id)}")
|
||||||
|
logger.debug(f"Got sample_id: {new.sample_id}")
|
||||||
try:
|
try:
|
||||||
not_a_nan = not np.isnan(new.sample_id) and new.sample_id.lower() != 'blank'
|
not_a_nan = not np.isnan(new.sample_id) and str(new.sample_id).lower() != 'blank'
|
||||||
except TypeError:
|
except TypeError:
|
||||||
not_a_nan = True
|
not_a_nan = True
|
||||||
if not_a_nan:
|
if not_a_nan:
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ from pandas import DataFrame
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from backend.db import models
|
from backend.db import models
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
def make_report_xlsx(records:list[dict]) -> DataFrame:
|
def make_report_xlsx(records:list[dict]) -> DataFrame:
|
||||||
df = DataFrame.from_records(records)
|
df = DataFrame.from_records(records)
|
||||||
@@ -10,7 +13,7 @@ def make_report_xlsx(records:list[dict]) -> DataFrame:
|
|||||||
# table = df.pivot_table(values="Cost", index=["Submitting Lab", "Extraction Kit"], columns=["Cost", "Sample Count"], aggfunc={'Cost':np.sum,'Sample Count':np.sum})
|
# table = df.pivot_table(values="Cost", index=["Submitting Lab", "Extraction Kit"], columns=["Cost", "Sample Count"], aggfunc={'Cost':np.sum,'Sample Count':np.sum})
|
||||||
df2 = df.groupby(["Submitting Lab", "Extraction Kit"]).agg({'Cost': ['sum', 'count'], 'Sample Count':['sum']})
|
df2 = df.groupby(["Submitting Lab", "Extraction Kit"]).agg({'Cost': ['sum', 'count'], 'Sample Count':['sum']})
|
||||||
# df2['Cost'] = df2['Cost'].map('${:,.2f}'.format)
|
# df2['Cost'] = df2['Cost'].map('${:,.2f}'.format)
|
||||||
print(df2.columns)
|
logger.debug(df2.columns)
|
||||||
# df2['Cost']['sum'] = df2['Cost']['sum'].apply('${:,.2f}'.format)
|
# df2['Cost']['sum'] = df2['Cost']['sum'].apply('${:,.2f}'.format)
|
||||||
df2.iloc[:, (df2.columns.get_level_values(1)=='sum') & (df2.columns.get_level_values(0)=='Cost')] = df2.iloc[:, (df2.columns.get_level_values(1)=='sum') & (df2.columns.get_level_values(0)=='Cost')].applymap('${:,.2f}'.format)
|
df2.iloc[:, (df2.columns.get_level_values(1)=='sum') & (df2.columns.get_level_values(0)=='Cost')] = df2.iloc[:, (df2.columns.get_level_values(1)=='sum') & (df2.columns.get_level_values(0)=='Cost')].applymap('${:,.2f}'.format)
|
||||||
return df2
|
return df2
|
||||||
@@ -27,7 +30,7 @@ def make_report_xlsx(records:list[dict]) -> DataFrame:
|
|||||||
# for ii in range(data_size):
|
# for ii in range(data_size):
|
||||||
# new_dict = {}
|
# new_dict = {}
|
||||||
# for genus in sub_dict:
|
# for genus in sub_dict:
|
||||||
# print(genus)
|
# logger.debug(genus)
|
||||||
# sub_name = list(sub_dict[genus].keys())[ii]
|
# sub_name = list(sub_dict[genus].keys())[ii]
|
||||||
# new_dict[genus] = sub_dict[genus][sub_name]
|
# new_dict[genus] = sub_dict[genus][sub_name]
|
||||||
# output.append({"date":dict_name, "name": sub_name, "data": new_dict})
|
# output.append({"date":dict_name, "name": sub_name, "data": new_dict})
|
||||||
@@ -55,10 +58,10 @@ def make_report_xlsx(records:list[dict]) -> DataFrame:
|
|||||||
# # col_dict = entry[col_name]
|
# # col_dict = entry[col_name]
|
||||||
# # series = pd.Series(data=col_dict.values(), index=col_dict.keys(), name=col_name)
|
# # series = pd.Series(data=col_dict.values(), index=col_dict.keys(), name=col_name)
|
||||||
# # # df[col_name] = series.values
|
# # # df[col_name] = series.values
|
||||||
# # # print(df.index)
|
# # # logger.debug(df.index)
|
||||||
# # series_list.append(series)
|
# # series_list.append(series)
|
||||||
# # df = DataFrame(series_list).T.fillna(0)
|
# # df = DataFrame(series_list).T.fillna(0)
|
||||||
# # print(df)
|
# # logger.debug(df)
|
||||||
# dfs['name'] = df
|
# dfs['name'] = df
|
||||||
# return dfs
|
# return dfs
|
||||||
|
|
||||||
@@ -74,14 +77,14 @@ def convert_control_by_mode(ctx:dict, control:models.Control, mode:str):
|
|||||||
for key in data[genus]:
|
for key in data[genus]:
|
||||||
_dict[key] = data[genus][key]
|
_dict[key] = data[genus][key]
|
||||||
output.append(_dict)
|
output.append(_dict)
|
||||||
# print(output)
|
# logger.debug(output)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def convert_data_list_to_df(ctx:dict, input:list[dict], subtype:str|None=None) -> DataFrame:
|
def convert_data_list_to_df(ctx:dict, input:list[dict], subtype:str|None=None) -> DataFrame:
|
||||||
df = DataFrame.from_records(input)
|
df = DataFrame.from_records(input)
|
||||||
safe = ['name', 'submitted_date', 'genus', 'target']
|
safe = ['name', 'submitted_date', 'genus', 'target']
|
||||||
print(df)
|
logger.debug(df)
|
||||||
for column in df.columns:
|
for column in df.columns:
|
||||||
if "percent" in column:
|
if "percent" in column:
|
||||||
count_col = [item for item in df.columns if "count" in item][0]
|
count_col = [item for item in df.columns if "count" in item][0]
|
||||||
@@ -90,5 +93,5 @@ def convert_data_list_to_df(ctx:dict, input:list[dict], subtype:str|None=None) -
|
|||||||
if column not in safe:
|
if column not in safe:
|
||||||
if subtype != None and column != subtype:
|
if subtype != None and column != subtype:
|
||||||
del df[column]
|
del df[column]
|
||||||
# print(df)
|
# logger.debug(df)
|
||||||
return df
|
return df
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import yaml
|
import yaml
|
||||||
import sys, os, stat, platform
|
import sys, os, stat, platform, shutil
|
||||||
import logging
|
import logging
|
||||||
from logging import handlers
|
from logging import handlers
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -8,17 +8,17 @@ from sqlalchemy.orm import Session
|
|||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
package_dir = Path(__file__).parents[2].resolve()
|
package_dir = Path(__file__).parents[2].resolve()
|
||||||
logger.debug(f"Package dir: {package_dir}")
|
logger.debug(f"Package dir: {package_dir}")
|
||||||
|
|
||||||
if platform.system == "Windows":
|
if platform.system() == "Windows":
|
||||||
os_config_dir = "AppData"
|
os_config_dir = "AppData/local"
|
||||||
logger.debug(f"Got platform Windows, config_dir: {os_config_dir}")
|
print(f"Got platform Windows, config_dir: {os_config_dir}")
|
||||||
else:
|
else:
|
||||||
os_config_dir = ".config"
|
os_config_dir = ".config"
|
||||||
logger.debug(f"Got platform other, config_dir: {os_config_dir}")
|
print(f"Got platform other, config_dir: {os_config_dir}")
|
||||||
|
|
||||||
|
|
||||||
main_aux_dir = Path.home().joinpath(f"{os_config_dir}/submissions")
|
main_aux_dir = Path.home().joinpath(f"{os_config_dir}/submissions")
|
||||||
@@ -27,6 +27,8 @@ CONFIGDIR = main_aux_dir.joinpath("config")
|
|||||||
LOGDIR = main_aux_dir.joinpath("logs")
|
LOGDIR = main_aux_dir.joinpath("logs")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GroupWriteRotatingFileHandler(handlers.RotatingFileHandler):
|
class GroupWriteRotatingFileHandler(handlers.RotatingFileHandler):
|
||||||
|
|
||||||
def doRollover(self):
|
def doRollover(self):
|
||||||
@@ -79,6 +81,16 @@ def get_config(settings_path: str|None) -> dict:
|
|||||||
## register the tag handler
|
## register the tag handler
|
||||||
yaml.add_constructor('!join', join)
|
yaml.add_constructor('!join', join)
|
||||||
# if user hasn't defined config path in cli args
|
# if user hasn't defined config path in cli args
|
||||||
|
logger.debug(f"Making directory: {CONFIGDIR.__str__()}")
|
||||||
|
try:
|
||||||
|
CONFIGDIR.mkdir(parents=True)
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
logger.debug(f"Making directory: {LOGDIR.__str__()}")
|
||||||
|
try:
|
||||||
|
LOGDIR.mkdir(parents=True)
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
if settings_path == None:
|
if settings_path == None:
|
||||||
# Check user .config/ozma directory
|
# Check user .config/ozma directory
|
||||||
# if Path.exists(Path.joinpath(CONFIGDIR, "config.yml")):
|
# if Path.exists(Path.joinpath(CONFIGDIR, "config.yml")):
|
||||||
@@ -94,6 +106,7 @@ def get_config(settings_path: str|None) -> dict:
|
|||||||
settings_path = Path(sys._MEIPASS).joinpath("files", "config.yml")
|
settings_path = Path(sys._MEIPASS).joinpath("files", "config.yml")
|
||||||
else:
|
else:
|
||||||
settings_path = package_dir.joinpath('config.yml')
|
settings_path = package_dir.joinpath('config.yml')
|
||||||
|
shutil.copyfile(settings_path.__str__(), CONFIGDIR.joinpath("config.yml").__str__())
|
||||||
else:
|
else:
|
||||||
if Path(settings_path).is_dir():
|
if Path(settings_path).is_dir():
|
||||||
settings_path = settings_path.joinpath("config.yml")
|
settings_path = settings_path.joinpath("config.yml")
|
||||||
@@ -103,6 +116,7 @@ def get_config(settings_path: str|None) -> dict:
|
|||||||
logger.error("No config.yml file found. Using empty dictionary.")
|
logger.error("No config.yml file found. Using empty dictionary.")
|
||||||
return {}
|
return {}
|
||||||
logger.debug(f"Using {settings_path} for config file.")
|
logger.debug(f"Using {settings_path} for config file.")
|
||||||
|
|
||||||
with open(settings_path, "r") as stream:
|
with open(settings_path, "r") as stream:
|
||||||
try:
|
try:
|
||||||
settings = yaml.load(stream, Loader=yaml.Loader)
|
settings = yaml.load(stream, Loader=yaml.Loader)
|
||||||
@@ -141,7 +155,7 @@ def create_database_session(database_path: Path|None) -> Session:
|
|||||||
return session
|
return session
|
||||||
|
|
||||||
|
|
||||||
def setup_logger(verbose:bool=False):
|
def setup_logger(verbosity:int=3):
|
||||||
"""Set logger levels using settings.
|
"""Set logger levels using settings.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -161,34 +175,38 @@ def setup_logger(verbose:bool=False):
|
|||||||
fh.setLevel(logging.DEBUG)
|
fh.setLevel(logging.DEBUG)
|
||||||
fh.name = "File"
|
fh.name = "File"
|
||||||
# create console handler with a higher log level
|
# create console handler with a higher log level
|
||||||
ch = logging.StreamHandler()
|
ch = logging.StreamHandler(stream=sys.stdout)
|
||||||
if verbose:
|
match verbosity:
|
||||||
ch.setLevel(logging.DEBUG)
|
case 3:
|
||||||
else:
|
ch.setLevel(logging.DEBUG)
|
||||||
ch.setLevel(logging.WARNING)
|
case 2:
|
||||||
|
ch.setLevel(logging.INFO)
|
||||||
|
case 1:
|
||||||
|
ch.setLevel(logging.WARNING)
|
||||||
ch.name = "Stream"
|
ch.name = "Stream"
|
||||||
# create formatter and add it to the handlers
|
# create formatter and add it to the handlers
|
||||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
fh.setFormatter(formatter)
|
fh.setFormatter(formatter)
|
||||||
ch.setFormatter(formatter)
|
ch.setFormatter(formatter)
|
||||||
ch.setLevel(logging.ERROR)
|
# ch.setLevel(logging.ERROR)
|
||||||
# add the handlers to the logger
|
# add the handlers to the logger
|
||||||
logger.addHandler(fh)
|
logger.addHandler(fh)
|
||||||
logger.addHandler(ch)
|
logger.addHandler(ch)
|
||||||
stderr_logger = logging.getLogger('STDERR')
|
# stderr_logger = logging.getLogger('STDERR')
|
||||||
|
|
||||||
return logger
|
return logger
|
||||||
# sl = StreamToLogger(stderr_logger, logging.ERROR)
|
# sl = StreamToLogger(stderr_logger, logging.ERROR)
|
||||||
# sys.stderr = sl
|
# sys.stderr = sl
|
||||||
|
|
||||||
def set_logger_verbosity(verbosity):
|
# def set_logger_verbosity(verbosity):
|
||||||
"""Does what it says.
|
# """Does what it says.
|
||||||
"""
|
# """
|
||||||
handler = [item for item in logger.parent.handlers if item.name == "Stream"][0]
|
# handler = [item for item in logger.parent.handlers if item.name == "Stream"][0]
|
||||||
match verbosity:
|
# match verbosity:
|
||||||
case 3:
|
# case 3:
|
||||||
handler.setLevel(logging.DEBUG)
|
# handler.setLevel(logging.DEBUG)
|
||||||
case 2:
|
# case 2:
|
||||||
handler.setLevel(logging.INFO)
|
# handler.setLevel(logging.INFO)
|
||||||
case 1:
|
# case 1:
|
||||||
handler.setLevel(logging.WARNING)
|
# handler.setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from PyQt6.QtWidgets import (
|
|||||||
QTabWidget, QWidget, QVBoxLayout,
|
QTabWidget, QWidget, QVBoxLayout,
|
||||||
QPushButton, QMenuBar, QFileDialog,
|
QPushButton, QMenuBar, QFileDialog,
|
||||||
QLineEdit, QMessageBox, QComboBox, QDateEdit, QHBoxLayout,
|
QLineEdit, QMessageBox, QComboBox, QDateEdit, QHBoxLayout,
|
||||||
QSpinBox
|
QSpinBox, QScrollArea
|
||||||
)
|
)
|
||||||
from PyQt6.QtGui import QAction, QIcon
|
from PyQt6.QtGui import QAction, QIcon
|
||||||
from PyQt6.QtCore import QDateTime, QDate, QSignalBlocker
|
from PyQt6.QtCore import QDateTime, QDate, QSignalBlocker
|
||||||
@@ -108,8 +108,9 @@ class App(QMainWindow):
|
|||||||
prsr = SheetParser(fname, **self.ctx)
|
prsr = SheetParser(fname, **self.ctx)
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
return
|
return
|
||||||
print(f"prsr.sub = {prsr.sub}")
|
logger.debug(f"prsr.sub = {prsr.sub}")
|
||||||
# replace formlayout with tab1.layout
|
# replace formlayout with tab1.layout
|
||||||
|
# self.form = self.table_widget.formlayout
|
||||||
for item in self.table_widget.formlayout.parentWidget().findChildren(QWidget):
|
for item in self.table_widget.formlayout.parentWidget().findChildren(QWidget):
|
||||||
item.setParent(None)
|
item.setParent(None)
|
||||||
variable_parser = re.compile(r"""
|
variable_parser = re.compile(r"""
|
||||||
@@ -128,11 +129,11 @@ class App(QMainWindow):
|
|||||||
mo = variable_parser.fullmatch(item).lastgroup
|
mo = variable_parser.fullmatch(item).lastgroup
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
mo = "other"
|
mo = "other"
|
||||||
print(f"Mo: {mo}")
|
logger.debug(f"Mo: {mo}")
|
||||||
match mo:
|
match mo:
|
||||||
case 'submitting_lab':
|
case 'submitting_lab':
|
||||||
self.table_widget.formlayout.addWidget(QLabel(item.replace("_", " ").title()))
|
self.table_widget.formlayout.addWidget(QLabel(item.replace("_", " ").title()))
|
||||||
print(f"{item}: {prsr.sub[item]}")
|
logger.debug(f"{item}: {prsr.sub[item]}")
|
||||||
add_widget = QComboBox()
|
add_widget = QComboBox()
|
||||||
labs = [item.__str__() for item in lookup_all_orgs(ctx=self.ctx)]
|
labs = [item.__str__() for item in lookup_all_orgs(ctx=self.ctx)]
|
||||||
try:
|
try:
|
||||||
@@ -167,15 +168,15 @@ class App(QMainWindow):
|
|||||||
add_widget.setEditable(True)
|
add_widget.setEditable(True)
|
||||||
# Ensure that all reagenttypes have a name that matches the items in the excel parser
|
# Ensure that all reagenttypes have a name that matches the items in the excel parser
|
||||||
query_var = item.replace("lot_", "")
|
query_var = item.replace("lot_", "")
|
||||||
print(f"Query for: {query_var}")
|
logger.debug(f"Query for: {query_var}")
|
||||||
if isinstance(prsr.sub[item], numpy.float64):
|
if isinstance(prsr.sub[item], numpy.float64):
|
||||||
print(f"{prsr.sub[item]} is a numpy float!")
|
logger.debug(f"{prsr.sub[item]} is a numpy float!")
|
||||||
try:
|
try:
|
||||||
prsr.sub[item] = int(prsr.sub[item])
|
prsr.sub[item] = int(prsr.sub[item])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
relevant_reagents = [item.__str__() for item in lookup_regent_by_type_name_and_kit_name(ctx=self.ctx, type_name=query_var, kit_name=prsr.sub['extraction_kit'])]
|
relevant_reagents = [item.__str__() for item in lookup_regent_by_type_name_and_kit_name(ctx=self.ctx, type_name=query_var, kit_name=prsr.sub['extraction_kit'])]
|
||||||
print(f"Relevant reagents: {relevant_reagents}")
|
logger.debug(f"Relevant reagents: {relevant_reagents}")
|
||||||
if prsr.sub[item] not in relevant_reagents and prsr.sub[item] != 'nan':
|
if prsr.sub[item] not in relevant_reagents and prsr.sub[item] != 'nan':
|
||||||
try:
|
try:
|
||||||
check = not numpy.isnan(prsr.sub[item])
|
check = not numpy.isnan(prsr.sub[item])
|
||||||
@@ -187,7 +188,7 @@ class App(QMainWindow):
|
|||||||
add_widget.addItems(relevant_reagents)
|
add_widget.addItems(relevant_reagents)
|
||||||
# TODO: make samples not appear in frame.
|
# TODO: make samples not appear in frame.
|
||||||
case 'samples':
|
case 'samples':
|
||||||
print(f"{item}: {prsr.sub[item]}")
|
logger.debug(f"{item}: {prsr.sub[item]}")
|
||||||
self.samples = prsr.sub[item]
|
self.samples = prsr.sub[item]
|
||||||
case _:
|
case _:
|
||||||
self.table_widget.formlayout.addWidget(QLabel(item.replace("_", " ").title()))
|
self.table_widget.formlayout.addWidget(QLabel(item.replace("_", " ").title()))
|
||||||
@@ -216,28 +217,7 @@ class App(QMainWindow):
|
|||||||
html += '</body></html>'
|
html += '</body></html>'
|
||||||
self.table_widget.webengineview.setHtml(html)
|
self.table_widget.webengineview.setHtml(html)
|
||||||
self.table_widget.webengineview.update()
|
self.table_widget.webengineview.update()
|
||||||
# type = self.table_widget.control_typer.currentText()
|
|
||||||
# mode = self.table_widget.mode_typer.currentText()
|
|
||||||
# controls = get_all_controls_by_type(ctx=self.ctx, type=type)
|
|
||||||
# data = []
|
|
||||||
# for control in controls:
|
|
||||||
# dicts = convert_control_by_mode(ctx=self.ctx, control=control, mode=mode)
|
|
||||||
# data.append(dicts)
|
|
||||||
# data = [item for sublist in data for item in sublist]
|
|
||||||
# # print(data)
|
|
||||||
# df = convert_data_list_to_df(ctx=self.ctx, input=data)
|
|
||||||
# fig = create_charts(ctx=self.ctx, df=df)
|
|
||||||
|
|
||||||
# print(fig)
|
|
||||||
# html = '<html><body>'
|
|
||||||
# html += plotly.offline.plot(fig, output_type='div', auto_open=True, image = 'png', image_filename='plot_image')
|
|
||||||
# html += '</body></html>'
|
|
||||||
# html = plotly.io.to_html(fig)
|
|
||||||
# # print(html)
|
|
||||||
# # with open("C:\\Users\\lwark\\Desktop\\test.html", "w") as f:
|
|
||||||
# # f.write(html)
|
|
||||||
# self.table_widget.webengineview.setHtml(html)
|
|
||||||
# self.table_widget.webengineview.update()
|
|
||||||
|
|
||||||
|
|
||||||
def submit_new_sample(self):
|
def submit_new_sample(self):
|
||||||
@@ -297,8 +277,8 @@ class App(QMainWindow):
|
|||||||
case QLineEdit():
|
case QLineEdit():
|
||||||
# ad hoc check to prevent double reporting of qdatedit under lineedit for some reason
|
# ad hoc check to prevent double reporting of qdatedit under lineedit for some reason
|
||||||
if not isinstance(prev_item, QDateEdit) and not isinstance(prev_item, QComboBox) and not isinstance(prev_item, QSpinBox):
|
if not isinstance(prev_item, QDateEdit) and not isinstance(prev_item, QComboBox) and not isinstance(prev_item, QSpinBox):
|
||||||
print(f"Previous: {prev_item}")
|
logger.debug(f"Previous: {prev_item}")
|
||||||
print(f"Item: {item}")
|
logger.debug(f"Item: {item}")
|
||||||
values.append(item.text())
|
values.append(item.text())
|
||||||
case QComboBox():
|
case QComboBox():
|
||||||
values.append(item.currentText())
|
values.append(item.currentText())
|
||||||
@@ -346,7 +326,7 @@ class App(QMainWindow):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
if self.table_widget.datepicker.start_date.date() > self.table_widget.datepicker.end_date.date():
|
if self.table_widget.datepicker.start_date.date() > self.table_widget.datepicker.end_date.date():
|
||||||
print("that is not allowed!")
|
logger.warning("Start date after end date is not allowed!")
|
||||||
# self.table_widget.datepicker.start_date.setDate(e_date)
|
# self.table_widget.datepicker.start_date.setDate(e_date)
|
||||||
threemonthsago = self.table_widget.datepicker.end_date.date().addDays(-90)
|
threemonthsago = self.table_widget.datepicker.end_date.date().addDays(-90)
|
||||||
with QSignalBlocker(self.table_widget.datepicker.start_date) as blocker:
|
with QSignalBlocker(self.table_widget.datepicker.start_date) as blocker:
|
||||||
@@ -372,12 +352,12 @@ class App(QMainWindow):
|
|||||||
|
|
||||||
|
|
||||||
def chart_maker(self):
|
def chart_maker(self):
|
||||||
print(f"Control getter context: \n\tControl type: {self.con_type}\n\tMode: {self.mode}\n\tStart Date: {self.start_date}\n\tEnd Date: {self.end_date}")
|
logger.debug(f"Control getter context: \n\tControl type: {self.con_type}\n\tMode: {self.mode}\n\tStart Date: {self.start_date}\n\tEnd Date: {self.end_date}")
|
||||||
if self.table_widget.sub_typer.currentText() == "":
|
if self.table_widget.sub_typer.currentText() == "":
|
||||||
self.subtype = None
|
self.subtype = None
|
||||||
else:
|
else:
|
||||||
self.subtype = self.table_widget.sub_typer.currentText()
|
self.subtype = self.table_widget.sub_typer.currentText()
|
||||||
print(f"Subtype: {self.subtype}")
|
logger.debug(f"Subtype: {self.subtype}")
|
||||||
controls = get_all_controls_by_type(ctx=self.ctx, con_type=self.con_type, start_date=self.start_date, end_date=self.end_date)
|
controls = get_all_controls_by_type(ctx=self.ctx, con_type=self.con_type, start_date=self.start_date, end_date=self.end_date)
|
||||||
if controls == None:
|
if controls == None:
|
||||||
return
|
return
|
||||||
@@ -386,14 +366,14 @@ class App(QMainWindow):
|
|||||||
dicts = convert_control_by_mode(ctx=self.ctx, control=control, mode=self.mode)
|
dicts = convert_control_by_mode(ctx=self.ctx, control=control, mode=self.mode)
|
||||||
data.append(dicts)
|
data.append(dicts)
|
||||||
data = [item for sublist in data for item in sublist]
|
data = [item for sublist in data for item in sublist]
|
||||||
# print(data)
|
# logger.debug(data)
|
||||||
df = convert_data_list_to_df(ctx=self.ctx, input=data, subtype=self.subtype)
|
df = convert_data_list_to_df(ctx=self.ctx, input=data, subtype=self.subtype)
|
||||||
if self.subtype == None:
|
if self.subtype == None:
|
||||||
title = self.mode
|
title = self.mode
|
||||||
else:
|
else:
|
||||||
title = f"{self.mode} - {self.subtype}"
|
title = f"{self.mode} - {self.subtype}"
|
||||||
fig = create_charts(ctx=self.ctx, df=df, ytitle=title)
|
fig = create_charts(ctx=self.ctx, df=df, ytitle=title)
|
||||||
print(f"Updating figure...")
|
logger.debug(f"Updating figure...")
|
||||||
html = '<html><body>'
|
html = '<html><body>'
|
||||||
if fig != None:
|
if fig != None:
|
||||||
html += plotly.offline.plot(fig, output_type='div', include_plotlyjs='cdn')#, image = 'png', auto_open=True, image_filename='plot_image')
|
html += plotly.offline.plot(fig, output_type='div', include_plotlyjs='cdn')#, image = 'png', auto_open=True, image_filename='plot_image')
|
||||||
@@ -404,7 +384,7 @@ class App(QMainWindow):
|
|||||||
# f.write(html)
|
# f.write(html)
|
||||||
self.table_widget.webengineview.setHtml(html)
|
self.table_widget.webengineview.setHtml(html)
|
||||||
self.table_widget.webengineview.update()
|
self.table_widget.webengineview.update()
|
||||||
print("Figure updated... I hope.")
|
logger.debug("Figure updated... I hope.")
|
||||||
|
|
||||||
|
|
||||||
# def datechange(self):
|
# def datechange(self):
|
||||||
@@ -412,7 +392,7 @@ class App(QMainWindow):
|
|||||||
# s_date = self.table_widget.datepicker.start_date.date()
|
# s_date = self.table_widget.datepicker.start_date.date()
|
||||||
# e_date = self.table_widget.datepicker.end_date.date()
|
# e_date = self.table_widget.datepicker.end_date.date()
|
||||||
# if s_date > e_date:
|
# if s_date > e_date:
|
||||||
# print("that is not allowed!")
|
# logger.debug("that is not allowed!")
|
||||||
# # self.table_widget.datepicker.start_date.setDate(e_date)
|
# # self.table_widget.datepicker.start_date.setDate(e_date)
|
||||||
# threemonthsago = e_date.addDays(-90)
|
# threemonthsago = e_date.addDays(-90)
|
||||||
# self.table_widget.datepicker.start_date.setDate(threemonthsago)
|
# self.table_widget.datepicker.start_date.setDate(threemonthsago)
|
||||||
@@ -448,6 +428,12 @@ class AddSubForm(QWidget):
|
|||||||
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)
|
||||||
|
|
||||||
|
self.interior = QScrollArea()
|
||||||
|
self.interior.setWidgetResizable(True)
|
||||||
|
self.interior.setFixedWidth(325)
|
||||||
|
self.interior.setParent(self.tab1)
|
||||||
|
self.interior.setWidget(self.formwidget)
|
||||||
|
|
||||||
self.sheetwidget = QWidget(self)
|
self.sheetwidget = QWidget(self)
|
||||||
self.sheetlayout = QVBoxLayout(self)
|
self.sheetlayout = QVBoxLayout(self)
|
||||||
@@ -455,22 +441,16 @@ class AddSubForm(QWidget):
|
|||||||
self.sub_wid = SubmissionsSheet(parent.ctx)
|
self.sub_wid = SubmissionsSheet(parent.ctx)
|
||||||
self.sheetlayout.addWidget(self.sub_wid)
|
self.sheetlayout.addWidget(self.sub_wid)
|
||||||
|
|
||||||
|
|
||||||
self.tab1.layout = QHBoxLayout(self)
|
self.tab1.layout = QHBoxLayout(self)
|
||||||
self.tab1.setLayout(self.tab1.layout)
|
self.tab1.setLayout(self.tab1.layout)
|
||||||
# self.tab1.layout.addLayout(self.formlayout)
|
# self.tab1.layout.addLayout(self.formlayout)
|
||||||
|
|
||||||
|
# self.tab1.layout.addWidget(self.formwidget)
|
||||||
self.tab1.layout.addWidget(self.formwidget)
|
self.tab1.layout.addWidget(self.formwidget)
|
||||||
self.tab1.layout.addWidget(self.sheetwidget)
|
self.tab1.layout.addWidget(self.sheetwidget)
|
||||||
# self.tab1.layout.addLayout(self.sheetlayout)
|
# self.tab1.layout.addLayout(self.sheetlayout)
|
||||||
# self.tab1.setWidgetResizable(True)
|
|
||||||
# self.tab1.setVerticalScrollBar(QScrollBar())
|
|
||||||
# self.tab1.layout.addWidget(self.scroller)
|
|
||||||
# self.tab1.setWidget(self.scroller)
|
|
||||||
# self.tab1.setMinimumHeight(300)
|
|
||||||
self.datepicker = ControlsDatePicker()
|
self.datepicker = ControlsDatePicker()
|
||||||
self.webengineview = QWebEngineView()
|
self.webengineview = QWebEngineView()
|
||||||
# data = '''<html>Hello World</html>'''
|
|
||||||
# self.webengineview.setHtml(data)
|
|
||||||
self.tab2.layout = QVBoxLayout(self)
|
self.tab2.layout = QVBoxLayout(self)
|
||||||
self.control_typer = QComboBox()
|
self.control_typer = QComboBox()
|
||||||
con_types = get_all_Control_Types_names(ctx=parent.ctx)
|
con_types = get_all_Control_Types_names(ctx=parent.ctx)
|
||||||
@@ -493,3 +473,5 @@ class AddSubForm(QWidget):
|
|||||||
self.tab3.setLayout(self.tab3.layout)
|
self.tab3.setLayout(self.tab3.layout)
|
||||||
self.layout.addWidget(self.tabs)
|
self.layout.addWidget(self.tabs)
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
print(self.tab1.layout.parentWidget().findChildren(QScrollArea))
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ from jinja2 import Environment, FileSystemLoader
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
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")
|
||||||
@@ -62,7 +65,7 @@ class AddReagentForm(QDialog):
|
|||||||
exp_input.setDate(QDate.currentDate())
|
exp_input.setDate(QDate.currentDate())
|
||||||
type_input = QComboBox()
|
type_input = QComboBox()
|
||||||
type_input.addItems([item.replace("_", " ").title() for item in get_all_reagenttype_names(ctx=ctx)])
|
type_input.addItems([item.replace("_", " ").title() for item in get_all_reagenttype_names(ctx=ctx)])
|
||||||
print(f"Trying to find index of {reagent_type}")
|
logger.debug(f"Trying to find index of {reagent_type}")
|
||||||
try:
|
try:
|
||||||
reagent_type = reagent_type.replace("_", " ").title()
|
reagent_type = reagent_type.replace("_", " ").title()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@@ -132,7 +135,7 @@ class SubmissionsSheet(QTableView):
|
|||||||
|
|
||||||
def show_details(self, item):
|
def show_details(self, item):
|
||||||
index=(self.selectionModel().currentIndex())
|
index=(self.selectionModel().currentIndex())
|
||||||
# print(index)
|
# logger.debug(index)
|
||||||
value=index.sibling(index.row(),0).data()
|
value=index.sibling(index.row(),0).data()
|
||||||
dlg = SubmissionDetails(ctx=self.ctx, id=value)
|
dlg = SubmissionDetails(ctx=self.ctx, id=value)
|
||||||
# dlg.show()
|
# dlg.show()
|
||||||
@@ -245,7 +248,7 @@ class KitAdder(QWidget):
|
|||||||
def submit(self):
|
def submit(self):
|
||||||
labels, values, reagents = self.extract_form_info(self)
|
labels, values, reagents = self.extract_form_info(self)
|
||||||
info = {item[0]:item[1] for item in zip(labels, values)}
|
info = {item[0]:item[1] for item in zip(labels, values)}
|
||||||
print(info)
|
logger.debug(info)
|
||||||
# info['reagenttypes'] = reagents
|
# info['reagenttypes'] = reagents
|
||||||
# del info['name']
|
# del info['name']
|
||||||
# del info['extension_of_life_(months)']
|
# del info['extension_of_life_(months)']
|
||||||
@@ -257,7 +260,7 @@ class KitAdder(QWidget):
|
|||||||
yml_type[used]['kits'][info['kit_name']] = {}
|
yml_type[used]['kits'][info['kit_name']] = {}
|
||||||
yml_type[used]['kits'][info['kit_name']]['cost'] = info['cost_per_run']
|
yml_type[used]['kits'][info['kit_name']]['cost'] = info['cost_per_run']
|
||||||
yml_type[used]['kits'][info['kit_name']]['reagenttypes'] = reagents
|
yml_type[used]['kits'][info['kit_name']]['reagenttypes'] = reagents
|
||||||
print(yml_type)
|
logger.debug(yml_type)
|
||||||
create_kit_from_yaml(ctx=self.ctx, exp=yml_type)
|
create_kit_from_yaml(ctx=self.ctx, exp=yml_type)
|
||||||
|
|
||||||
def extract_form_info(self, object):
|
def extract_form_info(self, object):
|
||||||
@@ -265,7 +268,7 @@ class KitAdder(QWidget):
|
|||||||
values = []
|
values = []
|
||||||
reagents = {}
|
reagents = {}
|
||||||
for item in object.findChildren(QWidget):
|
for item in object.findChildren(QWidget):
|
||||||
print(item.parentWidget())
|
logger.debug(item.parentWidget())
|
||||||
# if not isinstance(item.parentWidget(), ReagentTypeForm):
|
# if not isinstance(item.parentWidget(), ReagentTypeForm):
|
||||||
match item:
|
match item:
|
||||||
case QLabel():
|
case QLabel():
|
||||||
@@ -273,8 +276,8 @@ class KitAdder(QWidget):
|
|||||||
case QLineEdit():
|
case QLineEdit():
|
||||||
# ad hoc check to prevent double reporting of qdatedit under lineedit for some reason
|
# ad hoc check to prevent double reporting of qdatedit under lineedit for some reason
|
||||||
if not isinstance(prev_item, QDateEdit) and not isinstance(prev_item, QComboBox) and not isinstance(prev_item, QSpinBox) and not isinstance(prev_item, QScrollBar):
|
if not isinstance(prev_item, QDateEdit) and not isinstance(prev_item, QComboBox) and not isinstance(prev_item, QSpinBox) and not isinstance(prev_item, QScrollBar):
|
||||||
print(f"Previous: {prev_item}")
|
logger.debug(f"Previous: {prev_item}")
|
||||||
print(f"Item: {item}, {item.text()}")
|
logger.debug(f"Item: {item}, {item.text()}")
|
||||||
values.append(item.text())
|
values.append(item.text())
|
||||||
case QComboBox():
|
case QComboBox():
|
||||||
values.append(item.currentText())
|
values.append(item.currentText())
|
||||||
@@ -286,7 +289,7 @@ class KitAdder(QWidget):
|
|||||||
|
|
||||||
re_labels, re_values, _ = self.extract_form_info(item)
|
re_labels, re_values, _ = self.extract_form_info(item)
|
||||||
reagent = {item[0]:item[1] for item in zip(re_labels, re_values)}
|
reagent = {item[0]:item[1] for item in zip(re_labels, re_values)}
|
||||||
print(reagent)
|
logger.debug(reagent)
|
||||||
# reagent = {reagent['name:']:{'eol':reagent['extension_of_life_(months):']}}
|
# reagent = {reagent['name:']:{'eol':reagent['extension_of_life_(months):']}}
|
||||||
reagents[reagent['name']] = {'eol_ext':int(reagent['extension_of_life_(months)'])}
|
reagents[reagent['name']] = {'eol_ext':int(reagent['extension_of_life_(months)'])}
|
||||||
prev_item = item
|
prev_item = item
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from plotly.graph_objects import Figure
|
|||||||
import logging
|
import logging
|
||||||
from backend.excel import get_unique_values_in_df_column
|
from backend.excel import get_unique_values_in_df_column
|
||||||
|
|
||||||
logger = logging.getLogger("controls.tools.vis_functions")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
|
|
||||||
def create_charts(ctx:dict, df:pd.DataFrame, ytitle:str|None=None) -> Figure:
|
def create_charts(ctx:dict, df:pd.DataFrame, ytitle:str|None=None) -> Figure:
|
||||||
@@ -160,7 +160,7 @@ def construct_chart(ctx:dict, df:pd.DataFrame, modes:list, ytitle:str|None=None)
|
|||||||
color_discrete_sequence=None
|
color_discrete_sequence=None
|
||||||
else:
|
else:
|
||||||
color = "target"
|
color = "target"
|
||||||
print(get_unique_values_in_df_column(df, 'target'))
|
# print(get_unique_values_in_df_column(df, 'target'))
|
||||||
match get_unique_values_in_df_column(df, 'target'):
|
match get_unique_values_in_df_column(df, 'target'):
|
||||||
case ['Target']:
|
case ['Target']:
|
||||||
color_discrete_sequence=["blue"]
|
color_discrete_sequence=["blue"]
|
||||||
|
|||||||
Reference in New Issue
Block a user