Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pydantic v2 #447

Merged
merged 10 commits into from
Oct 16, 2023
65 changes: 28 additions & 37 deletions maud/data_model/experiment.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
"""Provides dataclass Experiment."""
"""Provides model Experiment."""

from enum import Enum
from typing import List, Optional

from pydantic import Field, validator
from pydantic.dataclasses import dataclass
from pydantic import BaseModel, Field, computed_field, field_validator

from maud.data_model.hardcoding import ID_SEPARATOR


class MSConfig:
"""Config for MeasurementSet, allowing it to contain pandas objects."""

arbitrary_types_allowed = True


class MeasurementType(str, Enum):
"""Possible types of measurement."""

Expand All @@ -23,8 +16,7 @@ class MeasurementType(str, Enum):
ENZYME = "enzyme"


@dataclass
class Measurement:
class Measurement(BaseModel):
"""Maud representation of a measurement."""

experiment: str
Expand All @@ -35,62 +27,61 @@ class Measurement:
compartment: Optional[str] = None
reaction: Optional[str] = None
enzyme: Optional[str] = None
target_id: str = Field(default=None, init=False, exclude=True)

def __post_init__(self):
@computed_field
def target_id(self) -> str:
"""Add target_id field."""
if self.target_type == MeasurementType.MIC:
self.target_id = ID_SEPARATOR.join(
[self.metabolite, self.compartment]
)
assert self.metabolite is not None
assert self.compartment is not None
return ID_SEPARATOR.join([self.metabolite, self.compartment])
elif self.target_type == MeasurementType.FLUX:
self.target_id = self.reaction
elif self.target_type == MeasurementType.ENZYME:
self.target_id = self.enzyme
assert self.reaction is not None
return self.reaction
else:
assert self.enzyme is not None
return self.enzyme


@dataclass
class EnzymeKnockout:
class EnzymeKnockout(BaseModel):
"""Maud representation of an enzyme being knocked out in an experiment."""

experiment: str
enzyme: str
id: str = Field(init=False, exclude=True)

def __post_init__(self):
@computed_field
def id(self) -> str:
"""Add id field."""
self.id = ID_SEPARATOR.join(["eko", self.experiment, self.enzyme])
return ID_SEPARATOR.join(["eko", self.experiment, self.enzyme])


@dataclass
class PhosphorylationModifyingEnzymeKnockout:
class PhosphorylationModifyingEnzymeKnockout(BaseModel):
"""Maud representation of a pme being knocked out in an experiment."""

experiment: str
enzyme: str
pme: str
id: str = Field(init=False, exclude=True)

def __post_init__(self):
@computed_field
def id(self) -> str:
"""Add id field."""
self.id = ID_SEPARATOR.join(["pko", self.experiment, self.enzyme])
return ID_SEPARATOR.join(["pko", self.experiment, self.enzyme])


@dataclass
class InitConcentration:
class InitConcentration(BaseModel):
"""Indication of the initial value of a concentration in the ODE."""

metabolite: str
compartment: str
value: float
target_id: str = Field(default=None, init=False, exclude=True)

def __post_init__(self):
@computed_field
def target_id(self) -> str:
"""Add target_id field."""
self.target_id = ID_SEPARATOR.join([self.metabolite, self.compartment])
return ID_SEPARATOR.join([self.metabolite, self.compartment])


@dataclass
class Experiment:
class Experiment(BaseModel):
"""Maud representation of an experiment.

This means a case where the boundary conditions and all measured quantities
Expand All @@ -109,7 +100,7 @@ class Experiment:
default_factory=lambda: []
)

@validator("temperature")
@field_validator("temperature")
def temp_must_be_non_negative(cls, v):
"""Make sure the temperature isn't negative."""
assert v >= 0
Expand Down
Loading
Loading