Plate map in procedure details.
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
# 202509.02
|
||||||
|
|
||||||
|
- First Useable updated version.
|
||||||
|
|
||||||
# 202504.04
|
# 202504.04
|
||||||
|
|
||||||
- Added html links for equipment/processes/tips.
|
- Added html links for equipment/processes/tips.
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|||||||
import sys, logging, json, inspect
|
import sys, logging, json, inspect
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
|
||||||
from dateutil.parser import parse
|
from dateutil.parser import parse
|
||||||
from jinja2 import TemplateNotFound, Template
|
from jinja2 import TemplateNotFound, Template
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
@@ -19,7 +18,7 @@ from sqlalchemy.exc import ArgumentError
|
|||||||
from typing import Any, List, ClassVar
|
from typing import Any, List, ClassVar
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from sqlalchemy.orm.relationships import _RelationshipDeclared
|
from sqlalchemy.orm.relationships import _RelationshipDeclared
|
||||||
from tools import report_result, list_sort_dict, jinja_template_loading, Report, Result
|
from tools import report_result, list_sort_dict, jinja_template_loading, Report, Result, ctx
|
||||||
|
|
||||||
# NOTE: Load testing environment
|
# NOTE: Load testing environment
|
||||||
if 'pytest' in sys.modules:
|
if 'pytest' in sys.modules:
|
||||||
@@ -92,10 +91,6 @@ class BaseClass(Base):
|
|||||||
Returns:
|
Returns:
|
||||||
Session: DB session from ctx settings.
|
Session: DB session from ctx settings.
|
||||||
"""
|
"""
|
||||||
if 'pytest' not in sys.modules:
|
|
||||||
from tools import ctx
|
|
||||||
else:
|
|
||||||
from test_settings import ctx
|
|
||||||
return ctx.database_session
|
return ctx.database_session
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -107,10 +102,6 @@ class BaseClass(Base):
|
|||||||
Returns:
|
Returns:
|
||||||
Path: Location of the Submissions directory in Settings object
|
Path: Location of the Submissions directory in Settings object
|
||||||
"""
|
"""
|
||||||
if 'pytest' not in sys.modules:
|
|
||||||
from tools import ctx
|
|
||||||
else:
|
|
||||||
from test_settings import ctx
|
|
||||||
return ctx.directory_path
|
return ctx.directory_path
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -122,10 +113,6 @@ class BaseClass(Base):
|
|||||||
Returns:
|
Returns:
|
||||||
Path: Location of the Submissions backup directory in Settings object
|
Path: Location of the Submissions backup directory in Settings object
|
||||||
"""
|
"""
|
||||||
if 'pytest' not in sys.modules:
|
|
||||||
from tools import ctx
|
|
||||||
else:
|
|
||||||
from test_settings import ctx
|
|
||||||
return ctx.backup_path
|
return ctx.backup_path
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -284,7 +271,7 @@ class BaseClass(Base):
|
|||||||
if issubclass(v.__class__, PydBaseClass):
|
if issubclass(v.__class__, PydBaseClass):
|
||||||
setattr(instance, k, v.to_sql())
|
setattr(instance, k, v.to_sql())
|
||||||
instance._misc_info.update(outside_kwargs)
|
instance._misc_info.update(outside_kwargs)
|
||||||
logger.info(f"Instance from query or create: {instance}, new: {new}")
|
# logger.info(f"Instance from query or create: {instance}, new: {new}")
|
||||||
return instance, new
|
return instance, new
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class ReagentRole(BaseClass):
|
|||||||
new = True
|
new = True
|
||||||
for k, v in sanitized_kwargs.items():
|
for k, v in sanitized_kwargs.items():
|
||||||
setattr(instance, k, v)
|
setattr(instance, k, v)
|
||||||
logger.info(f"Instance from query or create: {instance}")
|
# logger.info(f"Instance from query or create: {instance}")
|
||||||
return instance, new
|
return instance, new
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -785,7 +785,7 @@ class ProcedureType(BaseClass):
|
|||||||
)
|
)
|
||||||
return PydProcedure(**output)
|
return PydProcedure(**output)
|
||||||
|
|
||||||
def construct_plate_map(self, sample_dicts: List["PydSample"]) -> str:
|
def construct_plate_map(self, sample_dicts: List["PydSample"], creation:bool=True, vw_modifier:float=1.0) -> str:
|
||||||
"""
|
"""
|
||||||
Constructs an html based plate map for procedure details.
|
Constructs an html based plate map for procedure details.
|
||||||
|
|
||||||
@@ -800,13 +800,13 @@ class ProcedureType(BaseClass):
|
|||||||
if self.plate_rows == 0 or self.plate_columns == 0:
|
if self.plate_rows == 0 or self.plate_columns == 0:
|
||||||
return "<br/>"
|
return "<br/>"
|
||||||
sample_dicts = self.pad_sample_dicts(sample_dicts=sample_dicts)
|
sample_dicts = self.pad_sample_dicts(sample_dicts=sample_dicts)
|
||||||
vw = round((-0.07 * len(sample_dicts)) + 12.2, 1)
|
vw = round((-0.07 * len(sample_dicts)) + (12.2 * vw_modifier), 1)
|
||||||
# NOTE: An overly complicated list comprehension create a list of sample locations
|
# NOTE: An overly complicated list comprehension create a list of sample locations
|
||||||
# NOTE: next will return a blank cell if no value found for row/column
|
# NOTE: next will return a blank cell if no value found for row/column
|
||||||
env = jinja_template_loading()
|
env = jinja_template_loading()
|
||||||
template = env.get_template("support/plate_map.html")
|
template = env.get_template("support/plate_map.html")
|
||||||
html = template.render(plate_rows=self.plate_rows, plate_columns=self.plate_columns, samples=sample_dicts,
|
html = template.render(plate_rows=self.plate_rows, plate_columns=self.plate_columns, samples=sample_dicts,
|
||||||
vw=vw)
|
vw=vw, creation=creation)
|
||||||
return html + "<br/>"
|
return html + "<br/>"
|
||||||
|
|
||||||
def pad_sample_dicts(self, sample_dicts: List["PydSample"]):
|
def pad_sample_dicts(self, sample_dicts: List["PydSample"]):
|
||||||
@@ -985,6 +985,7 @@ class Procedure(BaseClass):
|
|||||||
output['sample_count'] = len(active_samples)
|
output['sample_count'] = len(active_samples)
|
||||||
output['clientlab'] = self.run.clientsubmission.clientlab.name
|
output['clientlab'] = self.run.clientsubmission.clientlab.name
|
||||||
output['cost'] = 0.00
|
output['cost'] = 0.00
|
||||||
|
output['platemap'] = self.make_procedure_platemap()
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def to_pydantic(self, **kwargs):
|
def to_pydantic(self, **kwargs):
|
||||||
@@ -1038,6 +1039,12 @@ class Procedure(BaseClass):
|
|||||||
output = {k: v for k, v in dicto.items()}
|
output = {k: v for k, v in dicto.items()}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def make_procedure_platemap(self):
|
||||||
|
dicto = [sample.to_pydantic() for sample in self.proceduresampleassociation]
|
||||||
|
html = self.proceduretype.construct_plate_map(sample_dicts=dicto, creation=False, vw_modifier=1.15)
|
||||||
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProcedureTypeReagentRoleAssociation(BaseClass):
|
class ProcedureTypeReagentRoleAssociation(BaseClass):
|
||||||
"""
|
"""
|
||||||
@@ -1143,7 +1150,7 @@ class ProcedureTypeReagentRoleAssociation(BaseClass):
|
|||||||
case _:
|
case _:
|
||||||
pass
|
pass
|
||||||
setattr(instance, k, v)
|
setattr(instance, k, v)
|
||||||
logger.info(f"Instance from query or create: {instance.__dict__}\nis new: {new}")
|
# logger.info(f"Instance from query or create: {instance.__dict__}\nis new: {new}")
|
||||||
return instance, new
|
return instance, new
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -1423,7 +1430,7 @@ class EquipmentRole(BaseClass):
|
|||||||
new = True
|
new = True
|
||||||
for k, v in sanitized_kwargs.items():
|
for k, v in sanitized_kwargs.items():
|
||||||
setattr(instance, k, v)
|
setattr(instance, k, v)
|
||||||
logger.info(f"Instance from query or create: {instance}")
|
# logger.info(f"Instance from query or create: {instance}")
|
||||||
return instance, new
|
return instance, new
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -1816,6 +1823,9 @@ class Process(BaseClass):
|
|||||||
|
|
||||||
|
|
||||||
class ProcessVersion(BaseClass):
|
class ProcessVersion(BaseClass):
|
||||||
|
|
||||||
|
pyd_model_name = "Process"
|
||||||
|
|
||||||
id = Column(INTEGER, primary_key=True) #: Process id, primary key
|
id = Column(INTEGER, primary_key=True) #: Process id, primary key
|
||||||
version = Column(FLOAT(2), default=1.00) #: Version number
|
version = Column(FLOAT(2), default=1.00) #: Version number
|
||||||
date_verified = Column(TIMESTAMP) #: Date this version was deemed worthy
|
date_verified = Column(TIMESTAMP) #: Date this version was deemed worthy
|
||||||
@@ -1867,7 +1877,7 @@ class ProcessVersion(BaseClass):
|
|||||||
version: str | float | None = None,
|
version: str | float | None = None,
|
||||||
name: str | None = None,
|
name: str | None = None,
|
||||||
limit: int = 0,
|
limit: int = 0,
|
||||||
**kwargs) -> ReagentLot | List[ReagentLot]:
|
**kwargs) -> ProcessVersion | List[ProcessVersion]:
|
||||||
query: Query = cls.__database_session__.query(cls)
|
query: Query = cls.__database_session__.query(cls)
|
||||||
match name:
|
match name:
|
||||||
case str():
|
case str():
|
||||||
@@ -1881,6 +1891,9 @@ class ProcessVersion(BaseClass):
|
|||||||
pass
|
pass
|
||||||
return cls.execute_query(query=query, limit=limit)
|
return cls.execute_query(query=query, limit=limit)
|
||||||
|
|
||||||
|
# def to_pydantic(self, pyd_model_name: str | None = None, **kwargs):
|
||||||
|
# output = super().to_pydantic(pyd_model_name=pyd_model_name, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Tips(BaseClass):
|
class Tips(BaseClass):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -879,7 +879,7 @@ class Run(BaseClass, LogMixin):
|
|||||||
Returns:
|
Returns:
|
||||||
PydSubmission: converted object.
|
PydSubmission: converted object.
|
||||||
"""
|
"""
|
||||||
from backend.validators import PydRun
|
from backend.validators import PydClientSubmission, PydRun
|
||||||
dicto = self.details_dict(full_data=True, backup=backup)
|
dicto = self.details_dict(full_data=True, backup=backup)
|
||||||
new_dict = {}
|
new_dict = {}
|
||||||
for key, value in dicto.items():
|
for key, value in dicto.items():
|
||||||
@@ -1916,6 +1916,8 @@ class ProcedureSampleAssociation(BaseClass):
|
|||||||
misc = output['misc_info']
|
misc = output['misc_info']
|
||||||
output.update(relevant)
|
output.update(relevant)
|
||||||
output['misc_info'] = misc
|
output['misc_info'] = misc
|
||||||
|
output['row'] = self.row
|
||||||
|
output['column'] = self.column
|
||||||
output['results'] = [result.details_dict() for result in output['results']]
|
output['results'] = [result.details_dict() for result in output['results']]
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
Contains pandas and openpyxl convenience functions for interacting with excel workbooks
|
Contains pandas and openpyxl convenience functions for interacting with excel workbooks
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# from backend.excel.parsers.clientsubmission_parser import ClientSubmissionInfoParser, ClientSubmissionSampleParser
|
|
||||||
from .parsers import (
|
from .parsers import (
|
||||||
DefaultParser, DefaultKEYVALUEParser, DefaultTABLEParser,
|
DefaultParser, DefaultKEYVALUEParser, DefaultTABLEParser,
|
||||||
ProcedureInfoParser, ProcedureSampleParser, ProcedureReagentParser, ProcedureEquipmentParser,
|
ProcedureInfoParser, ProcedureSampleParser, ProcedureReagentParser, ProcedureEquipmentParser,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from pathlib import Path
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
from typing import Tuple, List
|
from typing import Tuple, List
|
||||||
from backend.db.models import Procedure, Run
|
from backend.db.models import Procedure, Run
|
||||||
from tools import jinja_template_loading, get_first_blank_df_row, row_map, flatten_list
|
from tools import jinja_template_loading, get_first_blank_df_row, row_map, flatten_list, ctx
|
||||||
from PyQt6.QtWidgets import QWidget
|
from PyQt6.QtWidgets import QWidget
|
||||||
from openpyxl.worksheet.worksheet import Worksheet
|
from openpyxl.worksheet.worksheet import Worksheet
|
||||||
|
|
||||||
@@ -173,10 +173,6 @@ class TurnaroundMaker(ReportArchetype):
|
|||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if 'pytest' not in sys.modules:
|
|
||||||
from tools import ctx
|
|
||||||
else:
|
|
||||||
from test_settings import ctx
|
|
||||||
days = sub.turnaround_time
|
days = sub.turnaround_time
|
||||||
try:
|
try:
|
||||||
tat = sub.get_default_info("turnaround_time")
|
tat = sub.get_default_info("turnaround_time")
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ class DefaultWriter(object):
|
|||||||
value = value['name']
|
value = value['name']
|
||||||
except (KeyError, ValueError):
|
except (KeyError, ValueError):
|
||||||
return
|
return
|
||||||
# logger.debug(f"Value type: {type(value)}")
|
|
||||||
match value:
|
match value:
|
||||||
case x if issubclass(value.__class__, BaseClass):
|
case x if issubclass(value.__class__, BaseClass):
|
||||||
value = value.name
|
value = value.name
|
||||||
@@ -81,7 +80,6 @@ class DefaultWriter(object):
|
|||||||
self.worksheet = self.prewrite(self.worksheet, start_row=start_row)
|
self.worksheet = self.prewrite(self.worksheet, start_row=start_row)
|
||||||
self.start_row = self.delineate_start_row(start_row=start_row)
|
self.start_row = self.delineate_start_row(start_row=start_row)
|
||||||
self.end_row = self.delineate_end_row(start_row=start_row)
|
self.end_row = self.delineate_end_row(start_row=start_row)
|
||||||
logger.debug(f"Rows for {self.__class__.__name__}:\tstart: {self.start_row}, end: {self.end_row}")
|
|
||||||
return workbook
|
return workbook
|
||||||
|
|
||||||
def delineate_start_row(self, start_row: int = 1) -> int:
|
def delineate_start_row(self, start_row: int = 1) -> int:
|
||||||
@@ -93,7 +91,6 @@ class DefaultWriter(object):
|
|||||||
Returns:
|
Returns:
|
||||||
int
|
int
|
||||||
"""
|
"""
|
||||||
logger.debug(f"{self.__class__.__name__} will start looking for blank rows at {start_row}")
|
|
||||||
for iii, row in enumerate(self.worksheet.iter_rows(min_row=start_row), start=start_row):
|
for iii, row in enumerate(self.worksheet.iter_rows(min_row=start_row), start=start_row):
|
||||||
if all([item.value is None for item in row]):
|
if all([item.value is None for item in row]):
|
||||||
return iii
|
return iii
|
||||||
@@ -146,7 +143,6 @@ class DefaultKEYVALUEWriter(DefaultWriter):
|
|||||||
dictionary = sort_dict_by_list(dictionary=dictionary, order_list=self.key_order)
|
dictionary = sort_dict_by_list(dictionary=dictionary, order_list=self.key_order)
|
||||||
for ii, (k, v) in enumerate(dictionary.items(), start=self.start_row):
|
for ii, (k, v) in enumerate(dictionary.items(), start=self.start_row):
|
||||||
value = self.stringify_value(value=v)
|
value = self.stringify_value(value=v)
|
||||||
logger.debug(f"{self.__class__.__name__} attempting to write {value}")
|
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
self.worksheet.cell(column=1, row=ii, value=self.prettify_key(k))
|
self.worksheet.cell(column=1, row=ii, value=self.prettify_key(k))
|
||||||
@@ -172,7 +168,6 @@ class DefaultTABLEWriter(DefaultWriter):
|
|||||||
|
|
||||||
def delineate_end_row(self, start_row: int = 1) -> int:
|
def delineate_end_row(self, start_row: int = 1) -> int:
|
||||||
end_row = start_row + len(self.pydant_obj) + 1
|
end_row = start_row + len(self.pydant_obj) + 1
|
||||||
logger.debug(f"End row has been delineated as {start_row} + {len(self.pydant_obj)} + 1 = {end_row}")
|
|
||||||
return end_row
|
return end_row
|
||||||
|
|
||||||
def pad_samples_to_length(self, row_count,
|
def pad_samples_to_length(self, row_count,
|
||||||
@@ -220,7 +215,6 @@ class DefaultTABLEWriter(DefaultWriter):
|
|||||||
value = object.improved_dict()[header.lower().replace(" ", "_")]
|
value = object.improved_dict()[header.lower().replace(" ", "_")]
|
||||||
except (AttributeError, KeyError):
|
except (AttributeError, KeyError):
|
||||||
value = ""
|
value = ""
|
||||||
# logger.debug(f"{self.__class__.__name__} attempting to write {value}")
|
|
||||||
self.worksheet.cell(row=write_row, column=column, value=self.stringify_value(value))
|
self.worksheet.cell(row=write_row, column=column, value=self.stringify_value(value))
|
||||||
self.worksheet = self.postwrite(self.worksheet)
|
self.worksheet = self.postwrite(self.worksheet)
|
||||||
return workbook
|
return workbook
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Default
|
Default writers for procedures.
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import logging, sys
|
import logging, sys
|
||||||
@@ -18,9 +18,7 @@ class ProcedureInfoWriter(DefaultKEYVALUEWriter):
|
|||||||
'reagentrole', 'results', 'sample', 'tips', 'reagentlot']
|
'reagentrole', 'results', 'sample', 'tips', 'reagentlot']
|
||||||
|
|
||||||
def __init__(self, pydant_obj, *args, **kwargs):
|
def __init__(self, pydant_obj, *args, **kwargs):
|
||||||
|
|
||||||
super().__init__(pydant_obj=pydant_obj, *args, **kwargs)
|
super().__init__(pydant_obj=pydant_obj, *args, **kwargs)
|
||||||
|
|
||||||
self.fill_dictionary = {k: v for k, v in self.fill_dictionary.items() if k not in self.__class__.exclude}
|
self.fill_dictionary = {k: v for k, v in self.fill_dictionary.items() if k not in self.__class__.exclude}
|
||||||
|
|
||||||
def write_to_workbook(self, workbook: Workbook, sheet: str | None = None,
|
def write_to_workbook(self, workbook: Workbook, sheet: str | None = None,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
|
Writers for PCR results from Design and Analysis Software
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -69,13 +69,10 @@ class ProcedureCreation(QDialog):
|
|||||||
equipment['name'] == relevant_procedure_item.name))
|
equipment['name'] == relevant_procedure_item.name))
|
||||||
equipmentrole['equipment'].insert(0, equipmentrole['equipment'].pop(
|
equipmentrole['equipment'].insert(0, equipmentrole['equipment'].pop(
|
||||||
equipmentrole['equipment'].index(item_in_er_list)))
|
equipmentrole['equipment'].index(item_in_er_list)))
|
||||||
# proceduretype_dict['equipment_section'] = EquipmentUsage.construct_html(procedure=self.procedure, child=True)
|
|
||||||
proceduretype_dict['equipment'] = [sanitize_object_for_json(object) for object in proceduretype_dict['equipment']]
|
proceduretype_dict['equipment'] = [sanitize_object_for_json(object) for object in proceduretype_dict['equipment']]
|
||||||
self.update_equipment = EquipmentUsage.update_equipment
|
|
||||||
regex = re.compile(r".*R\d$")
|
regex = re.compile(r".*R\d$")
|
||||||
proceduretype_dict['previous'] = [""] + [item.name for item in self.run.procedure if item.proceduretype == self.proceduretype and not bool(regex.match(item.name))]
|
proceduretype_dict['previous'] = [""] + [item.name for item in self.run.procedure if item.proceduretype == self.proceduretype and not bool(regex.match(item.name))]
|
||||||
logger.debug(f"Procedure:\n{pformat(self.procedure.__dict__)}")
|
# sys.exit(f"ProcedureDict:\n{pformat(proceduretype_dict)}")
|
||||||
logger.debug(f"ProcedureType:\n{pformat(proceduretype_dict)}")
|
|
||||||
html = render_details_template(
|
html = render_details_template(
|
||||||
template_name="procedure_creation",
|
template_name="procedure_creation",
|
||||||
js_in=["procedure_form", "grid_drag", "context_menu"],
|
js_in=["procedure_form", "grid_drag", "context_menu"],
|
||||||
@@ -88,8 +85,9 @@ class ProcedureCreation(QDialog):
|
|||||||
self.webview.setHtml(html)
|
self.webview.setHtml(html)
|
||||||
|
|
||||||
@pyqtSlot(str, str, str, str)
|
@pyqtSlot(str, str, str, str)
|
||||||
def update_equipment(self, equipmentrole: str, equipment: str, process: str, tips: str):
|
def update_equipment(self, equipmentrole: str, equipment: str, processversion: str, tips: str):
|
||||||
from backend.db.models import Equipment, ProcessVersion, TipsLot
|
from backend.db.models import Equipment, ProcessVersion, TipsLot
|
||||||
|
logger.debug(f"\n\nEquipmentRole: {equipmentrole}, Equipment: {equipment}, Process: {processversion}, Tips: {tips}\n\n")
|
||||||
try:
|
try:
|
||||||
equipment_of_interest = next(
|
equipment_of_interest = next(
|
||||||
(item for item in self.procedure.equipment if item.equipmentrole == equipmentrole))
|
(item for item in self.procedure.equipment if item.equipmentrole == equipmentrole))
|
||||||
@@ -103,9 +101,9 @@ class ProcedureCreation(QDialog):
|
|||||||
eoi.name = equipment.name
|
eoi.name = equipment.name
|
||||||
eoi.asset_number = equipment.asset_number
|
eoi.asset_number = equipment.asset_number
|
||||||
eoi.nickname = equipment.nickname
|
eoi.nickname = equipment.nickname
|
||||||
process_name, version = process.split("-v")
|
process_name, version = processversion.split("-v")
|
||||||
process = ProcessVersion.query(name=process_name, version=version, limit=1)
|
processversion = ProcessVersion.query(name=process_name, version=version, limit=1)
|
||||||
eoi.process = process
|
eoi.processversion = processversion.to_pydantic()
|
||||||
try:
|
try:
|
||||||
tips_manufacturer, tipsref, lot = [item if item != "" else None for item in tips.split("-")]
|
tips_manufacturer, tipsref, lot = [item if item != "" else None for item in tips.split("-")]
|
||||||
tips = TipsLot.query(manufacturer=tips_manufacturer, ref=tipsref, lot=lot)
|
tips = TipsLot.query(manufacturer=tips_manufacturer, ref=tipsref, lot=lot)
|
||||||
|
|||||||
@@ -56,10 +56,15 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if procedure['sample'] %}
|
{% if procedure['sample'] %}
|
||||||
<button type="button"><h3><u>Procedure Samples:</u></h3></button>
|
<button type="button"><h3><u>Procedure Samples:</u></h3></button>
|
||||||
|
{% if procedure['platemap']|length > 5 %}
|
||||||
|
<br>
|
||||||
|
{{ procedure['platemap'] }}
|
||||||
|
{% else %}
|
||||||
<p>{% for sample in procedure['sample'] %}
|
<p>{% for sample in procedure['sample'] %}
|
||||||
<a class="{% if sample['active'] %}data-link {% else %}unused {% endif %}sample" id="{{ sample['sample_id'] }}">{{ sample['sample_id']}}</a><br>
|
<a class="{% if sample['active'] %}data-link {% else %}unused {% endif %}sample" id="{{ sample['sample_id'] }}">{{ sample['sample_id']}}</a><br>
|
||||||
{% endfor %}</p>
|
{% endfor %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% if not child %}
|
{% if not child %}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
<div class="plate" id="plate-container" style="grid-template-columns: repeat({{ plate_columns }}, {{ vw }}vw);grid-template-rows: repeat({{ plate_rows }}, {{ vw }}vw);">
|
<div class="plate" id="plate-container" style="grid-template-columns: repeat({{ plate_columns }}, {{ vw }}vw);grid-template-rows: repeat({{ plate_rows }}, {{ vw }}vw);">
|
||||||
{% for sample in samples %}
|
{% for sample in samples %}
|
||||||
<div class="well" draggable="true" id="{{ sample['well_id'] }}" style="background-color: {{ sample['background_color'] }};">
|
<div class="well" draggable="true" id="{{ sample['sample_id'] }}" style="background-color: {{ sample['background_color'] }};">
|
||||||
<p style="font-size: 0.7em; text-align: center; word-wrap: break-word;">{{ sample['sample_id'] }}</p>
|
{% if creation %}
|
||||||
|
<p style="font-size: 0.7em; text-align: center; word-wrap: break-word;">{{ sample['sample_id'] }}</p>
|
||||||
|
{% else %}
|
||||||
|
<a class="data-link sample" id="{{ sample['sample_id'] }}">{{ sample['sample_id']}}</a><br>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from copy import copy
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
|
from pprint import pformat
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from inspect import getmembers, isfunction, stack
|
from inspect import getmembers, isfunction, stack
|
||||||
from dateutil.easter import easter
|
from dateutil.easter import easter
|
||||||
@@ -1039,7 +1040,7 @@ def flatten_list(input_list: list) -> list:
|
|||||||
return list(itertools.chain.from_iterable(input_list))
|
return list(itertools.chain.from_iterable(input_list))
|
||||||
|
|
||||||
|
|
||||||
def sanitize_object_for_json(input_dict: dict) -> dict:
|
def sanitize_object_for_json(input_dict: dict) -> dict | str:
|
||||||
"""
|
"""
|
||||||
Takes an object and makes sure its components can be converted to JSON
|
Takes an object and makes sure its components can be converted to JSON
|
||||||
|
|
||||||
@@ -1057,8 +1058,12 @@ def sanitize_object_for_json(input_dict: dict) -> dict:
|
|||||||
try:
|
try:
|
||||||
input_dict = json.dumps(input_dict)
|
input_dict = json.dumps(input_dict)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
input_dict = str(input_dict)
|
match input_dict:
|
||||||
return input_dict
|
case str():
|
||||||
|
pass
|
||||||
|
case _:
|
||||||
|
input_dict = str(input_dict)
|
||||||
|
return input_dict.strip('\"')
|
||||||
output = {}
|
output = {}
|
||||||
for key, value in input_dict.items():
|
for key, value in input_dict.items():
|
||||||
match value:
|
match value:
|
||||||
@@ -1070,7 +1075,13 @@ def sanitize_object_for_json(input_dict: dict) -> dict:
|
|||||||
try:
|
try:
|
||||||
value = json.dumps(value)
|
value = json.dumps(value)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
value = str(value)
|
match value:
|
||||||
|
case str():
|
||||||
|
pass
|
||||||
|
case _:
|
||||||
|
value = str(value)
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = value.strip('\"')
|
||||||
output[key] = value
|
output[key] = value
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user