Code cleanup for validators complete.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
'''
|
"""
|
||||||
Contains database, validators and excel operations.
|
Contains database, validators and excel operations.
|
||||||
'''
|
"""
|
||||||
from .db import *
|
from .db import *
|
||||||
from .excel import *
|
from .excel import *
|
||||||
from .validators import *
|
from .validators import *
|
||||||
@@ -48,8 +48,6 @@ class ClientSubmissionNamer(DefaultNamer):
|
|||||||
if not sub_type:
|
if not sub_type:
|
||||||
logger.warning(f"Getting submissiontype from regex failed, using default submissiontype.")
|
logger.warning(f"Getting submissiontype from regex failed, using default submissiontype.")
|
||||||
sub_type = SubmissionType.query(name="Default")
|
sub_type = SubmissionType.query(name="Default")
|
||||||
logger.debug(f"Submission Type: {sub_type}")
|
|
||||||
# sys.exit()
|
|
||||||
return sub_type
|
return sub_type
|
||||||
|
|
||||||
def get_subtype_from_regex(self) -> SubmissionType:
|
def get_subtype_from_regex(self) -> SubmissionType:
|
||||||
@@ -84,9 +82,6 @@ class ClientSubmissionNamer(DefaultNamer):
|
|||||||
return sub_type
|
return sub_type
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RSLNamer(object):
|
class RSLNamer(object):
|
||||||
"""
|
"""
|
||||||
Object that will enforce proper formatting on RSL plate names.
|
Object that will enforce proper formatting on RSL plate names.
|
||||||
@@ -98,17 +93,10 @@ class RSLNamer(object):
|
|||||||
self.submission_type = submission_type
|
self.submission_type = submission_type
|
||||||
if not self.submission_type:
|
if not self.submission_type:
|
||||||
self.submission_type = self.retrieve_submission_type(filename=filename)
|
self.submission_type = self.retrieve_submission_type(filename=filename)
|
||||||
# logger.info(f"got submission type: {self.submission_type}")
|
|
||||||
if self.submission_type:
|
if self.submission_type:
|
||||||
# self.sub_object = BasicRun.find_polymorphic_subclass(polymorphic_identity=self.submission_type)
|
|
||||||
self.sub_object = SubmissionType.query(name=self.submission_type['name'], limit=1)
|
self.sub_object = SubmissionType.query(name=self.submission_type['name'], limit=1)
|
||||||
self.parsed_name = self.retrieve_rsl_number(filename=filename, regex=self.sub_object.get_regex(
|
self.parsed_name = self.retrieve_rsl_number(filename=filename, regex=self.sub_object.get_regex(
|
||||||
submission_type=self.submission_type))
|
submission_type=self.submission_type))
|
||||||
# if not data:
|
|
||||||
# data = dict(submission_type=self.submission_type)
|
|
||||||
# if "proceduretype" not in data.keys():
|
|
||||||
# data['proceduretype'] = self.submission_type
|
|
||||||
# self.parsed_name = self.sub_object.enforce_name(instr=self.parsed_name, data=data)
|
|
||||||
logger.info(f"Parsed name: {self.parsed_name}")
|
logger.info(f"Parsed name: {self.parsed_name}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -227,7 +215,6 @@ class RSLNamer(object):
|
|||||||
Returns:
|
Returns:
|
||||||
str: Output filename
|
str: Output filename
|
||||||
"""
|
"""
|
||||||
logger.debug(data)
|
|
||||||
if "submitted_date" in data.keys():
|
if "submitted_date" in data.keys():
|
||||||
if isinstance(data['submitted_date'], dict):
|
if isinstance(data['submitted_date'], dict):
|
||||||
if data['submitted_date']['value'] is not None:
|
if data['submitted_date']['value'] is not None:
|
||||||
@@ -244,13 +231,8 @@ class RSLNamer(object):
|
|||||||
today = datetime.now()
|
today = datetime.now()
|
||||||
if isinstance(today, str):
|
if isinstance(today, str):
|
||||||
today = datetime.strptime(today, "%Y-%m-%d")
|
today = datetime.strptime(today, "%Y-%m-%d")
|
||||||
# if "name" in data.keys():
|
|
||||||
# logger.debug(f"Found name: {data['name']}")
|
|
||||||
# plate_number = data['name'].split("-")[-1][0]
|
|
||||||
# else:
|
|
||||||
previous = Run.query(start_date=today, end_date=today, submissiontype=data['submissiontype'])
|
previous = Run.query(start_date=today, end_date=today, submissiontype=data['submissiontype'])
|
||||||
plate_number = len(previous) + 1
|
plate_number = len(previous) + 1
|
||||||
logger.debug(f"Using plate number: {plate_number}")
|
|
||||||
return f"RSL-{data['abbreviation']}-{today.year}{str(today.month).zfill(2)}{str(today.day).zfill(2)}-{plate_number}"
|
return f"RSL-{data['abbreviation']}-{today.year}{str(today.month).zfill(2)}{str(today.day).zfill(2)}-{plate_number}"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -283,5 +265,5 @@ class RSLNamer(object):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
from .pydant import PydRun, PydKitType, PydContact, PydOrganization, PydSample, PydReagent, PydReagentRole, \
|
from .pydant import PydRun, PydKitType, PydContact, PydClientLab, PydSample, PydReagent, PydReagentRole, \
|
||||||
PydEquipment, PydEquipmentRole, PydTips, PydProcess, PydElastic, PydClientSubmission, PydProcedure, PydResults
|
PydEquipment, PydEquipmentRole, PydTips, PydProcess, PydElastic, PydClientSubmission, PydProcedure, PydResults
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from typing import List, Tuple, Literal
|
|||||||
from types import GeneratorType
|
from types import GeneratorType
|
||||||
from . import RSLNamer
|
from . import RSLNamer
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tools import check_not_nan, convert_nans_to_nones, Report, Result, timezone, sort_dict_by_list
|
from tools import check_not_nan, convert_nans_to_nones, Report, Result, timezone, sort_dict_by_list, row_keys
|
||||||
from backend.db import models
|
from backend.db import models
|
||||||
from backend.db.models import *
|
from backend.db.models import *
|
||||||
from sqlalchemy.exc import StatementError
|
from sqlalchemy.exc import StatementError
|
||||||
@@ -35,7 +35,6 @@ class PydBaseClass(BaseModel, extra='allow', validate_assignment=True):
|
|||||||
@model_validator(mode="before")
|
@model_validator(mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def prevalidate(cls, data):
|
def prevalidate(cls, data):
|
||||||
# logger.debug(f"Initial data for {cls.__name__}: {pformat(data)}")
|
|
||||||
sql_fields = [k for k, v in cls._sql_object.__dict__.items() if isinstance(v, InstrumentedAttribute)]
|
sql_fields = [k for k, v in cls._sql_object.__dict__.items() if isinstance(v, InstrumentedAttribute)]
|
||||||
output = {}
|
output = {}
|
||||||
try:
|
try:
|
||||||
@@ -54,9 +53,6 @@ class PydBaseClass(BaseModel, extra='allow', validate_assignment=True):
|
|||||||
@model_validator(mode='after')
|
@model_validator(mode='after')
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_model(cls, data):
|
def validate_model(cls, data):
|
||||||
# _sql_object = getattr(models, cls.__name__.replace("Pyd", ""))
|
|
||||||
|
|
||||||
# total_dict = data.model_fields.update(data.model_extra)
|
|
||||||
for key, value in data.model_extra.items():
|
for key, value in data.model_extra.items():
|
||||||
if key in cls._sql_object.timestamps:
|
if key in cls._sql_object.timestamps:
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
@@ -70,11 +66,11 @@ class PydBaseClass(BaseModel, extra='allow', validate_assignment=True):
|
|||||||
data.__setattr__(key, value)
|
data.__setattr__(key, value)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def __init__(self, **data):
|
# def __init__(self, **data):
|
||||||
# NOTE: Grab the sql model for validation purposes.
|
# # NOTE: Grab the sql model for validation purposes.
|
||||||
# self.__class__._sql_object = getattr(models, self.__class__.__name__.replace("Pyd", ""))
|
# # self.__class__._sql_object = getattr(models, self.__class__.__name__.replace("Pyd", ""))
|
||||||
|
#
|
||||||
super().__init__(**data)
|
# super().__init__(**data)
|
||||||
|
|
||||||
def filter_field(self, key: str) -> Any:
|
def filter_field(self, key: str) -> Any:
|
||||||
"""
|
"""
|
||||||
@@ -121,8 +117,6 @@ class PydBaseClass(BaseModel, extra='allow', validate_assignment=True):
|
|||||||
|
|
||||||
def to_sql(self):
|
def to_sql(self):
|
||||||
dicto = self.improved_dict(dictionaries=False)
|
dicto = self.improved_dict(dictionaries=False)
|
||||||
logger.debug(f"Dicto: {dicto}")
|
|
||||||
# sql, new = self._sql_object().query_or_create(**dicto)
|
|
||||||
sql, new = self._sql_object.query_or_create(**dicto)
|
sql, new = self._sql_object.query_or_create(**dicto)
|
||||||
if new:
|
if new:
|
||||||
logger.warning(f"Creating new {self._sql_object} with values:\n{pformat(dicto)}")
|
logger.warning(f"Creating new {self._sql_object} with values:\n{pformat(dicto)}")
|
||||||
@@ -226,11 +220,6 @@ class PydReagent(PydBaseClass):
|
|||||||
else:
|
else:
|
||||||
return values.data['reagentrole'].strip()
|
return values.data['reagentrole'].strip()
|
||||||
|
|
||||||
# @field_validator("reagentrole", mode="before")
|
|
||||||
# @classmethod
|
|
||||||
# def rescue_reagentrole(cls, value):
|
|
||||||
# if
|
|
||||||
|
|
||||||
def improved_dict(self) -> dict:
|
def improved_dict(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Constructs a dictionary consisting of model.fields and model.extras
|
Constructs a dictionary consisting of model.fields and model.extras
|
||||||
@@ -261,31 +250,11 @@ class PydReagent(PydBaseClass):
|
|||||||
reagentrole = ReagentRole.query(name=self.reagentrole)
|
reagentrole = ReagentRole.query(name=self.reagentrole)
|
||||||
reagent.reagentrole = reagentrole
|
reagent.reagentrole = reagentrole
|
||||||
reagent.expiry = self.expiry
|
reagent.expiry = self.expiry
|
||||||
# logger.debug(f"Reagent: {reagent}")
|
|
||||||
# if reagent is None:
|
|
||||||
# reagent = Reagent()
|
|
||||||
# for key, value in self.__dict__.items():
|
|
||||||
# if isinstance(value, dict):
|
|
||||||
# if key == "misc_info":
|
|
||||||
# value = value
|
|
||||||
# else:
|
|
||||||
# value = value['value']
|
|
||||||
# # NOTE: reagent method sets fields based on keys in dictionary
|
|
||||||
# reagent.set_attribute(key, value)
|
|
||||||
# if procedure is not None and reagent not in procedure.reagents:
|
|
||||||
# assoc = ProcedureReagentAssociation(reagent=reagent, procedure=procedure)
|
|
||||||
# assoc.comments = self.comment
|
|
||||||
# else:
|
|
||||||
# assoc = None
|
|
||||||
# else:
|
|
||||||
# if submission is not None and reagent not in submission.reagents:
|
|
||||||
# submission.update_reagentassoc(reagent=reagent, role=self.role)
|
|
||||||
return reagent, report
|
return reagent, report
|
||||||
|
|
||||||
|
|
||||||
class PydSample(PydBaseClass):
|
class PydSample(PydBaseClass):
|
||||||
sample_id: str
|
sample_id: str
|
||||||
# sampletype: str | None = Field(default=None)
|
|
||||||
submission_rank: int | List[int] | None = Field(default=0, validate_default=True)
|
submission_rank: int | List[int] | None = Field(default=0, validate_default=True)
|
||||||
enabled: bool = Field(default=True)
|
enabled: bool = Field(default=True)
|
||||||
row: int = Field(default=0)
|
row: int = Field(default=0)
|
||||||
@@ -328,7 +297,6 @@ class PydSample(PydBaseClass):
|
|||||||
def improved_dict(self, dictionaries: bool = True) -> dict:
|
def improved_dict(self, dictionaries: bool = True) -> dict:
|
||||||
output = super().improved_dict(dictionaries=dictionaries)
|
output = super().improved_dict(dictionaries=dictionaries)
|
||||||
output['name'] = self.sample_id
|
output['name'] = self.sample_id
|
||||||
# del output['sampletype']
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def to_sql(self):
|
def to_sql(self):
|
||||||
@@ -340,21 +308,6 @@ class PydSample(PydBaseClass):
|
|||||||
class PydTips(PydBaseClass):
|
class PydTips(PydBaseClass):
|
||||||
name: str
|
name: str
|
||||||
lot: str | None = Field(default=None)
|
lot: str | None = Field(default=None)
|
||||||
# tips: str
|
|
||||||
|
|
||||||
# @field_validator('tips', mode='before')
|
|
||||||
# @classmethod
|
|
||||||
# def get_role_name(cls, value):
|
|
||||||
# if isinstance(value, list):
|
|
||||||
# output = []
|
|
||||||
# for tips in value:
|
|
||||||
# if isinstance(tips, Tips):
|
|
||||||
# tips = tips.name
|
|
||||||
# output.append(tips)
|
|
||||||
# value = output
|
|
||||||
# if isinstance(value, Tips):
|
|
||||||
# value = value.name
|
|
||||||
# return value
|
|
||||||
|
|
||||||
@report_result
|
@report_result
|
||||||
def to_sql(self) -> Tuple[Tips, Report]:
|
def to_sql(self) -> Tuple[Tips, Report]:
|
||||||
@@ -369,9 +322,6 @@ class PydTips(PydBaseClass):
|
|||||||
"""
|
"""
|
||||||
report = Report()
|
report = Report()
|
||||||
tips = TipsLot.query(name=self.name, limit=1)
|
tips = TipsLot.query(name=self.name, limit=1)
|
||||||
# logger.debug(f"Tips query has yielded: {tips}")
|
|
||||||
# assoc = ProcedureTipsAssociation.query_or_create(tips=tips, procedure=procedure, tiprole=self.tiprole, limit=1)
|
|
||||||
# logger.debug(f"Got association: {assoc}")
|
|
||||||
return tips, report
|
return tips, report
|
||||||
|
|
||||||
|
|
||||||
@@ -379,7 +329,6 @@ class PydEquipment(PydBaseClass):
|
|||||||
asset_number: str
|
asset_number: str
|
||||||
name: str
|
name: str
|
||||||
nickname: str | None
|
nickname: str | None
|
||||||
# process: List[dict] | None
|
|
||||||
process: List[PydProcess] | PydProcess | None
|
process: List[PydProcess] | PydProcess | None
|
||||||
equipmentrole: str | PydEquipmentRole | None
|
equipmentrole: str | PydEquipmentRole | None
|
||||||
tips: List[PydTips] | PydTips | None = Field(default=[])
|
tips: List[PydTips] | PydTips | None = Field(default=[])
|
||||||
@@ -401,8 +350,6 @@ class PydEquipment(PydBaseClass):
|
|||||||
@field_validator('process', mode='before')
|
@field_validator('process', mode='before')
|
||||||
@classmethod
|
@classmethod
|
||||||
def process_to_pydantic(cls, value, values):
|
def process_to_pydantic(cls, value, values):
|
||||||
# if isinstance(value, dict):
|
|
||||||
# value = value['processes']
|
|
||||||
if isinstance(value, GeneratorType):
|
if isinstance(value, GeneratorType):
|
||||||
value = [item for item in value]
|
value = [item for item in value]
|
||||||
value = convert_nans_to_nones(value)
|
value = convert_nans_to_nones(value)
|
||||||
@@ -412,13 +359,9 @@ class PydEquipment(PydBaseClass):
|
|||||||
value = value.to_pydantic(pyd_model_name="PydProcess")
|
value = value.to_pydantic(pyd_model_name="PydProcess")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
# value = [item.strip() for item in value]
|
|
||||||
d: Process = next((process for process in value if values.data['name'] in [item.name for item in process.equipment]), None)
|
d: Process = next((process for process in value if values.data['name'] in [item.name for item in process.equipment]), None)
|
||||||
print(f"Next process: {d.details_dict()}")
|
|
||||||
if d:
|
if d:
|
||||||
# value = PydProcess(**d.details_dict())
|
|
||||||
value = d.to_pydantic()
|
value = d.to_pydantic()
|
||||||
# value = next((process.to_pydantic() for process in value))
|
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
logger.error(f"Process Validation error due to {e}")
|
logger.error(f"Process Validation error due to {e}")
|
||||||
pass
|
pass
|
||||||
@@ -427,8 +370,6 @@ class PydEquipment(PydBaseClass):
|
|||||||
@field_validator('tips', mode='before')
|
@field_validator('tips', mode='before')
|
||||||
@classmethod
|
@classmethod
|
||||||
def tips_to_pydantic(cls, value, values):
|
def tips_to_pydantic(cls, value, values):
|
||||||
# if isinstance(value, dict):
|
|
||||||
# value = value['processes']
|
|
||||||
if isinstance(value, GeneratorType):
|
if isinstance(value, GeneratorType):
|
||||||
value = [item for item in value]
|
value = [item for item in value]
|
||||||
value = convert_nans_to_nones(value)
|
value = convert_nans_to_nones(value)
|
||||||
@@ -438,44 +379,16 @@ class PydEquipment(PydBaseClass):
|
|||||||
value = value.to_pydantic(pyd_model_name="PydTips")
|
value = value.to_pydantic(pyd_model_name="PydTips")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
# value = [item.strip() for item in value]
|
|
||||||
d: Tips = next(
|
d: Tips = next(
|
||||||
(tips for tips in value if values.data['name'] in [item.name for item in tips.equipment]),
|
(tips for tips in value if values.data['name'] in [item.name for item in tips.equipment]),
|
||||||
None)
|
None)
|
||||||
print(f"Next process: {d.details_dict()}")
|
|
||||||
if d:
|
if d:
|
||||||
# value = PydProcess(**d.details_dict())
|
|
||||||
value = d.to_pydantic()
|
value = d.to_pydantic()
|
||||||
# value = next((process.to_pydantic() for process in value))
|
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
logger.error(f"Process Validation error due to {e}")
|
logger.error(f"Process Validation error due to {e}")
|
||||||
pass
|
pass
|
||||||
return value
|
return value
|
||||||
|
|
||||||
# @field_validator('tips', mode='before')
|
|
||||||
# @classmethod
|
|
||||||
# def tips_to_pydantic(cls, value):
|
|
||||||
# match value:
|
|
||||||
# case list():
|
|
||||||
# output = []
|
|
||||||
# for tips in value:
|
|
||||||
# match tips:
|
|
||||||
# case Tips():
|
|
||||||
# tips = tips.to_pydantic()
|
|
||||||
# case dict():
|
|
||||||
# tips = PydTips(**tips)
|
|
||||||
# case _:
|
|
||||||
# continue
|
|
||||||
# output.append(tips)
|
|
||||||
# case _:
|
|
||||||
# output = value
|
|
||||||
# return output
|
|
||||||
#
|
|
||||||
# @field_validator('tips')
|
|
||||||
# @classmethod
|
|
||||||
# def single_out_tips(cls, value, values):
|
|
||||||
# return value
|
|
||||||
|
|
||||||
@report_result
|
@report_result
|
||||||
def to_sql(self, procedure: Procedure | str = None, proceduretype: ProcedureType | str = None) -> Tuple[
|
def to_sql(self, procedure: Procedure | str = None, proceduretype: ProcedureType | str = None) -> Tuple[
|
||||||
Equipment, ProcedureEquipmentAssociation]:
|
Equipment, ProcedureEquipmentAssociation]:
|
||||||
@@ -493,7 +406,6 @@ class PydEquipment(PydBaseClass):
|
|||||||
procedure = Procedure.query(name=procedure)
|
procedure = Procedure.query(name=procedure)
|
||||||
if isinstance(proceduretype, str):
|
if isinstance(proceduretype, str):
|
||||||
proceduretype = ProcedureType.query(name=proceduretype)
|
proceduretype = ProcedureType.query(name=proceduretype)
|
||||||
logger.debug(f"Querying equipment: {self.asset_number}")
|
|
||||||
equipment = Equipment.query(asset_number=self.asset_number)
|
equipment = Equipment.query(asset_number=self.asset_number)
|
||||||
if equipment is None:
|
if equipment is None:
|
||||||
logger.error("No equipment found. Returning None.")
|
logger.error("No equipment found. Returning None.")
|
||||||
@@ -507,7 +419,6 @@ class PydEquipment(PydBaseClass):
|
|||||||
logger.error(f"Couldn't get association due to {e}, returning...")
|
logger.error(f"Couldn't get association due to {e}, returning...")
|
||||||
return None, None
|
return None, None
|
||||||
if new:
|
if new:
|
||||||
# assoc = ProcedureEquipmentAssociation(procedure=procedure, equipment=equipment)
|
|
||||||
# TODO: This seems precarious. What if there is more than one process?
|
# TODO: This seems precarious. What if there is more than one process?
|
||||||
# NOTE: It looks like the way fetching the process is done in the SQL model, this shouldn't be a problem, but I'll include a failsafe.
|
# NOTE: It looks like the way fetching the process is done in the SQL model, this shouldn't be a problem, but I'll include a failsafe.
|
||||||
# NOTE: I need to find a way to filter this by the kittype involved.
|
# NOTE: I need to find a way to filter this by the kittype involved.
|
||||||
@@ -517,7 +428,6 @@ class PydEquipment(PydBaseClass):
|
|||||||
process = Process.query(name=self.processes[0], limit=1)
|
process = Process.query(name=self.processes[0], limit=1)
|
||||||
if process is None:
|
if process is None:
|
||||||
logger.error(f"Found unknown process: {process}.")
|
logger.error(f"Found unknown process: {process}.")
|
||||||
logger.debug(f"Using process: {process}")
|
|
||||||
assoc.process = process
|
assoc.process = process
|
||||||
assoc.equipmentrole = self.equipmentrole
|
assoc.equipmentrole = self.equipmentrole
|
||||||
else:
|
else:
|
||||||
@@ -662,7 +572,6 @@ class PydRun(PydBaseClass): #, extra='allow'):
|
|||||||
if "pytest" in sys.modules and sub_type.replace(" ", "") == "BasicRun":
|
if "pytest" in sys.modules and sub_type.replace(" ", "") == "BasicRun":
|
||||||
output = "RSL-BS-Test001"
|
output = "RSL-BS-Test001"
|
||||||
else:
|
else:
|
||||||
# try:
|
|
||||||
output = RSLNamer(filename=sub_type.filepath.__str__(), submission_type=sub_type.submissiontype,
|
output = RSLNamer(filename=sub_type.filepath.__str__(), submission_type=sub_type.submissiontype,
|
||||||
data=values.data).parsed_name
|
data=values.data).parsed_name
|
||||||
return dict(value=output, missing=True)
|
return dict(value=output, missing=True)
|
||||||
@@ -685,10 +594,7 @@ class PydRun(PydBaseClass): #, extra='allow'):
|
|||||||
super().__init__(**data)
|
super().__init__(**data)
|
||||||
# NOTE: this could also be done with default_factory
|
# NOTE: this could also be done with default_factory
|
||||||
submission_type = self.clientsubmission.submissiontype
|
submission_type = self.clientsubmission.submissiontype
|
||||||
# logger.debug(submission_type)
|
|
||||||
self.namer = RSLNamer(self.rsl_plate_number['value'], submission_type=submission_type)
|
self.namer = RSLNamer(self.rsl_plate_number['value'], submission_type=submission_type)
|
||||||
# if run_custom:
|
|
||||||
# self.submission_object.custom_validation(pyd=self)
|
|
||||||
|
|
||||||
def set_attribute(self, key: str, value):
|
def set_attribute(self, key: str, value):
|
||||||
"""
|
"""
|
||||||
@@ -790,18 +696,14 @@ class PydRun(PydBaseClass): #, extra='allow'):
|
|||||||
"""
|
"""
|
||||||
report = Report()
|
report = Report()
|
||||||
dicto = self.improved_dict()
|
dicto = self.improved_dict()
|
||||||
# logger.debug(f"Pydantic procedure type: {self.proceduretype['value']}")
|
|
||||||
# logger.debug(f"Pydantic improved_dict: {pformat(dicto)}")
|
|
||||||
instance, result = Run.query_or_create(submissiontype=self.submission_type['value'],
|
instance, result = Run.query_or_create(submissiontype=self.submission_type['value'],
|
||||||
rsl_plate_number=self.rsl_plate_number['value'])
|
rsl_plate_number=self.rsl_plate_number['value'])
|
||||||
# logger.debug(f"Created or queried instance: {instance}")
|
|
||||||
if instance is None:
|
if instance is None:
|
||||||
report.add_result(Result(msg="Overwrite Cancelled."))
|
report.add_result(Result(msg="Overwrite Cancelled."))
|
||||||
return None, report
|
return None, report
|
||||||
report.add_result(result)
|
report.add_result(result)
|
||||||
self.handle_duplicate_samples()
|
self.handle_duplicate_samples()
|
||||||
for key, value in dicto.items():
|
for key, value in dicto.items():
|
||||||
# logger.debug(f"Checking key {key}, value {value}")
|
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
try:
|
try:
|
||||||
value = value['value']
|
value = value['value']
|
||||||
@@ -857,7 +759,6 @@ class PydRun(PydBaseClass): #, extra='allow'):
|
|||||||
value = value
|
value = value
|
||||||
instance.set_attribute(key=key, value=value)
|
instance.set_attribute(key=key, value=value)
|
||||||
case item if item in instance.jsons:
|
case item if item in instance.jsons:
|
||||||
# logger.debug(f"Validating json value: {item} to value:{pformat(value)}")
|
|
||||||
try:
|
try:
|
||||||
ii = value.items()
|
ii = value.items()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@@ -867,7 +768,6 @@ class PydRun(PydBaseClass): #, extra='allow'):
|
|||||||
value[k] = v.strftime("%Y-%m-%d %H:%M:%S")
|
value[k] = v.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
# logger.debug(f"Setting json value: {item} to value:{pformat(value)}")
|
|
||||||
instance.set_attribute(key=key, value=value)
|
instance.set_attribute(key=key, value=value)
|
||||||
case _:
|
case _:
|
||||||
try:
|
try:
|
||||||
@@ -914,22 +814,8 @@ class PydRun(PydBaseClass): #, extra='allow'):
|
|||||||
SubmissionFormWidget: Submission form widget
|
SubmissionFormWidget: Submission form widget
|
||||||
"""
|
"""
|
||||||
from frontend.widgets.submission_widget import SubmissionFormWidget
|
from frontend.widgets.submission_widget import SubmissionFormWidget
|
||||||
try:
|
|
||||||
logger.debug(f"PCR info: {self.pcr_info}")
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
return SubmissionFormWidget(parent=parent, pyd=self, disable=disable)
|
return SubmissionFormWidget(parent=parent, pyd=self, disable=disable)
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
def construct_filename(self) -> str:
|
def construct_filename(self) -> str:
|
||||||
"""
|
"""
|
||||||
Creates filename for this instance
|
Creates filename for this instance
|
||||||
@@ -942,45 +828,43 @@ class PydRun(PydBaseClass): #, extra='allow'):
|
|||||||
"/", "")
|
"/", "")
|
||||||
return render
|
return render
|
||||||
|
|
||||||
def check_kit_integrity(self, extraction_kit: str | dict | None = None, exempt: List[PydReagent] = []) -> Tuple[
|
# def check_kit_integrity(self, extraction_kit: str | dict | None = None, exempt: List[PydReagent] = []) -> Tuple[
|
||||||
List[PydReagent], Report, List[PydReagent]]:
|
# List[PydReagent], Report, List[PydReagent]]:
|
||||||
"""
|
# """
|
||||||
Ensures all reagents expected in kittype are listed in Submission
|
# Ensures all reagents expected in kittype are listed in Submission
|
||||||
|
#
|
||||||
Args:
|
# Args:
|
||||||
extraction_kit (str | dict | None, optional): kittype to be checked. Defaults to None.
|
# extraction_kit (str | dict | None, optional): kittype to be checked. Defaults to None.
|
||||||
exempt (List[PydReagent], optional): List of reagents that don't need to be checked. Defaults to []
|
# exempt (List[PydReagent], optional): List of reagents that don't need to be checked. Defaults to []
|
||||||
|
#
|
||||||
Returns:
|
# Returns:
|
||||||
Tuple[List[PydReagent], Report]: List of reagents and Result object containing a message and any missing components.
|
# Tuple[List[PydReagent], Report]: List of reagents and Result object containing a message and any missing components.
|
||||||
"""
|
# """
|
||||||
report = Report()
|
# report = Report()
|
||||||
# logger.debug(f"The following reagents are exempt from the kittype integrity check:\n{exempt}")
|
# if isinstance(extraction_kit, str):
|
||||||
if isinstance(extraction_kit, str):
|
# extraction_kit = dict(value=extraction_kit)
|
||||||
extraction_kit = dict(value=extraction_kit)
|
# if extraction_kit is not None and extraction_kit != self.extraction_kit['value']:
|
||||||
if extraction_kit is not None and extraction_kit != self.extraction_kit['value']:
|
# self.extraction_kit['value'] = extraction_kit['value']
|
||||||
self.extraction_kit['value'] = extraction_kit['value']
|
# ext_kit = KitType.query(name=self.extraction_kit['value'])
|
||||||
ext_kit = KitType.query(name=self.extraction_kit['value'])
|
# ext_kit_rtypes = [item.to_pydantic() for item in
|
||||||
ext_kit_rtypes = [item.to_pydantic() for item in
|
# ext_kit.get_reagents(required_only=True, proceduretype=self.submission_type['value'])]
|
||||||
ext_kit.get_reagents(required_only=True, proceduretype=self.submission_type['value'])]
|
# # NOTE: Exclude any reagenttype found in this pydclientsubmission not expected in kittype.
|
||||||
# NOTE: Exclude any reagenttype found in this pydclientsubmission not expected in kittype.
|
# expected_check = [item.equipmentrole for item in ext_kit_rtypes]
|
||||||
expected_check = [item.equipmentrole for item in ext_kit_rtypes]
|
# output_reagents = [rt for rt in self.reagents if rt.role in expected_check]
|
||||||
output_reagents = [rt for rt in self.reagents if rt.role in expected_check]
|
# missing_check = [item.role for item in output_reagents]
|
||||||
missing_check = [item.role for item in output_reagents]
|
# missing_reagents = [rt for rt in ext_kit_rtypes if
|
||||||
missing_reagents = [rt for rt in ext_kit_rtypes if
|
# rt.equipmentrole not in missing_check and rt.equipmentrole not in exempt]
|
||||||
rt.equipmentrole not in missing_check and rt.equipmentrole not in exempt]
|
# missing_reagents += [rt for rt in output_reagents if rt.missing]
|
||||||
# logger.debug(f"Missing reagents: {missing_reagents}")
|
# output_reagents += [rt for rt in missing_reagents if rt not in output_reagents]
|
||||||
missing_reagents += [rt for rt in output_reagents if rt.missing]
|
# # NOTE: if lists are equal return no problem
|
||||||
output_reagents += [rt for rt in missing_reagents if rt not in output_reagents]
|
# if len(missing_reagents) == 0:
|
||||||
# NOTE: if lists are equal return no problem
|
# result = None
|
||||||
if len(missing_reagents) == 0:
|
# else:
|
||||||
result = None
|
# result = Result(
|
||||||
else:
|
# msg=f"The excel sheet you are importing is missing some reagents expected by the kittype.\n\nIt looks like you are missing: {[item.equipmentrole.upper() for item in missing_reagents]}\n\nAlternatively, you may have set the wrong extraction kittype.\n\nThe program will populate lists using existing reagents.\n\nPlease make sure you check the lots carefully!",
|
||||||
result = Result(
|
# status="Warning")
|
||||||
msg=f"The excel sheet you are importing is missing some reagents expected by the kittype.\n\nIt looks like you are missing: {[item.equipmentrole.upper() for item in missing_reagents]}\n\nAlternatively, you may have set the wrong extraction kittype.\n\nThe program will populate lists using existing reagents.\n\nPlease make sure you check the lots carefully!",
|
# report.add_result(result)
|
||||||
status="Warning")
|
# return output_reagents, report, missing_reagents
|
||||||
report.add_result(result)
|
|
||||||
return output_reagents, report, missing_reagents
|
|
||||||
|
|
||||||
def check_reagent_expiries(self, exempt: List[PydReagent] = []):
|
def check_reagent_expiries(self, exempt: List[PydReagent] = []):
|
||||||
report = Report()
|
report = Report()
|
||||||
@@ -1039,9 +923,7 @@ class PydContact(BaseModel):
|
|||||||
area_regex = re.compile(r"^\(?(\d{3})\)?(-| )?")
|
area_regex = re.compile(r"^\(?(\d{3})\)?(-| )?")
|
||||||
if len(value) > 8:
|
if len(value) > 8:
|
||||||
match = area_regex.match(value)
|
match = area_regex.match(value)
|
||||||
# logger.debug(f"Match: {match.group(1)}")
|
|
||||||
value = area_regex.sub(f"({match.group(1).strip()}) ", value)
|
value = area_regex.sub(f"({match.group(1).strip()}) ", value)
|
||||||
# logger.debug(f"Output phone: {value}")
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@report_result
|
@report_result
|
||||||
@@ -1065,7 +947,7 @@ class PydContact(BaseModel):
|
|||||||
value = getattr(self, field)
|
value = getattr(self, field)
|
||||||
match field:
|
match field:
|
||||||
case "organization":
|
case "organization":
|
||||||
value = [Organization.query(name=value)]
|
value = [ClientLab.query(name=value)]
|
||||||
case _:
|
case _:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
@@ -1075,7 +957,7 @@ class PydContact(BaseModel):
|
|||||||
return instance, report
|
return instance, report
|
||||||
|
|
||||||
|
|
||||||
class PydOrganization(BaseModel):
|
class PydClientLab(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
cost_centre: str
|
cost_centre: str
|
||||||
contact: List[PydContact] | None
|
contact: List[PydContact] | None
|
||||||
@@ -1109,7 +991,6 @@ class PydOrganization(BaseModel):
|
|||||||
value = [item.to_sql() for item in value if item]
|
value = [item.to_sql() for item in value if item]
|
||||||
case _:
|
case _:
|
||||||
value = getattr(self, field)
|
value = getattr(self, field)
|
||||||
logger.debug(f"Setting {field} to {value}")
|
|
||||||
if value:
|
if value:
|
||||||
setattr(instance, field, value)
|
setattr(instance, field, value)
|
||||||
return instance, report
|
return instance, report
|
||||||
@@ -1128,50 +1009,50 @@ class PydReagentRole(BaseModel):
|
|||||||
return timedelta(days=value)
|
return timedelta(days=value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@report_result
|
# @report_result
|
||||||
def to_sql(self, kit: KitType) -> ReagentRole:
|
# def to_sql(self, kit: KitType) -> ReagentRole:
|
||||||
"""
|
# """
|
||||||
Converts this instance into a backend.db.models.ReagentType instance
|
# Converts this instance into a backend.db.models.ReagentType instance
|
||||||
|
#
|
||||||
Args:
|
# Args:
|
||||||
kit (KitType): KitType joined to the reagentrole
|
# kit (KitType): KitType joined to the reagentrole
|
||||||
|
#
|
||||||
Returns:
|
# Returns:
|
||||||
ReagentRole: ReagentType instance
|
# ReagentRole: ReagentType instance
|
||||||
"""
|
# """
|
||||||
report = Report()
|
# report = Report()
|
||||||
instance: ReagentRole = ReagentRole.query(name=self.name)
|
# instance: ReagentRole = ReagentRole.query(name=self.name)
|
||||||
if instance is None:
|
# if instance is None:
|
||||||
instance = ReagentRole(name=self.name, eol_ext=self.eol_ext)
|
# instance = ReagentRole(name=self.name, eol_ext=self.eol_ext)
|
||||||
try:
|
# try:
|
||||||
assoc = KitTypeReagentRoleAssociation.query(reagentrole=instance, kittype=kit)
|
# assoc = KitTypeReagentRoleAssociation.query(reagentrole=instance, kittype=kit)
|
||||||
except StatementError:
|
# except StatementError:
|
||||||
assoc = None
|
# assoc = None
|
||||||
if assoc is None:
|
# if assoc is None:
|
||||||
assoc = KitTypeReagentRoleAssociation(kittype=kit, reagentrole=instance, uses=self.uses,
|
# assoc = KitTypeReagentRoleAssociation(kittype=kit, reagentrole=instance, uses=self.uses,
|
||||||
required=self.required)
|
# required=self.required)
|
||||||
return instance, report
|
# return instance, report
|
||||||
|
|
||||||
|
|
||||||
class PydKitType(BaseModel):
|
# class PydKitType(BaseModel):
|
||||||
name: str
|
# name: str
|
||||||
reagent_roles: List[PydReagent] = []
|
# reagent_roles: List[PydReagent] = []
|
||||||
|
#
|
||||||
@report_result
|
# @report_result
|
||||||
def to_sql(self) -> Tuple[KitType, Report]:
|
# def to_sql(self) -> Tuple[KitType, Report]:
|
||||||
"""
|
# """
|
||||||
Converts this instance into a backend.db.models.kits.KitType instance
|
# Converts this instance into a backend.db.models.kits.KitType instance
|
||||||
|
#
|
||||||
Returns:
|
# Returns:
|
||||||
Tuple[KitType, Report]: KitType instance and report of results.
|
# Tuple[KitType, Report]: KitType instance and report of results.
|
||||||
"""
|
# """
|
||||||
report = Report()
|
# report = Report()
|
||||||
instance = KitType.query(name=self.name)
|
# instance = KitType.query(name=self.name)
|
||||||
if instance is None:
|
# if instance is None:
|
||||||
instance = KitType(name=self.name)
|
# instance = KitType(name=self.name)
|
||||||
for role in self.reagent_roles:
|
# for role in self.reagent_roles:
|
||||||
role.to_sql(instance)
|
# role.to_sql(instance)
|
||||||
return instance, report
|
# return instance, report
|
||||||
|
|
||||||
|
|
||||||
class PydEquipmentRole(BaseModel):
|
class PydEquipmentRole(BaseModel):
|
||||||
@@ -1210,7 +1091,6 @@ class PydProcess(PydBaseClass, extra="allow"):
|
|||||||
@field_validator("tips", mode="before")
|
@field_validator("tips", mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def enforce_list(cls, value):
|
def enforce_list(cls, value):
|
||||||
# logger.debug(f"Validating field: {value}")
|
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
value = [value]
|
value = [value]
|
||||||
output = []
|
output = []
|
||||||
@@ -1240,10 +1120,8 @@ class PydProcess(PydBaseClass, extra="allow"):
|
|||||||
def to_sql(self):
|
def to_sql(self):
|
||||||
report = Report()
|
report = Report()
|
||||||
name = self.name.split("-")[0]
|
name = self.name.split("-")[0]
|
||||||
logger.debug(f"Query process: {self.name}, version = {self.version}")
|
|
||||||
# NOTE: can't use query_or_create due to name not being part of ProcessVersion
|
# NOTE: can't use query_or_create due to name not being part of ProcessVersion
|
||||||
instance = ProcessVersion.query(name=name, version=self.version, limit=1)
|
instance = ProcessVersion.query(name=name, version=self.version, limit=1)
|
||||||
logger.debug(f"Got instance: {instance}")
|
|
||||||
if not instance:
|
if not instance:
|
||||||
instance = ProcessVersion()
|
instance = ProcessVersion()
|
||||||
return instance, report
|
return instance, report
|
||||||
@@ -1255,7 +1133,6 @@ class PydElastic(BaseModel, extra="allow", arbitrary_types_allowed=True):
|
|||||||
|
|
||||||
@report_result
|
@report_result
|
||||||
def to_sql(self):
|
def to_sql(self):
|
||||||
# print(self.instance)
|
|
||||||
fields = [item for item in self.model_extra]
|
fields = [item for item in self.model_extra]
|
||||||
for field in fields:
|
for field in fields:
|
||||||
try:
|
try:
|
||||||
@@ -1265,11 +1142,8 @@ class PydElastic(BaseModel, extra="allow", arbitrary_types_allowed=True):
|
|||||||
continue
|
continue
|
||||||
match field_type:
|
match field_type:
|
||||||
case _RelationshipDeclared():
|
case _RelationshipDeclared():
|
||||||
# logger.debug(f"{field} is a relationship with {field_type.entity.class_}")
|
|
||||||
field_value = field_type.entity.class_.argument.query(name=getattr(self, field))
|
field_value = field_type.entity.class_.argument.query(name=getattr(self, field))
|
||||||
# logger.debug(f"{field} query result: {field_value}")
|
|
||||||
case ColumnProperty():
|
case ColumnProperty():
|
||||||
# logger.debug(f"{field} is a property.")
|
|
||||||
field_value = getattr(self, field)
|
field_value = getattr(self, field)
|
||||||
self.instance.__setattr__(field, field_value)
|
self.instance.__setattr__(field, field_value)
|
||||||
return self.instance
|
return self.instance
|
||||||
@@ -1343,26 +1217,11 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
|
|||||||
@field_validator("reagentrole")
|
@field_validator("reagentrole")
|
||||||
@classmethod
|
@classmethod
|
||||||
def rescue_reagentrole(cls, value, values):
|
def rescue_reagentrole(cls, value, values):
|
||||||
# if not value:
|
|
||||||
# match values.data['kittype']:
|
|
||||||
# case dict():
|
|
||||||
# if "value" in values.data['kittype'].keys():
|
|
||||||
# roi = values.data['kittype']['value']
|
|
||||||
# elif "name" in values.data['kittype'].keys():
|
|
||||||
# roi = values.data['kittype']['name']
|
|
||||||
# else:
|
|
||||||
# raise KeyError(f"Couldn't find kittype name in the dictionary: {values.data['kittype']}")
|
|
||||||
# case str():
|
|
||||||
# roi = values.data['kittype']
|
|
||||||
# if roi != cls.model_fields['kittype'].default['value']:
|
|
||||||
# kittype = KitType.query(name=roi)
|
|
||||||
# value = {item.name: item.reagent for item in kittype.reagentrole}
|
|
||||||
if not value:
|
if not value:
|
||||||
value = {}
|
value = {}
|
||||||
for reagentrole in values.data['proceduretype'].reagentrole:
|
for reagentrole in values.data['proceduretype'].reagentrole:
|
||||||
reagents = [reagent.lot_dicts for reagent in reagentrole.reagent]
|
reagents = [reagent.lot_dicts for reagent in reagentrole.reagent]
|
||||||
value[reagentrole.name] = flatten_list(reagents)
|
value[reagentrole.name] = flatten_list(reagents)
|
||||||
# value = {item.name: item.reagent for item in values.data['proceduretype'].reagentrole}
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@field_validator("run")
|
@field_validator("run")
|
||||||
@@ -1400,25 +1259,25 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
return len(self.sample)
|
return len(self.sample)
|
||||||
|
|
||||||
def update_kittype_reagentroles(self, kittype: str | KitType):
|
# def update_kittype_reagentroles(self, kittype: str | KitType):
|
||||||
if kittype == self.__class__.model_fields['kittype'].default['value']:
|
# if kittype == self.__class__.model_fields['kittype'].default['value']:
|
||||||
return
|
# return
|
||||||
if isinstance(kittype, str):
|
# if isinstance(kittype, str):
|
||||||
kittype_obj = KitType.query(name=kittype)
|
# kittype_obj = KitType.query(name=kittype)
|
||||||
try:
|
# try:
|
||||||
self.reagentrole = {
|
# self.reagentrole = {
|
||||||
item.name: item.get_reagents(kittype=kittype_obj) + [PydReagent(name="--New--", lot="", reagentrole="")]
|
# item.name: item.get_reagents(kittype=kittype_obj) + [PydReagent(name="--New--", lot="", reagentrole="")]
|
||||||
for item in
|
# for item in
|
||||||
kittype_obj.get_reagents(proceduretype=self.proceduretype)}
|
# kittype_obj.get_reagents(proceduretype=self.proceduretype)}
|
||||||
except AttributeError:
|
# except AttributeError:
|
||||||
self.reagentrole = {}
|
# self.reagentrole = {}
|
||||||
reordered_options = {}
|
# reordered_options = {}
|
||||||
if self.reagentrole:
|
# if self.reagentrole:
|
||||||
for k, v in self.reagentrole.items():
|
# for k, v in self.reagentrole.items():
|
||||||
reordered_options[k] = self.reorder_reagents(reagentrole=k, options=v)
|
# reordered_options[k] = self.reorder_reagents(reagentrole=k, options=v)
|
||||||
self.reagentrole = reordered_options
|
# self.reagentrole = reordered_options
|
||||||
self.kittype['value'] = kittype
|
# self.kittype['value'] = kittype
|
||||||
self.possible_kits.insert(0, self.possible_kits.pop(self.possible_kits.index(kittype)))
|
# self.possible_kits.insert(0, self.possible_kits.pop(self.possible_kits.index(kittype)))
|
||||||
|
|
||||||
def reorder_reagents(self, reagentrole: str, options: list):
|
def reorder_reagents(self, reagentrole: str, options: list):
|
||||||
reagent_used = next((reagent for reagent in self.reagent if reagent.reagentrole == reagentrole), None)
|
reagent_used = next((reagent for reagent in self.reagent if reagent.reagentrole == reagentrole), None)
|
||||||
@@ -1430,26 +1289,24 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
|
|||||||
options.insert(0, options.pop(options.index(roi)))
|
options.insert(0, options.pop(options.index(roi)))
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def update_kittype_equipmentroles(self, kittype: str | KitType):
|
# def update_kittype_equipmentroles(self, kittype: str | KitType):
|
||||||
if kittype == self.__class__.model_fields['kittype'].default['value']:
|
# if kittype == self.__class__.model_fields['kittype'].default['value']:
|
||||||
return
|
# return
|
||||||
if isinstance(kittype, str):
|
# if isinstance(kittype, str):
|
||||||
kittype_obj = KitType.query(name=kittype)
|
# kittype_obj = KitType.query(name=kittype)
|
||||||
try:
|
# try:
|
||||||
self.equipment = {item.name: item.get_reagents(kittype=kittype_obj) for item in
|
# self.equipment = {item.name: item.get_reagents(kittype=kittype_obj) for item in
|
||||||
kittype_obj.get_reagents(proceduretype=self.proceduretype)}
|
# kittype_obj.get_reagents(proceduretype=self.proceduretype)}
|
||||||
except AttributeError:
|
# except AttributeError:
|
||||||
self.reagentrole = {}
|
# self.reagentrole = {}
|
||||||
self.kittype['value'] = kittype
|
# self.kittype['value'] = kittype
|
||||||
self.possible_kits.insert(0, self.possible_kits.pop(self.possible_kits.index(kittype)))
|
# self.possible_kits.insert(0, self.possible_kits.pop(self.possible_kits.index(kittype)))
|
||||||
|
|
||||||
def update_samples(self, sample_list: List[dict]):
|
def update_samples(self, sample_list: List[dict]):
|
||||||
# logger.debug(f"Incoming sample_list:\n{pformat(sample_list)}")
|
|
||||||
for iii, sample_dict in enumerate(sample_list, start=1):
|
for iii, sample_dict in enumerate(sample_list, start=1):
|
||||||
if sample_dict['sample_id'].startswith("blank_"):
|
if sample_dict['sample_id'].startswith("blank_"):
|
||||||
sample_dict['sample_id'] = ""
|
sample_dict['sample_id'] = ""
|
||||||
row, column = self.proceduretype.ranked_plate[sample_dict['index']]
|
row, column = self.proceduretype.ranked_plate[sample_dict['index']]
|
||||||
# logger.debug(f"Row: {row}, Column: {column}")
|
|
||||||
try:
|
try:
|
||||||
sample = next(
|
sample = next(
|
||||||
(item for item in self.sample if item.sample_id.upper() == sample_dict['sample_id'].upper()))
|
(item for item in self.sample if item.sample_id.upper() == sample_dict['sample_id'].upper()))
|
||||||
@@ -1468,8 +1325,6 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
|
|||||||
sample.row = row
|
sample.row = row
|
||||||
sample.column = column
|
sample.column = column
|
||||||
sample.procedure_rank = sample_dict['index']
|
sample.procedure_rank = sample_dict['index']
|
||||||
# logger.debug(f"Sample of interest: {sample.improved_dict()}")
|
|
||||||
# logger.debug(f"Updated samples:\n{pformat(self.sample)}")
|
|
||||||
|
|
||||||
def update_reagents(self, reagentrole: str, name: str, lot: str, expiry: str):
|
def update_reagents(self, reagentrole: str, name: str, lot: str, expiry: str):
|
||||||
try:
|
try:
|
||||||
@@ -1484,7 +1339,6 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
|
|||||||
idx = 0
|
idx = 0
|
||||||
insertable = PydReagent(reagentrole=reagentrole, name=name, lot=lot, expiry=expiry)
|
insertable = PydReagent(reagentrole=reagentrole, name=name, lot=lot, expiry=expiry)
|
||||||
self.reagent.insert(idx, insertable)
|
self.reagent.insert(idx, insertable)
|
||||||
# logger.debug(self.reagent)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_new_reagents(cls, reagent: PydReagent):
|
def update_new_reagents(cls, reagent: PydReagent):
|
||||||
@@ -1505,7 +1359,6 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
|
|||||||
sql.technician = self.technician['value']
|
sql.technician = self.technician['value']
|
||||||
else:
|
else:
|
||||||
sql.technician = self.technician
|
sql.technician = self.technician
|
||||||
# sql.repeat = int(self.repeat)
|
|
||||||
if sql.repeat:
|
if sql.repeat:
|
||||||
regex = re.compile(r".*\dR\d$")
|
regex = re.compile(r".*\dR\d$")
|
||||||
repeats = [item for item in self.run.procedure if
|
repeats = [item for item in self.run.procedure if
|
||||||
@@ -1529,14 +1382,12 @@ class PydProcedure(PydBaseClass, arbitrary_types_allowed=True):
|
|||||||
removable = ProcedureReagentLotAssociation.query(procedure=sql, reagentrole=reagentrole)
|
removable = ProcedureReagentLotAssociation.query(procedure=sql, reagentrole=reagentrole)
|
||||||
else:
|
else:
|
||||||
removable = []
|
removable = []
|
||||||
logger.debug(f"Removable: {removable}")
|
|
||||||
if removable:
|
if removable:
|
||||||
if isinstance(removable, list):
|
if isinstance(removable, list):
|
||||||
for r in removable:
|
for r in removable:
|
||||||
r.delete()
|
r.delete()
|
||||||
else:
|
else:
|
||||||
removable.delete()
|
removable.delete()
|
||||||
logger.debug(f"Adding {reagent} to {sql}")
|
|
||||||
reagent_assoc = ProcedureReagentLotAssociation(reagentlot=reagent, procedure=sql, reagentrole=reagentrole)
|
reagent_assoc = ProcedureReagentLotAssociation(reagentlot=reagent, procedure=sql, reagentrole=reagentrole)
|
||||||
try:
|
try:
|
||||||
start_index = max([item.id for item in ProcedureSampleAssociation.query()]) + 1
|
start_index = max([item.id for item in ProcedureSampleAssociation.query()]) + 1
|
||||||
@@ -1603,13 +1454,6 @@ class PydClientSubmission(PydBaseClass):
|
|||||||
submitter_plate_id: dict | None = Field(default=dict(value=None, missing=True), validate_default=True)
|
submitter_plate_id: dict | None = Field(default=dict(value=None, missing=True), validate_default=True)
|
||||||
sample: List[PydSample] | None = Field(default=[])
|
sample: List[PydSample] | None = Field(default=[])
|
||||||
|
|
||||||
# @field_validator("submissiontype", mode="before")
|
|
||||||
# @classmethod
|
|
||||||
# def enforce_submissiontype(cls, value):
|
|
||||||
# if isinstance(value, str):
|
|
||||||
# value = dict(value=value, missing=False)
|
|
||||||
# return value
|
|
||||||
|
|
||||||
@field_validator("submissiontype", "clientlab", "contact", mode="before")
|
@field_validator("submissiontype", "clientlab", "contact", mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def enforce_value(cls, value):
|
def enforce_value(cls, value):
|
||||||
@@ -1728,7 +1572,6 @@ class PydClientSubmission(PydBaseClass):
|
|||||||
"""
|
"""
|
||||||
from frontend.widgets.submission_widget import ClientSubmissionFormWidget
|
from frontend.widgets.submission_widget import ClientSubmissionFormWidget
|
||||||
if not samples:
|
if not samples:
|
||||||
# samples = [sample for sample in self.sample if sample.sample_id.lower() not in ["", "blank"]]
|
|
||||||
samples = self.sample
|
samples = self.sample
|
||||||
return ClientSubmissionFormWidget(parent=parent, clientsubmission=self, samples=samples, disable=disable)
|
return ClientSubmissionFormWidget(parent=parent, clientsubmission=self, samples=samples, disable=disable)
|
||||||
|
|
||||||
@@ -1736,11 +1579,6 @@ class PydClientSubmission(PydBaseClass):
|
|||||||
sql = super().to_sql()
|
sql = super().to_sql()
|
||||||
assert not any([isinstance(item, PydSample) for item in sql.sample])
|
assert not any([isinstance(item, PydSample) for item in sql.sample])
|
||||||
sql.sample = []
|
sql.sample = []
|
||||||
# if "info_placement" not in sql._misc_info:
|
|
||||||
# sql._misc_info['info_placement'] = []
|
|
||||||
# info_placement = []
|
|
||||||
logger.debug(f"PYD Submission type: {self.submissiontype}")
|
|
||||||
logger.debug(f"SQL Submission Type: {sql.submissiontype}")
|
|
||||||
if not sql.submissiontype:
|
if not sql.submissiontype:
|
||||||
sql.submissiontype = SubmissionType.query(name=self.submissiontype['value'])
|
sql.submissiontype = SubmissionType.query(name=self.submissiontype['value'])
|
||||||
match sql.submissiontype:
|
match sql.submissiontype:
|
||||||
@@ -1749,7 +1587,6 @@ class PydClientSubmission(PydBaseClass):
|
|||||||
case _:
|
case _:
|
||||||
sql.submissiontype = SubmissionType.query(name="Default")
|
sql.submissiontype = SubmissionType.query(name="Default")
|
||||||
for k in list(self.model_fields.keys()) + list(self.model_extra.keys()):
|
for k in list(self.model_fields.keys()) + list(self.model_extra.keys()):
|
||||||
logger.debug(f"Running {k}")
|
|
||||||
attribute = getattr(self, k)
|
attribute = getattr(self, k)
|
||||||
match k:
|
match k:
|
||||||
case "filepath":
|
case "filepath":
|
||||||
@@ -1757,14 +1594,6 @@ class PydClientSubmission(PydBaseClass):
|
|||||||
continue
|
continue
|
||||||
case _:
|
case _:
|
||||||
pass
|
pass
|
||||||
# logger.debug(f"Setting {k} to {attribute}")
|
|
||||||
# if isinstance(attribute, dict):
|
|
||||||
# if "location" in attribute:
|
|
||||||
# info_placement.append(dict(name=k, location=attribute['location']))
|
|
||||||
# else:
|
|
||||||
# info_placement.append(dict(name=k, location=None))
|
|
||||||
# # max_row = max([value['location']['row'] for value in info_placement if value])
|
|
||||||
# sql._misc_info['info_placement'] = info_placement
|
|
||||||
return sql
|
return sql
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -1775,19 +1604,6 @@ class PydClientSubmission(PydBaseClass):
|
|||||||
else:
|
else:
|
||||||
return max([item.submission_rank for item in self.sample])
|
return max([item.submission_rank for item in self.sample])
|
||||||
|
|
||||||
# def pad_samples_to_length(self, row_count, column_names):
|
|
||||||
# output_samples = []
|
|
||||||
# for iii in range(1, row_count + 1):
|
|
||||||
# try:
|
|
||||||
# sample = next((item for item in self.samples if item.submission_rank == iii))
|
|
||||||
# except StopIteration:
|
|
||||||
# sample = PydSample(sample_id="")
|
|
||||||
# for column in column_names:
|
|
||||||
# setattr(sample, column[0], "")
|
|
||||||
# sample.submission_rank = iii
|
|
||||||
# output_samples.append(sample)
|
|
||||||
# return sorted(output_samples, key=lambda x: x.submission_rank)
|
|
||||||
|
|
||||||
def improved_dict(self, dictionaries: bool = True) -> dict:
|
def improved_dict(self, dictionaries: bool = True) -> dict:
|
||||||
output = super().improved_dict(dictionaries=dictionaries)
|
output = super().improved_dict(dictionaries=dictionaries)
|
||||||
output['sample'] = self.sample
|
output['sample'] = self.sample
|
||||||
@@ -1798,10 +1614,6 @@ class PydClientSubmission(PydBaseClass):
|
|||||||
pass
|
pass
|
||||||
return sort_dict_by_list(output, self.key_value_order)
|
return sort_dict_by_list(output, self.key_value_order)
|
||||||
|
|
||||||
# @property
|
|
||||||
# def writable_dict(self):
|
|
||||||
# output = self.improved_dict()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filename_template(self):
|
def filename_template(self):
|
||||||
submissiontype = SubmissionType.query(name=self.submissiontype['value'])
|
submissiontype = SubmissionType.query(name=self.submissiontype['value'])
|
||||||
|
|||||||
Reference in New Issue
Block a user