Skip to content

Commit

Permalink
Added "name" support to fromEquation method
Browse files Browse the repository at this point in the history
  • Loading branch information
JR-1991 committed May 11, 2022
1 parent 85027bb commit abed3a2
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
41 changes: 39 additions & 2 deletions pyenzyme/enzymeml/models/kineticmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import re
import numexpr

from typing import List, TYPE_CHECKING, Optional
from typing import Any, List, TYPE_CHECKING, Optional
from pydantic import Field
from dataclasses import dataclass

Expand Down Expand Up @@ -177,7 +177,7 @@ def createGenerator(name: str, equation: str, **parameters):
return ModelFactory(name=name, equation=equation, **parameters)

@classmethod
def fromEquation(cls, name: str, equation: str):
def fromEquation(cls, name: str, equation: str, enzmldoc: Optional[Any] = None):
"""Creates a Kinetic Model instance from an equation
Args:
Expand All @@ -187,19 +187,56 @@ def fromEquation(cls, name: str, equation: str):
KineticModel: Resulting kinetic model
"""

if enzmldoc:
# Convert an equation with names to one with IDs

class_name = enzmldoc.__class__.__name__
if class_name != "EnzymeMLDocument":
# Guard clause
raise TypeError(
f"Expected type 'EnzymeMLDocument' for argument 'enzmldoc'. Got '{class_name}' instead."
)

# Now perform the actual conversion
equation = cls._convert_names_to_ids(enzmldoc, equation)

# Create a new instance
cls = cls(name=name, equation=equation)

# Parse equation and add parameters
used_species = []
for node in ast.walk(ast.parse(equation)):
if isinstance(node, ast.Name):
name = node.id
regex = re.compile(r"[s|p|c]\d*")
if not bool(regex.match(name)) and "_" + name not in cls.__dict__:
cls.addParameter(name=name)
else:
used_species.append(name)

if not used_species:
raise TypeError(
"It seems like you have included no species (Protein, Reactant, Complex) in your equation. "
"Are you using names? Please set your 'EnzymeMLDocument' to the argument 'enzmldoc' in order to proceed"
)

return cls

@staticmethod
def _convert_names_to_ids(enzmldoc, equation: str):
"""Converts names in an equation to appropriate IDs given in an EnzymeMLDocument"""

all_species = {
**enzmldoc.protein_dict,
**enzmldoc.reactant_dict,
**enzmldoc.complex_dict,
}

for id, species in all_species.items():
equation = equation.replace(species.name, id)

return equation

# ! Utilities

def get_id(self) -> str:
Expand Down
20 changes: 20 additions & 0 deletions tests/enzymeml/models/test_kineticlaw.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,26 @@ def test_content(self):
assert km.getParameter("km").stdev == 1.0
assert not km.getParameter("km").is_global

def test_from_equation(self, enzmldoc):
"""Tests the model initialization via an equation"""

# With IDs
model = KineticModel.fromEquation(name="Model", equation="s0 * x + p0 * c0")

assert len(model.parameters) == 1
assert model.parameters[0].name == "x"
assert model.name == "Model"

# With names
model = KineticModel.fromEquation(
name="Model", equation="Reactant * x + Protein * Complex", enzmldoc=enzmldoc
)

assert len(model.parameters) == 1
assert model.parameters[0].name == "x"
assert model.name == "Model"
assert model.equation == "s0 * x + p0 * c0"

def test_model_generator(self, enzmldoc):
"""Tests consistency of the model generator"""

Expand Down

0 comments on commit abed3a2

Please sign in to comment.