Sample results writer improvements.
This commit is contained in:
@@ -1558,7 +1558,7 @@ class Procedure(BaseClass):
|
||||
def to_pydantic(self, **kwargs):
|
||||
from backend.validators.pydant import PydResults, PydReagent
|
||||
output = super().to_pydantic()
|
||||
logger.debug(f"Pydantic output: \n\n{pformat(output.__dict__)}\n\n")
|
||||
print(f"Pydantic output: \n\n{pformat(output.__dict__)}\n\n")
|
||||
try:
|
||||
output.kittype = dict(value=output.kittype['name'], missing=False)
|
||||
except KeyError:
|
||||
@@ -1580,17 +1580,18 @@ class Procedure(BaseClass):
|
||||
pass
|
||||
# output.reagent = [PydReagent(**item) for item in output.reagent]
|
||||
output.reagent = reagents
|
||||
|
||||
results = []
|
||||
for result in output.results:
|
||||
match result:
|
||||
case dict():
|
||||
results.append(PydResults(**result))
|
||||
case PydResults():
|
||||
results.append(result)
|
||||
case _:
|
||||
pass
|
||||
output.results = results
|
||||
# results = []
|
||||
# for result in output.results:
|
||||
# match result:
|
||||
# case dict():
|
||||
# results.append(PydResults(**result))
|
||||
# case PydResults():
|
||||
# results.append(result)
|
||||
# case _:
|
||||
# pass
|
||||
# output.results = results
|
||||
output.result = [item.to_pydantic() for item in self.results]
|
||||
output.sample_results = flatten_list([[result.to_pydantic() for result in item.results] for item in self.proceduresampleassociation])
|
||||
# for sample in output.sample:
|
||||
# sample.enabled = True
|
||||
return output
|
||||
@@ -3116,6 +3117,13 @@ class Results(BaseClass):
|
||||
sampleprocedureassociation = relationship("ProcedureSampleAssociation", back_populates="results")
|
||||
_img = Column(String(128))
|
||||
|
||||
@property
|
||||
def sample_id(self):
|
||||
if self.assoc_id:
|
||||
return self.sampleprocedureassociation.sample.sample_id
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def image(self) -> bytes|None:
|
||||
dir = self.__directory_path__.joinpath("submission_imgs.zip")
|
||||
@@ -3131,3 +3139,10 @@ class Results(BaseClass):
|
||||
@image.setter
|
||||
def image(self, value):
|
||||
self._img = value
|
||||
|
||||
def to_pydantic(self, pyd_model_name:str|None=None, **kwargs):
|
||||
output = super().to_pydantic(pyd_model_name=pyd_model_name, **kwargs)
|
||||
if self.sample_id:
|
||||
output.sample_id = self.sample_id
|
||||
return output
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class PCRSampleParser(DefaultTABLEParser):
|
||||
if assoc and not isinstance(assoc, list):
|
||||
output = self._pyd_object(results=list(item.values())[0], parent=assoc)
|
||||
output.result_type = "PCR"
|
||||
del output.result['result_type']
|
||||
yield output
|
||||
else:
|
||||
continue
|
||||
|
||||
@@ -10,7 +10,7 @@ from openpyxl.workbook.workbook import Workbook
|
||||
from openpyxl.worksheet.worksheet import Worksheet
|
||||
from pandas import DataFrame
|
||||
|
||||
from backend.db.models import BaseClass
|
||||
from backend.db.models import BaseClass, ProcedureType
|
||||
from backend.validators.pydant import PydBaseClass
|
||||
|
||||
logger = logging.getLogger(f"submissions.{__name__}")
|
||||
@@ -21,10 +21,10 @@ class DefaultWriter(object):
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}<{self.filepath.stem}>"
|
||||
|
||||
def __init__(self, pydant_obj, range_dict: dict | None = None, *args, **kwargs):
|
||||
def __init__(self, pydant_obj, proceduretype: ProcedureType|None=None, range_dict: dict | None = None, *args, **kwargs):
|
||||
# self.filepath = output_filepath
|
||||
self.pydant_obj = pydant_obj
|
||||
self.fill_dictionary = pydant_obj.improved_dict()
|
||||
self.proceduretype = proceduretype
|
||||
if range_dict:
|
||||
self.range_dict = range_dict
|
||||
else:
|
||||
@@ -71,6 +71,10 @@ class DefaultKEYVALUEWriter(DefaultWriter):
|
||||
sheet="Sample List"
|
||||
)]
|
||||
|
||||
def __init__(self, pydant_obj, proceduretype: ProcedureType|None=None, range_dict: dict | None = None, *args, **kwargs):
|
||||
super().__init__(pydant_obj=pydant_obj, proceduretype=proceduretype, range_dict=range_dict, *args, **kwargs)
|
||||
self.fill_dictionary = self.pydant_obj.improved_dict()
|
||||
|
||||
@classmethod
|
||||
def check_location(cls, locations: list, sheet: str):
|
||||
return any([item['sheet'] == sheet for item in locations])
|
||||
@@ -82,21 +86,6 @@ class DefaultKEYVALUEWriter(DefaultWriter):
|
||||
worksheet = workbook[rng['sheet']]
|
||||
try:
|
||||
for ii, (k, v) in enumerate(self.fill_dictionary.items(), start=rng['start_row']):
|
||||
# match v:
|
||||
# case x if issubclass(v.__class__, BaseClass):
|
||||
# v = v.name
|
||||
# case x if issubclass(v.__class__, PydBaseClass):
|
||||
# v = v.name
|
||||
# case dict():
|
||||
# try:
|
||||
# v = v['value']
|
||||
# except ValueError:
|
||||
# try:
|
||||
# v = v['name']
|
||||
# except ValueError:
|
||||
# v = v.__str__()
|
||||
# case _:
|
||||
# pass
|
||||
try:
|
||||
worksheet.cell(column=rng['key_column'], row=rows[ii], value=self.prettify_key(k))
|
||||
worksheet.cell(column=rng['value_column'], row=rows[ii], value=self.stringify_value(v))
|
||||
@@ -127,7 +116,7 @@ class DefaultTABLEWriter(DefaultWriter):
|
||||
from backend import PydSample
|
||||
output_samples = []
|
||||
for iii in range(1, row_count + 1):
|
||||
logger.debug(f"Submission rank: {iii}")
|
||||
# logger.debug(f"Submission rank: {iii}")
|
||||
if isinstance(self.pydant_obj, list):
|
||||
iterator = self.pydant_obj
|
||||
else:
|
||||
@@ -139,8 +128,8 @@ class DefaultTABLEWriter(DefaultWriter):
|
||||
for column in column_names:
|
||||
setattr(sample, column[0], "")
|
||||
sample.submission_rank = iii
|
||||
logger.debug(f"Appending {sample.sample_id}")
|
||||
logger.debug(f"Iterator now: {[item.submission_rank for item in iterator]}")
|
||||
# logger.debug(f"Appending {sample.sample_id}")
|
||||
# logger.debug(f"Iterator now: {[item.submission_rank for item in iterator]}")
|
||||
output_samples.append(sample)
|
||||
return sorted(output_samples, key=lambda x: x.submission_rank)
|
||||
|
||||
|
||||
@@ -80,9 +80,9 @@ class ProcedureSampleWriter(DefaultTABLEWriter):
|
||||
list_worksheet[rng['header_row']] if item.value]
|
||||
samples = self.pad_samples_to_length(row_count=row_count, column_names=column_names)
|
||||
# samples = self.pydant_obj
|
||||
logger.debug(f"Samples: {[item.submission_rank for item in samples]}")
|
||||
# logger.debug(f"Samples: {[item.submission_rank for item in samples]}")
|
||||
for sample in samples:
|
||||
logger.debug(f"Writing sample: {sample}")
|
||||
# logger.debug(f"Writing sample: {sample}")
|
||||
write_row = rng['header_row'] + sample.submission_rank
|
||||
for column in column_names:
|
||||
if column[0].lower() in ["well"]:#, "row", "column"]:
|
||||
@@ -92,6 +92,6 @@ class ProcedureSampleWriter(DefaultTABLEWriter):
|
||||
value = getattr(sample, column[0])
|
||||
except KeyError:
|
||||
value = ""
|
||||
logger.debug(f"{column} Writing {value} to row {write_row}, column {write_column}")
|
||||
# logger.debug(f"{column} Writing {value} to row {write_row}, column {write_column}")
|
||||
list_worksheet.cell(row=write_row, column=write_column, value=value)
|
||||
return workbook
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from .pcr_results_writer import PCRInfoWriter, PCRSampleWriter
|
||||
@@ -0,0 +1,83 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Alignment
|
||||
|
||||
from backend.excel.writers import DefaultKEYVALUEWriter, DefaultTABLEWriter
|
||||
from tools import flatten_list
|
||||
|
||||
logger = logging.getLogger(f"submissions.{__name__}")
|
||||
|
||||
class PCRInfoWriter(DefaultKEYVALUEWriter):
|
||||
|
||||
default_range_dict = [dict(
|
||||
start_row=1,
|
||||
end_row=24,
|
||||
key_column=1,
|
||||
value_column=2,
|
||||
sheet="Results"
|
||||
)]
|
||||
|
||||
def write_to_workbook(self, workbook: Workbook) -> Workbook:
|
||||
worksheet = workbook[f"{self.proceduretype.name} Results"]
|
||||
for key, value in self.fill_dictionary['result'].items():
|
||||
logger.debug(f"Filling in {key} with {value}")
|
||||
worksheet.cell(value['location']['row'], value['location']['key_column'], value=key.replace("_", " ").title())
|
||||
worksheet.cell(value['location']['row'], value['location']['value_column'], value=value['value'])
|
||||
return workbook
|
||||
|
||||
|
||||
class PCRSampleWriter(DefaultTABLEWriter):
|
||||
|
||||
def write_to_workbook(self, workbook: Workbook) -> Workbook:
|
||||
worksheet = workbook[f"{self.proceduretype.name} Results"]
|
||||
header_row = self.proceduretype.allowed_result_methods['PCR']['sample']['header_row']
|
||||
proto_columns = [(1, "sample"), (2, "target")]
|
||||
columns = []
|
||||
for iii, header in enumerate(self.column_headers, start=3):
|
||||
worksheet.cell(row=header_row, column=iii, value=header.replace("_", " ").title())
|
||||
columns.append((iii, header))
|
||||
columns = sorted(columns, key=lambda x: x[0])
|
||||
columns = proto_columns + columns
|
||||
logger.debug(columns)
|
||||
all_results = flatten_list([[item for item in self.rearrange_results(result)] for result in self.pydant_obj])
|
||||
if len(all_results) > 0 :
|
||||
worksheet.cell(row=header_row, column=1, value="Sample")
|
||||
worksheet.cell(row=header_row, column=2, value="Target")
|
||||
for iii, item in enumerate(all_results, start=1):
|
||||
row = header_row + iii
|
||||
for k, v in item.items():
|
||||
column = next((col[0] for col in columns if col[1]==k), None)
|
||||
cell = worksheet.cell(row=row, column=column)
|
||||
cell.value = v
|
||||
cell.alignment = Alignment(horizontal='left')
|
||||
return workbook
|
||||
|
||||
@classmethod
|
||||
def rearrange_results(cls, result) -> Generator[dict, None, None]:
|
||||
for target, values in result.result.items():
|
||||
values['target'] = target
|
||||
values['sample'] = result.sample_id
|
||||
yield values
|
||||
|
||||
@property
|
||||
def column_headers(self):
|
||||
output = []
|
||||
for item in self.pydant_obj:
|
||||
logger.debug(item)
|
||||
dicto: dict = item.result
|
||||
for value in dicto.values():
|
||||
for key in value.keys():
|
||||
output.append(key)
|
||||
return sorted(list(set(output)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from io import BytesIO
|
||||
from pprint import pformat
|
||||
|
||||
from openpyxl.reader.excel import load_workbook
|
||||
from openpyxl.workbook import Workbook
|
||||
|
||||
from backend.managers import DefaultManager
|
||||
from backend.managers import DefaultManager, results
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
from backend.excel.parsers import procedure_parsers
|
||||
from backend.excel.writers import procedure_writers
|
||||
from backend.excel.writers import procedure_writers, results_writers
|
||||
if TYPE_CHECKING:
|
||||
from backend.db.models import ProcedureType
|
||||
|
||||
@@ -81,5 +82,15 @@ class DefaultProcedureManager(DefaultManager):
|
||||
sample_writer = procedure_writers.ProcedureSampleWriter
|
||||
self.sample_writer = sample_writer(pydant_obj=self.pyd, range_dict=self.proceduretype.sample_map)
|
||||
workbook = self.sample_writer.write_to_workbook(workbook)
|
||||
logger.debug(self.pyd.result)
|
||||
# TODO: Find way to group results by result_type.
|
||||
for result in self.pyd.result:
|
||||
Writer = getattr(results_writers, f"{result.result_type}InfoWriter")
|
||||
res_info_writer = Writer(pydant_obj=result, proceduretype=self.proceduretype)
|
||||
workbook = res_info_writer.write_to_workbook(workbook=workbook)
|
||||
# sample_results = [sample.result for sample in self.pyd.sample]
|
||||
logger.debug(pformat(self.pyd.sample_results))
|
||||
Writer = getattr(results_writers, "PCRSampleWriter")
|
||||
res_sample_writer = Writer(pydant_obj=self.pyd.sample_results, proceduretype=self.proceduretype)
|
||||
workbook = res_sample_writer.write_to_workbook(workbook=workbook)
|
||||
return workbook
|
||||
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from typing import Tuple, List, TYPE_CHECKING
|
||||
|
||||
from openpyxl.reader.excel import load_workbook
|
||||
|
||||
from backend.db.models import Procedure
|
||||
from backend.excel.parsers.results_parsers.pcr_results_parser import PCRSampleParser, PCRInfoParser
|
||||
from backend.excel.writers.results_writers.pcr_results_writer import PCRInfoWriter, PCRSampleWriter
|
||||
from . import DefaultResultsManager
|
||||
if TYPE_CHECKING:
|
||||
from backend.validators.pydant import PydResults
|
||||
@@ -23,6 +28,13 @@ class PCRManager(DefaultResultsManager):
|
||||
self.info_parser = PCRInfoParser(filepath=self.fname, procedure=self.procedure)
|
||||
self.sample_parser = PCRSampleParser(filepath=self.fname, procedure=self.procedure)
|
||||
|
||||
def write(self):
|
||||
workbook = load_workbook(BytesIO(self.procedure.proceduretype.template_file))
|
||||
self.info_writer = PCRInfoWriter(pydant_obj=self.procedure.to_pydantic(), proceduretype=self.procedure.proceduretype)
|
||||
workbook = self.info_writer.write_to_workbook(workbook)
|
||||
self.sample_writer = PCRSampleWriter(pydant_obj=self.procedure.to_pydantic(), proceduretype=self.procedure.proceduretype)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from pprint import pformat
|
||||
|
||||
from openpyxl import load_workbook
|
||||
from openpyxl.workbook.workbook import Workbook
|
||||
from tools import copy_xl_sheet
|
||||
@@ -18,8 +20,8 @@ class DefaultRunManager(DefaultManager):
|
||||
clientsubmission = DefaultClientSubmissionManager(parent=self.parent, input_object=self.pyd.clientsubmission, submissiontype=self.pyd.clientsubmission.submissiontype)
|
||||
workbook = clientsubmission.write()
|
||||
for procedure in self.pyd.procedure:
|
||||
logger.debug(f"Running procedure: {procedure}")
|
||||
procedure = DefaultProcedureManager(proceduretype=procedure.proceduretype.name, parent=self.parent, input_object=procedure)
|
||||
logger.debug(f"Running procedure: {pformat(procedure.__dict__)}")
|
||||
procedure = DefaultProcedureManager(proceduretype=procedure.proceduretype, parent=self.parent, input_object=procedure)
|
||||
wb: Workbook = procedure.write()
|
||||
for sheetname in wb.sheetnames:
|
||||
source_sheet = wb[sheetname]
|
||||
|
||||
@@ -1309,7 +1309,7 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
|
||||
reagentrole: dict | None = Field(default={}, validate_default=True)
|
||||
sample: List[PydSample] = Field(default=[])
|
||||
equipment: List[PydEquipment] = Field(default=[])
|
||||
results: List[PydResults] | List[dict] = Field(default=[])
|
||||
result: List[PydResults] | List[dict] = Field(default=[])
|
||||
|
||||
@field_validator("name", "technician", "kittype", mode="before")
|
||||
@classmethod
|
||||
@@ -1749,7 +1749,7 @@ class PydClientSubmission(PydBaseClass):
|
||||
|
||||
|
||||
class PydResults(PydBaseClass, arbitrary_types_allowed=True):
|
||||
results: dict = Field(default={})
|
||||
result: dict = Field(default={})
|
||||
result_type: str = Field(default="NA")
|
||||
img: None | bytes = Field(default=None)
|
||||
parent: Procedure | ProcedureSampleAssociation | None = Field(default=None)
|
||||
|
||||
@@ -26,9 +26,9 @@ class SubmissionDetails(QDialog):
|
||||
a window showing text details of procedure
|
||||
"""
|
||||
|
||||
def __init__(self, parent, sub: Run | Sample | Reagent) -> None:
|
||||
def __init__(self, parent, sub: Run | Sample | Reagent, **kwargs) -> None:
|
||||
|
||||
super().__init__(parent)
|
||||
super().__init__(parent, **kwargs)
|
||||
self.app = get_application_from_parent(parent)
|
||||
self.webview = QWebEngineView(parent=self)
|
||||
self.webview.setMinimumSize(900, 500)
|
||||
|
||||
@@ -424,7 +424,7 @@ class SubmissionsTree(QTreeView):
|
||||
# Run.query(id=id).show_details(self)
|
||||
obj = dicto['item_type'].query(name=dicto['query_str'], limit=1)
|
||||
logger.debug(obj)
|
||||
obj.show_details(obj)
|
||||
obj.show_details(self)
|
||||
|
||||
def link_extractions(self):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user