# File: replicate.py
# Project: core
# Author: Jan Range
# License: BSD-2 clause
# Copyright (c) 2022 Institute of Biochemistry and Technical Biochemistry Stuttgart
from pydantic import Field, validator, PrivateAttr
from typing import List, TYPE_CHECKING, Optional
from dataclasses import dataclass
from pyenzyme.enzymeml.core.enzymemlbase import EnzymeMLBase
from pyenzyme.enzymeml.core.ontology import DataTypes
from pyenzyme.enzymeml.core.exceptions import DataError
from pyenzyme.enzymeml.core.utils import type_checking, deprecated_getter
if TYPE_CHECKING: # pragma: no cover
static_check_init_args = dataclass
else:
static_check_init_args = type_checking
[docs]@static_check_init_args
class Replicate(EnzymeMLBase):
id: str = Field(
...,
description="Unique identifier of the replicate",
)
species_id: str = Field(
...,
description="Unique identifier of the species that has been measured.",
regex=r"[s|r|p][\d]+",
)
measurement_id: Optional[str] = Field(
None,
description="Unique identifier of the measurement that the replicate is part of.",
regex=r"m[\d]+",
)
data_type: DataTypes = Field(
DataTypes.CONCENTRATION,
description="Type of data that was measured (e.g. concentration)",
)
data_unit: str = Field(
...,
description="SI unit of the data that was measured.",
)
time_unit: str = Field(
...,
description="Time unit of the replicate.",
)
time: List[float] = Field(
None,
description="Time steps of the replicate.",
)
data: List[float] = Field(
None,
description="Data that was measured.",
)
is_calculated: bool = Field(
False,
description="Whether or not the data has been generated by simulation.",
)
uri: Optional[str] = Field(
None,
description="URI of the protein.",
)
creator_id: Optional[str] = Field(
None,
description="Unique identifier of the author.",
)
# * Private
_time_unit_id: Optional[str] = PrivateAttr(None)
_data_unit_id: Optional[str] = PrivateAttr(None)
_enzmldoc = PrivateAttr(default=None)
[docs] @validator("data")
def check_data_completeness(cls, data: List[float], values: dict):
if values.get("time") is None and data is not None:
# Check if time is given
raise DataError(
"No time values provided for the data yet. \
Please include time values too, using the 'time' attribute"
)
elif values.get("time"):
# Check if the data complies with the time values
timesteps = len(values["time"])
if timesteps != len(data):
raise DataError(
f"The number of steps provided for the data [{len(data)}] does not match the number of timesteps [{timesteps}] for replicate '{values['id']}'"
)
return data
# ! Getters
[docs] def data_unitdef(self):
"""Returns the appropriate unitdef if an enzmldoc is given"""
if not self._enzmldoc:
return None
return self._enzmldoc._unit_dict[self._data_unit_id]
[docs] def time_unitdef(self):
"""Returns the appropriate unitdef if an enzmldoc is given"""
if not self._enzmldoc:
return None
return self._enzmldoc._unit_dict[self._time_unit_id]
[docs] @deprecated_getter("measurement_id")
def getMeasurement(self):
return self.measurement_id
[docs] @deprecated_getter("is_calculated")
def getIsCalculated(self):
return self.is_calculated
[docs] @deprecated_getter("replicate_id")
def getReplica(self):
return self.id
[docs] @deprecated_getter("species_id")
def getReactant(self):
return self.species_id
[docs] @deprecated_getter("data_type")
def getType(self):
return self.data_type
[docs] @deprecated_getter("data_unit")
def getDataUnit(self):
return self.data_unit
[docs] @deprecated_getter("time_unit")
def getTimeUnit(self):
return self.time_unit
[docs] @deprecated_getter("time' and 'data")
def getData(self, sep=False):
return self.time, self.data