Moments before disaster.

This commit is contained in:
lwark
2024-10-09 12:44:06 -05:00
parent ae5fb1b48f
commit 066d1af0f2
5 changed files with 101 additions and 6 deletions

View File

@@ -84,7 +84,7 @@ class ControlType(BaseClass):
Returns: Returns:
List[ControlType]: Control types that have targets List[ControlType]: Control types that have targets
""" """
return [item for item in cls.query() if item.targets] return (item for item in cls.query() if item.targets)
@classmethod @classmethod
def build_positive_regex(cls) -> Pattern: def build_positive_regex(cls) -> Pattern:

View File

@@ -506,7 +506,7 @@ class BasicSubmission(BaseClass):
Returns: Returns:
List[str]: List of names List[str]: List of names
""" """
return [item.role for item in self.submission_equipment_associations] return (item.role for item in self.submission_equipment_associations)
@classmethod @classmethod
def submissions_to_df(cls, submission_type: str | None = None, limit: int = 0, def submissions_to_df(cls, submission_type: str | None = None, limit: int = 0,
@@ -527,7 +527,8 @@ class BasicSubmission(BaseClass):
# logger.debug(f"Using limit: {limit}") # logger.debug(f"Using limit: {limit}")
# NOTE: use lookup function to create list of dicts # NOTE: use lookup function to create list of dicts
subs = [item.to_dict() for item in subs = [item.to_dict() for item in
cls.query(submission_type=submission_type, limit=limit, chronologic=chronologic, page=page, page_size=page_size)] cls.query(submission_type=submission_type, limit=limit, chronologic=chronologic, page=page,
page_size=page_size)]
# logger.debug(f"Got {len(subs)} submissions.") # logger.debug(f"Got {len(subs)} submissions.")
df = pd.DataFrame.from_records(subs) df = pd.DataFrame.from_records(subs)
# logger.debug(f"Column names: {df.columns}") # logger.debug(f"Column names: {df.columns}")
@@ -971,6 +972,19 @@ class BasicSubmission(BaseClass):
# samples.append(sample) # samples.append(sample)
# return samples # return samples
@classmethod
def parse_pcr_controls(cls, xl: Workbook) -> list:
location_map = cls.get_submission_type().sample_map['pcr_controls']
name_column = 1
for item in location_map:
logger.debug(f"Looking for {item['name']}")
worksheet = xl[item['sheet']]
for iii, row in enumerate(worksheet.iter_rows(max_row=len(worksheet['A']), max_col=name_column), start=1):
for cell in row:
if cell.value == item['name']:
logger.debug(f"Pulling from row {iii}, column {item['ct_column']}")
yield dict(name=item['name'], ct=worksheet.cell(row=iii, column=item['ct_column']).value)
@classmethod @classmethod
def filename_template(cls) -> str: def filename_template(cls) -> str:
""" """
@@ -1560,6 +1574,11 @@ class Wastewater(BasicSubmission):
for sample in output: for sample in output:
yield sample yield sample
# @classmethod
# def parse_pcr_controls(cls, xl: Workbook, location_map: list) -> list:
@classmethod @classmethod
def enforce_name(cls, instr: str, data: dict | None = {}) -> str: def enforce_name(cls, instr: str, data: dict | None = {}) -> str:
""" """

View File

@@ -1,6 +1,7 @@
''' '''
contains parser objects for pulling values from client generated submission sheets. contains parser objects for pulling values from client generated submission sheets.
''' '''
import json
from copy import copy from copy import copy
from getpass import getuser from getpass import getuser
from pprint import pformat from pprint import pformat
@@ -142,7 +143,6 @@ class SheetParser(object):
return PydSubmission(filepath=self.filepath, run_custom=True, **self.sub) return PydSubmission(filepath=self.filepath, run_custom=True, **self.sub)
class InfoParser(object): class InfoParser(object):
""" """
Object to parse generic info from excel sheet. Object to parse generic info from excel sheet.
@@ -675,6 +675,7 @@ class PCRParser(object):
rsl_plate_num = self.submission_obj.rsl_plate_num rsl_plate_num = self.submission_obj.rsl_plate_num
self.pcr = self.parse_general() self.pcr = self.parse_general()
self.samples = self.submission_obj.parse_pcr(xl=self.xl, rsl_plate_num=rsl_plate_num) self.samples = self.submission_obj.parse_pcr(xl=self.xl, rsl_plate_num=rsl_plate_num)
self.controls = self.submission_obj.parse_pcr_controls(xl=self.xl)
def parse_general(self): def parse_general(self):
""" """
@@ -698,3 +699,74 @@ class PCRParser(object):
pcr['imported_by'] = getuser() pcr['imported_by'] = getuser()
# logger.debug(f"PCR: {pformat(pcr)}") # logger.debug(f"PCR: {pformat(pcr)}")
return pcr return pcr
class EDSParser(object):
expand_device = {"QS7PRO": "QuantStudio tm 7 Pro System"}
expand_block = {"BLOCK_96W_01ML": "96-Well 0.1-mL Block"}
def __init__(self, filepath: str | Path | None = None):
logger.info(f"\n\nParsing {filepath.__str__()}\n\n")
match filepath:
case Path():
self.filepath = filepath
case str():
self.filepath = Path(filepath)
case _:
logger.error(f"No filepath given.")
raise ValueError("No filepath given.")
self.eds = ZipFile(self.filepath)
self.analysis_settings = json.loads(self.eds.read("primary/analysis_setting.json").decode("utf-8"))
self.analysis_results = json.loads(self.eds.read("primary/analysis_setting.json").decode("utf-8"))
self.presence_absence_results = json.loads(
self.eds.read("extensions/am.pa/presence_absence_result.json").decode("utf-8"))
self.presence_absence_settings = json.loads(
self.eds.read("extensions/am.pa/presence_absence_setting.json").decode("utf-8"))
self.run_summary = json.loads(self.eds.read("run/run_summary.json").decode("utf-8"))
self.run_method = json.loads(self.eds.read("setup/run_method.json").decode("utf-8"))
self.plate_setup = json.loads(self.eds.read("setup/plate_setup.json").decode("utf-8"))
self.eds_summary = json.loads(self.eds.read("summary.json").decode("utf-8"))
def parse_DA_date_format(self, value: int) -> datetime:
value = value / 1000
return datetime.utcfromtimestamp(value)
def get_run_time(self, start: datetime, end: datetime) -> Tuple[str, str, str]:
delta = end - start
minutes, seconds = divmod(delta.seconds, 60)
duration = f"{minutes} minutes {seconds} seconds"
start_time = start.strftime("%Y-%m-%d %I:%M:%S %p %Z")
end_time = end.strftime("%Y-%m-%d %I:%M:%S %p %Z")
return start_time, end_time, duration
def parse_summary(self):
summary = dict()
summary['file_name'] = self.filepath.absolute().__str__()
summary['comment'] = self.eds_summary['description']
summary['operator'] = self.run_summary['operator']
summary['barcode'] = self.plate_setup['plateBarcode']
try:
summary['instrument_type'] = self.__class__.expand_device[self.eds_summary['instrumentType']]
except KeyError:
summary['instrument_type'] = self.eds_summary['instrumentType']
try:
summary['block_type'] = self.__class__.expand_block[self.plate_setup['blockType']]
except KeyError:
summary['block_type'] = self.plate_setup['blockType']
summary['instrument_name'] = self.run_summary['instrumentName']
summary['instrument_serial_number'] = self.run_summary['instrumentSerialNumber']
summary['heated_cover_serial_number'] = self.run_summary['coverSerialNumber']
summary['block_serial_number'] = self.run_summary['blockSerialNumber']
run_start = self.parse_DA_date_format(self.run_summary['startTime'])
run_end = self.parse_DA_date_format(self.run_summary['endTime'])
summary['run_start_date/time'], summary['run_end_date/time'], summary['run_duration'] = \
self.get_run_time(run_start, run_end)
summary['sample_volume'] = self.run_method['sampleVolume']
summary['cover_temperature'] = self.run_method['coverTemperature']
summary['passive_reference'] = self.plate_setup['passiveReference']
summary['pcr_stage/step_number'] = f"Stage {self.analysis_settings['cqAnalysisStageNumber']} Step {self.analysis_settings['cqAnalysisStepNumber']}"
summary['quantification_cycle_method'] = self.analysis_results['cqAlgorithmType']
summary['analysis_date/time'] = self.parse_DA_date_format(self.eds_summary['analysis']['primary']['analysisTime'])
summary['software_name_and_version'] = "Design & Analysis Software v2.8.0"
summary['plugin_name_and_version'] = "Primary Analysis v1.8.1, Presence Absence v2.4.0"
return summary

View File

@@ -91,7 +91,7 @@ class EquipmentUsage(QDialog):
class RoleComboBox(QWidget): class RoleComboBox(QWidget):
def __init__(self, parent, role: PydEquipmentRole, used: list) -> None: def __init__(self, parent, role: PydEquipmentRole, used: Generator) -> None:
super().__init__(parent) super().__init__(parent)
self.layout = QGridLayout() self.layout = QGridLayout()
self.role = role self.role = role

View File

@@ -76,7 +76,11 @@ class SubmissionsSheet(QTableView):
super().__init__(parent) super().__init__(parent)
self.app = self.parent() self.app = self.parent()
self.report = Report() self.report = Report()
self.setData(page=1, page_size=self.app.page_size) try:
page_size = self.app.page_size
except AttributeError:
page_size = 250
self.setData(page=1, page_size=page_size)
self.resizeColumnsToContents() self.resizeColumnsToContents()
self.resizeRowsToContents() self.resizeRowsToContents()
self.setSortingEnabled(True) self.setSortingEnabled(True)