post documentation and code clean-up.
This commit is contained in:
@@ -9,6 +9,7 @@ def set_sqlite_pragma(dbapi_connection, connection_record):
|
||||
"""
|
||||
*should* allow automatic creation of foreign keys in the database
|
||||
I have no idea how it actually works.
|
||||
Listens for connect and then turns on foreign keys?
|
||||
|
||||
Args:
|
||||
dbapi_connection (_type_): _description_
|
||||
|
||||
@@ -1581,12 +1581,12 @@ class WastewaterArtic(BasicSubmission):
|
||||
dict: dictionary used in submissions summary
|
||||
"""
|
||||
output = super().to_dict(full_data=full_data, backup=backup, report=report)
|
||||
if report:
|
||||
return output
|
||||
if self.artic_technician in [None, "None"]:
|
||||
output['artic_technician'] = self.technician
|
||||
else:
|
||||
output['artic_technician'] = self.artic_technician
|
||||
if report:
|
||||
return output
|
||||
output['gel_info'] = self.gel_info
|
||||
output['gel_image_path'] = self.gel_image
|
||||
output['dna_core_submission_number'] = self.dna_core_submission_number
|
||||
@@ -2253,6 +2253,12 @@ class BasicSample(BaseClass):
|
||||
|
||||
@classmethod
|
||||
def get_searchables(cls):
|
||||
"""
|
||||
Delivers a list of fields that can be used in fuzzy search.
|
||||
|
||||
Returns:
|
||||
List[str]: List of fields.
|
||||
"""
|
||||
return [dict(label="Submitter ID", field="submitter_id")]
|
||||
|
||||
@classmethod
|
||||
@@ -2381,22 +2387,14 @@ class WastewaterSample(BasicSample):
|
||||
output_dict["submitter_id"] = output_dict['ww_full_sample_id']
|
||||
return output_dict
|
||||
|
||||
def get_previous_ww_submission(self, current_artic_submission: WastewaterArtic):
|
||||
try:
|
||||
plates = [item['plate'] for item in current_artic_submission.source_plates]
|
||||
except TypeError as e:
|
||||
logger.error(f"source_plates must not be present")
|
||||
plates = [item.rsl_plate_num for item in
|
||||
self.submissions[:self.submissions.index(current_artic_submission)]]
|
||||
subs = [sub for sub in self.submissions if sub.rsl_plate_num in plates]
|
||||
# logger.debug(f"Submissions: {subs}")
|
||||
try:
|
||||
return subs[-1]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_searchables(cls):
|
||||
def get_searchables(cls) -> List[str]:
|
||||
"""
|
||||
Delivers a list of fields that can be used in fuzzy search. Extends parent.
|
||||
|
||||
Returns:
|
||||
List[str]: List of fields.
|
||||
"""
|
||||
searchables = super().get_searchables()
|
||||
for item in ["ww_processing_num", "ww_full_sample_id", "rsl_number"]:
|
||||
label = item.strip("ww_").replace("_", " ").replace("rsl", "RSL").title()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'''
|
||||
Contains pandas convenience functions for interacting with excel workbooks
|
||||
Contains pandas and openpyxl convenience functions for interacting with excel workbooks
|
||||
'''
|
||||
|
||||
from .reports import *
|
||||
from .parser import *
|
||||
from .writer import *
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'''
|
||||
contains parser object for pulling values from client generated submission sheets.
|
||||
contains parser objects for pulling values from client generated submission sheets.
|
||||
'''
|
||||
import sys
|
||||
from copy import copy
|
||||
@@ -78,7 +78,7 @@ class SheetParser(object):
|
||||
|
||||
def parse_reagents(self, extraction_kit: str | None = None):
|
||||
"""
|
||||
Pulls reagent info from the excel sheet
|
||||
Calls reagent parser class to pull info from the excel sheet
|
||||
|
||||
Args:
|
||||
extraction_kit (str | None, optional): Relevant extraction kit for reagent map. Defaults to None.
|
||||
@@ -91,16 +91,22 @@ class SheetParser(object):
|
||||
|
||||
def parse_samples(self):
|
||||
"""
|
||||
Pulls sample info from the excel sheet
|
||||
Calls sample parser to pull info from the excel sheet
|
||||
"""
|
||||
parser = SampleParser(xl=self.xl, submission_type=self.submission_type)
|
||||
self.sub['samples'] = parser.reconcile_samples()
|
||||
|
||||
def parse_equipment(self):
|
||||
"""
|
||||
Calls equipment parser to pull info from the excel sheet
|
||||
"""
|
||||
parser = EquipmentParser(xl=self.xl, submission_type=self.submission_type)
|
||||
self.sub['equipment'] = parser.parse_equipment()
|
||||
|
||||
def parse_tips(self):
|
||||
"""
|
||||
Calls tips parser to pull info from the excel sheet
|
||||
"""
|
||||
parser = TipParser(xl=self.xl, submission_type=self.submission_type)
|
||||
self.sub['tips'] = parser.parse_tips()
|
||||
|
||||
@@ -160,8 +166,16 @@ class SheetParser(object):
|
||||
|
||||
|
||||
class InfoParser(object):
|
||||
|
||||
"""
|
||||
Object to parse generic info from excel sheet.
|
||||
"""
|
||||
def __init__(self, xl: Workbook, submission_type: str|SubmissionType, sub_object: BasicSubmission|None=None):
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (str | SubmissionType): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
sub_object (BasicSubmission | None, optional): Submission object holding methods. Defaults to None.
|
||||
"""
|
||||
logger.info(f"\n\nHello from InfoParser!\n\n")
|
||||
if isinstance(submission_type, str):
|
||||
submission_type = SubmissionType.query(name=submission_type)
|
||||
@@ -221,6 +235,7 @@ class InfoParser(object):
|
||||
new['name'] = k
|
||||
relevant.append(new)
|
||||
# logger.debug(f"relevant map for {sheet}: {pformat(relevant)}")
|
||||
# NOTE: make sure relevant is not an empty list.
|
||||
if not relevant:
|
||||
continue
|
||||
for item in relevant:
|
||||
@@ -231,6 +246,7 @@ class InfoParser(object):
|
||||
case "submission_type":
|
||||
value, missing = is_missing(value)
|
||||
value = value.title()
|
||||
# NOTE: is field a JSON?
|
||||
case thing if thing in self.sub_object.jsons():
|
||||
value, missing = is_missing(value)
|
||||
if missing: continue
|
||||
@@ -248,12 +264,23 @@ class InfoParser(object):
|
||||
dicto[item['name']] = dict(value=value, missing=missing)
|
||||
except (KeyError, IndexError):
|
||||
continue
|
||||
# Return after running the parser components held in submission object.
|
||||
return self.sub_object.custom_info_parser(input_dict=dicto, xl=self.xl)
|
||||
|
||||
|
||||
class ReagentParser(object):
|
||||
"""
|
||||
Object to pull reagents from excel sheet.
|
||||
"""
|
||||
|
||||
def __init__(self, xl: Workbook, submission_type: str, extraction_kit: str, sub_object:BasicSubmission|None=None):
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (str): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
extraction_kit (str): Extraction kit used.
|
||||
sub_object (BasicSubmission | None, optional): Submission object holding methods. Defaults to None.
|
||||
"""
|
||||
# logger.debug("\n\nHello from ReagentParser!\n\n")
|
||||
self.submission_type_obj = submission_type
|
||||
self.sub_object = sub_object
|
||||
@@ -284,7 +311,7 @@ class ReagentParser(object):
|
||||
pass
|
||||
return reagent_map
|
||||
|
||||
def parse_reagents(self) -> List[PydReagent]:
|
||||
def parse_reagents(self) -> List[dict]:
|
||||
"""
|
||||
Extracts reagent information from the excel form.
|
||||
|
||||
@@ -312,7 +339,7 @@ class ReagentParser(object):
|
||||
comment = ""
|
||||
except (KeyError, IndexError):
|
||||
listo.append(
|
||||
PydReagent(role=item.strip(), lot=None, expiry=None, name=None, comment="", missing=True))
|
||||
dict(role=item.strip(), lot=None, expiry=None, name=None, comment="", missing=True))
|
||||
continue
|
||||
# NOTE: If the cell is blank tell the PydReagent
|
||||
if check_not_nan(lot):
|
||||
@@ -336,17 +363,17 @@ class ReagentParser(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
|
||||
"""
|
||||
|
||||
def __init__(self, xl: Workbook, submission_type: SubmissionType, sample_map: dict | None = None, sub_object:BasicSubmission|None=None) -> None:
|
||||
"""
|
||||
convert sample sub-dataframe to dictionary of records
|
||||
|
||||
Args:
|
||||
df (pd.DataFrame): input sample dataframe
|
||||
elution_map (pd.DataFrame | None, optional): optional map of elution plate. Defaults to None.
|
||||
"""
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (SubmissionType): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
sample_map (dict | None, optional): Locations in database where samples are found. Defaults to None.
|
||||
sub_object (BasicSubmission | None, optional): Submission object holding methods. Defaults to None.
|
||||
"""
|
||||
# logger.debug("\n\nHello from SampleParser!\n\n")
|
||||
self.samples = []
|
||||
self.xl = xl
|
||||
@@ -383,10 +410,13 @@ class SampleParser(object):
|
||||
sample_info_map = sample_map
|
||||
return sample_info_map
|
||||
|
||||
def parse_plate_map(self):
|
||||
def parse_plate_map(self) -> List[dict]:
|
||||
"""
|
||||
Parse sample location/name from plate map
|
||||
"""
|
||||
|
||||
Returns:
|
||||
List[dict]: List of sample ids and locations.
|
||||
"""
|
||||
invalids = [0, "0", "EMPTY"]
|
||||
smap = self.sample_info_map['plate_map']
|
||||
ws = self.xl[smap['sheet']]
|
||||
@@ -412,7 +442,11 @@ class SampleParser(object):
|
||||
def parse_lookup_table(self) -> List[dict]:
|
||||
"""
|
||||
Parse misc info from lookup table.
|
||||
"""
|
||||
|
||||
Returns:
|
||||
List[dict]: List of basic sample info.
|
||||
"""
|
||||
|
||||
lmap = self.sample_info_map['lookup_table']
|
||||
ws = self.xl[lmap['sheet']]
|
||||
lookup_samples = []
|
||||
@@ -460,7 +494,13 @@ class SampleParser(object):
|
||||
new_samples.append(PydSample(**translated_dict))
|
||||
return result, new_samples
|
||||
|
||||
def reconcile_samples(self):
|
||||
def reconcile_samples(self) -> List[dict]:
|
||||
"""
|
||||
Merges sample info from lookup table and plate map.
|
||||
|
||||
Returns:
|
||||
List[dict]: Reconciled samples
|
||||
"""
|
||||
# TODO: Move to pydantic validator?
|
||||
if self.plate_map_samples is None or self.lookup_samples is None:
|
||||
self.samples = self.lookup_samples or self.plate_map_samples
|
||||
@@ -504,8 +544,15 @@ class SampleParser(object):
|
||||
|
||||
|
||||
class EquipmentParser(object):
|
||||
|
||||
"""
|
||||
Object to pull data for equipment in excel sheet
|
||||
"""
|
||||
def __init__(self, xl: Workbook, submission_type: str|SubmissionType) -> None:
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (str | SubmissionType): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
"""
|
||||
if isinstance(submission_type, str):
|
||||
submission_type = SubmissionType.query(name=submission_type)
|
||||
self.submission_type = submission_type
|
||||
@@ -582,8 +629,15 @@ class EquipmentParser(object):
|
||||
|
||||
|
||||
class TipParser(object):
|
||||
|
||||
"""
|
||||
Object to pull data for tips in excel sheet
|
||||
"""
|
||||
def __init__(self, xl: Workbook, submission_type: str|SubmissionType) -> None:
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (str | SubmissionType): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
"""
|
||||
if isinstance(submission_type, str):
|
||||
submission_type = SubmissionType.query(name=submission_type)
|
||||
self.submission_type = submission_type
|
||||
@@ -644,8 +698,6 @@ class PCRParser(object):
|
||||
|
||||
def __init__(self, filepath: Path | None=None, submission: BasicSubmission | None=None) -> None:
|
||||
"""
|
||||
Initializes object.
|
||||
|
||||
Args:
|
||||
filepath (Path | None, optional): file to parse. Defaults to None.
|
||||
"""
|
||||
|
||||
@@ -90,6 +90,13 @@ class ReportMaker(object):
|
||||
return html
|
||||
|
||||
def write_report(self, filename: Path | str, obj: QWidget | None = None):
|
||||
"""
|
||||
Writes info to files.
|
||||
|
||||
Args:
|
||||
filename (Path | str): Basename of output file
|
||||
obj (QWidget | None, optional): Parent object. Defaults to None.
|
||||
"""
|
||||
if isinstance(filename, str):
|
||||
filename = Path(filename)
|
||||
filename = filename.absolute()
|
||||
@@ -108,6 +115,9 @@ class ReportMaker(object):
|
||||
self.writer.close()
|
||||
|
||||
def fix_up_xl(self):
|
||||
"""
|
||||
Handles formatting of xl file.
|
||||
"""
|
||||
# logger.debug(f"Updating worksheet")
|
||||
worksheet: Worksheet = self.writer.sheets['Report']
|
||||
for idx, col in enumerate(self.summary_df, start=1): # loop through all columns
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
'''
|
||||
contains writer objects for pushing values to submission sheet templates.
|
||||
'''
|
||||
import logging
|
||||
from copy import copy
|
||||
from operator import itemgetter
|
||||
@@ -27,8 +30,9 @@ class SheetWriter(object):
|
||||
def __init__(self, submission: PydSubmission, missing_only: bool = False):
|
||||
"""
|
||||
Args:
|
||||
filepath (Path | None, optional): file path to excel sheet. Defaults to None.
|
||||
"""
|
||||
submission (PydSubmission): Object containing submission information.
|
||||
missing_only (bool, optional): Whether to only fill in missing values. Defaults to False.
|
||||
"""
|
||||
self.sub = OrderedDict(submission.improved_dict())
|
||||
for k, v in self.sub.items():
|
||||
match k:
|
||||
@@ -116,6 +120,13 @@ class InfoWriter(object):
|
||||
|
||||
def __init__(self, xl: Workbook, submission_type: SubmissionType | str, info_dict: dict,
|
||||
sub_object: BasicSubmission | None = None):
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (SubmissionType | str): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
info_dict (dict): Dictionary of information to write.
|
||||
sub_object (BasicSubmission | None, optional): Submission object containing methods. Defaults to None.
|
||||
"""
|
||||
logger.debug(f"Info_dict coming into InfoWriter: {pformat(info_dict)}")
|
||||
if isinstance(submission_type, str):
|
||||
submission_type = SubmissionType.query(name=submission_type)
|
||||
@@ -186,6 +197,13 @@ class ReagentWriter(object):
|
||||
|
||||
def __init__(self, xl: Workbook, submission_type: SubmissionType | str, extraction_kit: KitType | str,
|
||||
reagent_list: list):
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (SubmissionType | str): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
extraction_kit (KitType | str): Extraction kit used.
|
||||
reagent_list (list): List of reagent dicts to be written to excel.
|
||||
"""
|
||||
self.xl = xl
|
||||
if isinstance(submission_type, str):
|
||||
submission_type = SubmissionType.query(name=submission_type)
|
||||
@@ -245,8 +263,13 @@ class SampleWriter(object):
|
||||
"""
|
||||
object to write sample data into excel file
|
||||
"""
|
||||
|
||||
def __init__(self, xl: Workbook, submission_type: SubmissionType | str, sample_list: list):
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (SubmissionType | str): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
sample_list (list): List of sample dictionaries to be written to excel file.
|
||||
"""
|
||||
if isinstance(submission_type, str):
|
||||
submission_type = SubmissionType.query(name=submission_type)
|
||||
self.submission_type = submission_type
|
||||
@@ -303,6 +326,12 @@ class EquipmentWriter(object):
|
||||
"""
|
||||
|
||||
def __init__(self, xl: Workbook, submission_type: SubmissionType | str, equipment_list: list):
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (SubmissionType | str): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
equipment_list (list): List of equipment dictionaries to write to excel file.
|
||||
"""
|
||||
if isinstance(submission_type, str):
|
||||
submission_type = SubmissionType.query(name=submission_type)
|
||||
self.submission_type = submission_type
|
||||
@@ -385,6 +414,12 @@ class TipWriter(object):
|
||||
"""
|
||||
|
||||
def __init__(self, xl: Workbook, submission_type: SubmissionType | str, tips_list: list):
|
||||
"""
|
||||
Args:
|
||||
xl (Workbook): Openpyxl workbook from submitted excel file.
|
||||
submission_type (SubmissionType | str): Type of submission expected (Wastewater, Bacterial Culture, etc.)
|
||||
tips_list (list): List of tip dictionaries to write to the excel file.
|
||||
"""
|
||||
if isinstance(submission_type, str):
|
||||
submission_type = SubmissionType.query(name=submission_type)
|
||||
self.submission_type = submission_type
|
||||
@@ -460,8 +495,15 @@ class TipWriter(object):
|
||||
|
||||
|
||||
class DocxWriter(object):
|
||||
"""
|
||||
Object to render
|
||||
"""
|
||||
|
||||
def __init__(self, base_dict: dict):
|
||||
"""
|
||||
Args:
|
||||
base_dict (dict): dictionary of info to be written to template.
|
||||
"""
|
||||
self.sub_obj = BasicSubmission.find_polymorphic_subclass(polymorphic_identity=base_dict['submission_type'])
|
||||
env = jinja_template_loading()
|
||||
temp_name = f"{base_dict['submission_type'].replace(' ', '').lower()}_subdocument.docx"
|
||||
@@ -506,7 +548,13 @@ class DocxWriter(object):
|
||||
output.append(contents)
|
||||
return output
|
||||
|
||||
def create_merged_template(self, *args):
|
||||
def create_merged_template(self, *args) -> BytesIO:
|
||||
"""
|
||||
Appends submission specific information
|
||||
|
||||
Returns:
|
||||
BytesIO: Merged docx template
|
||||
"""
|
||||
merged_document = Document()
|
||||
output = BytesIO()
|
||||
for index, file in enumerate(args):
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
'''
|
||||
Contains all validators
|
||||
'''
|
||||
import logging, re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -3,21 +3,18 @@ Contains pydantic models and accompanying validators
|
||||
'''
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
from operator import attrgetter
|
||||
import uuid, re, logging
|
||||
from pydantic import BaseModel, field_validator, Field, model_validator, PrivateAttr
|
||||
import uuid, re, logging, csv
|
||||
from pydantic import BaseModel, field_validator, Field, model_validator
|
||||
from datetime import date, datetime, timedelta
|
||||
from dateutil.parser import parse
|
||||
from dateutil.parser import ParserError
|
||||
from typing import List, Tuple, Literal
|
||||
from . import RSLNamer
|
||||
from pathlib import Path
|
||||
from tools import check_not_nan, convert_nans_to_nones, Report, Result, row_map
|
||||
from tools import check_not_nan, convert_nans_to_nones, Report, Result
|
||||
from backend.db.models import *
|
||||
from sqlalchemy.exc import StatementError, IntegrityError
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
from openpyxl import load_workbook, Workbook
|
||||
from io import BytesIO
|
||||
|
||||
logger = logging.getLogger(f"submissions.{__name__}")
|
||||
|
||||
@@ -106,20 +103,17 @@ class PydReagent(BaseModel):
|
||||
return values.data['role']
|
||||
|
||||
def improved_dict(self) -> dict:
|
||||
"""
|
||||
Constructs a dictionary consisting of model.fields and model.extras
|
||||
|
||||
Returns:
|
||||
dict: Information dictionary
|
||||
"""
|
||||
try:
|
||||
extras = list(self.model_extra.keys())
|
||||
except AttributeError:
|
||||
extras = []
|
||||
fields = list(self.model_fields.keys()) + extras
|
||||
# output = {}
|
||||
# for k in fields:
|
||||
# value = getattr(self, k)
|
||||
# match value:
|
||||
# case date():
|
||||
# value = value.strftime("%Y-%m-%d")
|
||||
# case _:
|
||||
# pass
|
||||
# output[k] = value
|
||||
return {k: getattr(self, k) for k in fields}
|
||||
|
||||
def toSQL(self, submission: BasicSubmission | str = None) -> Tuple[Reagent, SubmissionReagentAssociation, Report]:
|
||||
@@ -142,7 +136,7 @@ class PydReagent(BaseModel):
|
||||
if isinstance(value, dict):
|
||||
value = value['value']
|
||||
# logger.debug(f"Reagent info item for {key}: {value}")
|
||||
# set fields based on keys in dictionary
|
||||
# NOTE: set fields based on keys in dictionary
|
||||
match key:
|
||||
case "lot":
|
||||
reagent.lot = value.upper()
|
||||
@@ -177,11 +171,9 @@ class PydReagent(BaseModel):
|
||||
assoc = None
|
||||
# add end-of-life extension from reagent type to expiry date
|
||||
# NOTE: this will now be done only in the reporting phase to account for potential changes in end-of-life extensions
|
||||
|
||||
return reagent, assoc, report
|
||||
|
||||
|
||||
|
||||
class PydSample(BaseModel, extra='allow'):
|
||||
submitter_id: str
|
||||
sample_type: str
|
||||
@@ -220,6 +212,12 @@ class PydSample(BaseModel, extra='allow'):
|
||||
return str(value)
|
||||
|
||||
def improved_dict(self) -> dict:
|
||||
"""
|
||||
Constructs a dictionary consisting of model.fields and model.extras
|
||||
|
||||
Returns:
|
||||
dict: Information dictionary
|
||||
"""
|
||||
fields = list(self.model_fields.keys()) + list(self.model_extra.keys())
|
||||
return {k: getattr(self, k) for k in fields}
|
||||
|
||||
@@ -249,7 +247,6 @@ class PydSample(BaseModel, extra='allow'):
|
||||
if isinstance(submission, str):
|
||||
submission = BasicSubmission.query(rsl_plate_num=submission)
|
||||
assoc_type = submission.submission_type_name
|
||||
# assoc_type = self.sample_type.replace("Sample", "").strip()
|
||||
for row, column, aid, submission_rank in zip(self.row, self.column, self.assoc_id, self.submission_rank):
|
||||
# logger.debug(f"Looking up association with identity: ({submission.submission_type_name} Association)")
|
||||
# logger.debug(f"Looking up association with identity: ({assoc_type} Association)")
|
||||
@@ -268,6 +265,12 @@ class PydSample(BaseModel, extra='allow'):
|
||||
return instance, out_associations, report
|
||||
|
||||
def improved_dict(self) -> dict:
|
||||
"""
|
||||
Constructs a dictionary consisting of model.fields and model.extras
|
||||
|
||||
Returns:
|
||||
dict: Information dictionary
|
||||
"""
|
||||
try:
|
||||
extras = list(self.model_extra.keys())
|
||||
except AttributeError:
|
||||
@@ -281,7 +284,16 @@ class PydTips(BaseModel):
|
||||
lot: str|None = Field(default=None)
|
||||
role: str
|
||||
|
||||
def to_sql(self, submission:BasicSubmission):
|
||||
def to_sql(self, submission:BasicSubmission) -> SubmissionTipsAssociation:
|
||||
"""
|
||||
Con
|
||||
|
||||
Args:
|
||||
submission (BasicSubmission): A submission object to associate tips represented here.
|
||||
|
||||
Returns:
|
||||
SubmissionTipsAssociation: Association between queried tips and submission
|
||||
"""
|
||||
tips = Tips.query(name=self.name, lot=self.lot, limit=1)
|
||||
assoc = SubmissionTipsAssociation(submission=submission, tips=tips, role_name=self.role)
|
||||
return assoc
|
||||
@@ -348,6 +360,12 @@ class PydEquipment(BaseModel, extra='ignore'):
|
||||
return equipment, assoc
|
||||
|
||||
def improved_dict(self) -> dict:
|
||||
"""
|
||||
Constructs a dictionary consisting of model.fields and model.extras
|
||||
|
||||
Returns:
|
||||
dict: Information dictionary
|
||||
"""
|
||||
try:
|
||||
extras = list(self.model_extra.keys())
|
||||
except AttributeError:
|
||||
@@ -619,7 +637,14 @@ class PydSubmission(BaseModel, extra='allow'):
|
||||
self.submission_object = BasicSubmission.find_polymorphic_subclass(
|
||||
polymorphic_identity=self.submission_type['value'])
|
||||
|
||||
def set_attribute(self, key, value):
|
||||
def set_attribute(self, key:str, value):
|
||||
"""
|
||||
Better handling of attribute setting.
|
||||
|
||||
Args:
|
||||
key (str): Name of field to set
|
||||
value (_type_): Value to set field to.
|
||||
"""
|
||||
self.__setattr__(name=key, value=value)
|
||||
|
||||
def handle_duplicate_samples(self):
|
||||
@@ -775,15 +800,14 @@ class PydSubmission(BaseModel, extra='allow'):
|
||||
except AttributeError:
|
||||
instance.run_cost = 0
|
||||
# logger.debug(f"Calculated base run cost of: {instance.run_cost}")
|
||||
# Apply any discounts that are applicable for client and kit.
|
||||
# NOTE: Apply any discounts that are applicable for client and kit.
|
||||
try:
|
||||
# logger.debug("Checking and applying discounts...")
|
||||
discounts = [item.amount for item in
|
||||
Discount.query(kit_type=instance.extraction_kit, organization=instance.submitting_lab)]
|
||||
# logger.debug(f"We got discounts: {discounts}")
|
||||
if len(discounts) > 0:
|
||||
discounts = sum(discounts)
|
||||
instance.run_cost = instance.run_cost - discounts
|
||||
instance.run_cost = instance.run_cost - sum(discounts)
|
||||
except Exception as e:
|
||||
logger.error(f"An unknown exception occurred when calculating discounts: {e}")
|
||||
# We need to make sure there's a proper rsl plate number
|
||||
@@ -808,7 +832,13 @@ class PydSubmission(BaseModel, extra='allow'):
|
||||
from frontend.widgets.submission_widget import SubmissionFormWidget
|
||||
return SubmissionFormWidget(parent=parent, submission=self)
|
||||
|
||||
def to_writer(self):
|
||||
def to_writer(self) -> "SheetWriter":
|
||||
"""
|
||||
Sends data here to the sheet writer.
|
||||
|
||||
Returns:
|
||||
SheetWriter: Sheetwriter object that will perform writing.
|
||||
"""
|
||||
from backend.excel.writer import SheetWriter
|
||||
return SheetWriter(self)
|
||||
|
||||
@@ -866,6 +896,19 @@ class PydSubmission(BaseModel, extra='allow'):
|
||||
status="Warning")
|
||||
report.add_result(result)
|
||||
return output_reagents, report
|
||||
|
||||
def export_csv(self, filename:Path|str):
|
||||
try:
|
||||
worksheet = self.csv
|
||||
except AttributeError:
|
||||
logger.error("No csv found.")
|
||||
return
|
||||
if isinstance(filename, str):
|
||||
filename = Path(filename)
|
||||
with open(filename, 'w', newline="") as f:
|
||||
c = csv.writer(f)
|
||||
for r in worksheet.rows:
|
||||
c.writerow([cell.value for cell in r])
|
||||
|
||||
|
||||
class PydContact(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user