Skip to content

Commit 9431c6e

Browse files
authored
feat: add measurement grouping based on initial conditions; fix circular imports
- Introduced `group_id` assignment for measurements in an EnzymeMLDocument based on shared initial conditions (species concentration, pH, temperature). - Refactored import structure to avoid circular imports caused by top-level references, improving compatibility with third-party usage.
2 parents cf1943f + d8cbac8 commit 9431c6e

File tree

13 files changed

+730
-53
lines changed

13 files changed

+730
-53
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<h1 align="center">
22
PyEnzyme<br>
3-
<img src="https://img.shields.io/badge/PyEnzyme-1.1.5-blue" alt="v2.0.0">
3+
<img alt="PyPI - Version" src="https://img.shields.io/pypi/v/pyenzyme">
44
<img src="https://github.com/EnzymeML/PyEnzyme/actions/workflows/unit-tests.yaml/badge.svg" alt="Build Badge">
55
</a>
66
<a href="https://www.codacy.com/gh/EnzymeML/PyEnzyme/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=EnzymeML/PyEnzyme&amp;utm_campaign=Badge_Grade"><img src="https://app.codacy.com/project/badge/Grade/4ceb8d010e7b456c926c8b18737ff102"/></a>

pyenzyme/__init__.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
from mdmodels.units.unit_definition import UnitDefinition, UnitType
44

5-
from .versions.v2 import * # noqa: F403
6-
from .versions.io import EnzymeMLHandler
7-
from .fetcher import * # noqa: F403
85
from .composer import compose
9-
from .suite import EnzymeMLSuite
6+
from .fetcher import * # noqa: F403
107
from .plotting import plot, plot_interactive
118
from .pretty import summary
9+
from .suite import EnzymeMLSuite
10+
from .tools import group_measurements
11+
from .versions.io import EnzymeMLHandler
12+
from .versions.v2 import * # noqa: F403
1213

1314
# Input functions
1415
from_csv = EnzymeMLHandler.from_csv
@@ -41,6 +42,7 @@
4142
"plot",
4243
"plot_interactive",
4344
"summary",
45+
"group_measurements",
4446
]
4547

46-
__version__ = "2.0.0"
48+
__version__ = "2.1.0"

pyenzyme/petab/io.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
from pyenzyme.sbml.serializer import to_sbml
88
from pyenzyme.versions import v2
99

10-
from .petab import PEtab, Problem
1110
from .conditions import ConditionRow
12-
from .observables import ObservableRow
1311
from .measurements import MeasurementRow
12+
from .observables import ObservableRow
1413
from .parameters import ParameterRow
14+
from .petab import PEtab, Problem
1515

1616
# Default filenames for PEtab format components
1717
PARAMETER_FILENAME = "parameters.tsv"

pyenzyme/sbml/serializer.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@
1010

1111
import pyenzyme as pe
1212
import pyenzyme.tools as tools
13-
14-
from pyenzyme import rdf
13+
from pyenzyme import UnitDefinition, rdf
1514
from pyenzyme import xmlutils as _xml
1615
from pyenzyme.logging import add_logger
1716
from pyenzyme.sbml import create_sbml_omex
1817
from pyenzyme.sbml.validation import validate_sbml_export
1918
from pyenzyme.sbml.versions import v2
2019
from pyenzyme.tabular import to_pandas
21-
from pyenzyme import UnitDefinition
2220

2321
NSMAP = {"enzymeml": "https://www.enzymeml.org/v2"}
2422
CELSIUS_CONVERSION_FACTOR = 273.15

pyenzyme/sbml/validation.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
from loguru import logger
2+
from mdmodels.units.unit_definition import UnitDefinition
23

3-
import pyenzyme as pe
44
import pyenzyme.tools as tools
5+
from pyenzyme.versions.v2 import (
6+
EnzymeMLDocument,
7+
EquationType,
8+
MeasurementData,
9+
Parameter,
10+
ReactionElement,
11+
)
512

613

7-
def validate_sbml_export(doc: pe.EnzymeMLDocument) -> bool:
14+
def validate_sbml_export(doc: EnzymeMLDocument) -> bool:
815
"""This function validates the SBML export of an EnzymeML document.
916
1017
Args:
@@ -26,7 +33,7 @@ def validate_sbml_export(doc: pe.EnzymeMLDocument) -> bool:
2633
return result
2734

2835

29-
def _check_consistent_vessel_ids(doc: pe.EnzymeMLDocument) -> bool:
36+
def _check_consistent_vessel_ids(doc: EnzymeMLDocument) -> bool:
3037
"""This validator checks whether all species have a vessel id that exists in the document.
3138
3239
SBML documents require that all species have a vessel id that exists in the document and
@@ -62,7 +69,7 @@ def _check_consistent_vessel_ids(doc: pe.EnzymeMLDocument) -> bool:
6269
return all(result)
6370

6471

65-
def _check_equation_either_rule_or_reaction(doc: pe.EnzymeMLDocument) -> bool:
72+
def _check_equation_either_rule_or_reaction(doc: EnzymeMLDocument) -> bool:
6673
"""This validator checks whether there are either rules or reactions in the document.
6774
6875
SBML documents require that there are either rules or reactions in the document. For instance,
@@ -78,10 +85,10 @@ def _check_equation_either_rule_or_reaction(doc: pe.EnzymeMLDocument) -> bool:
7885
"""
7986

8087
species_w_rate = {
81-
eq.species_id for eq in doc.equations if eq.equation_type == pe.EquationType.ODE
88+
eq.species_id for eq in doc.equations if eq.equation_type == EquationType.ODE
8289
}
8390

84-
all_reaction_elements = tools.extract(obj=doc, target=pe.ReactionElement)
91+
all_reaction_elements = tools.extract(obj=doc, target=ReactionElement)
8592
result, validated = [], set()
8693

8794
for element in all_reaction_elements:
@@ -98,7 +105,7 @@ def _check_equation_either_rule_or_reaction(doc: pe.EnzymeMLDocument) -> bool:
98105
return all(result)
99106

100107

101-
def _check_units_exist(doc: pe.EnzymeMLDocument) -> bool:
108+
def _check_units_exist(doc: EnzymeMLDocument) -> bool:
102109
"""This validator checks whether all units in the document are defined in the SBML standard.
103110
104111
Args:
@@ -109,26 +116,26 @@ def _check_units_exist(doc: pe.EnzymeMLDocument) -> bool:
109116
"""
110117

111118
mandatory_unit_objects = [
112-
*tools.extract(obj=doc, target=pe.MeasurementData),
119+
*tools.extract(obj=doc, target=MeasurementData),
113120
]
114121

115122
optional_unit_objects = [
116-
*tools.extract(obj=doc, target=pe.Parameter),
123+
*tools.extract(obj=doc, target=Parameter),
117124
]
118125

119126
result = []
120127

121128
for unit_obj in mandatory_unit_objects:
122-
units = tools.extract(obj=unit_obj, target=pe.UnitDefinition)
129+
units = tools.extract(obj=unit_obj, target=UnitDefinition)
123130

124131
if len(units) == 0:
125132
logger.error(
126-
f"Object of type '{type(unit_obj).__name__}' with id '{unit_obj.id}' does not have a unit defined."
133+
f"Object of type '{type(unit_obj).__name__}' with id '{unit_obj.species_id}' does not have a unit defined."
127134
)
128135
result.append(False)
129136

130137
for unit_obj in optional_unit_objects:
131-
units = tools.extract(obj=unit_obj, target=pe.UnitDefinition)
138+
units = tools.extract(obj=unit_obj, target=UnitDefinition)
132139

133140
if len(units) == 0:
134141
logger.warning(
@@ -140,7 +147,7 @@ def _check_units_exist(doc: pe.EnzymeMLDocument) -> bool:
140147
return all(result)
141148

142149

143-
def _check_assigned_params_are_not_constant(doc: pe.EnzymeMLDocument) -> bool:
150+
def _check_assigned_params_are_not_constant(doc: EnzymeMLDocument) -> bool:
144151
"""This validator checks whether all assigned parameters are not constant.
145152
146153
If a parameter is assigned a value through an assignment rule, it should not be constant.
@@ -154,7 +161,7 @@ def _check_assigned_params_are_not_constant(doc: pe.EnzymeMLDocument) -> bool:
154161
bool: True if all assigned parameters are valid, False otherwise.
155162
"""
156163

157-
assignments = doc.filter_equations(equation_type=pe.EquationType.ASSIGNMENT)
164+
assignments = doc.filter_equations(equation_type=EquationType.ASSIGNMENT)
158165
result = []
159166

160167
for assignment in assignments:

pyenzyme/sbml/versions/v1.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from __future__ import annotations
22

33
import pandas as pd
4+
from mdmodels.units.unit_definition import UnitDefinition
45
from pydantic import computed_field
5-
from pydantic_xml import element, BaseXmlModel, attr, wrapped
6+
from pydantic_xml import BaseXmlModel, attr, element, wrapped
67

7-
from pyenzyme import Measurement, UnitDefinition, DataTypes
88
from pyenzyme.sbml.utils import _get_unit
99
from pyenzyme.sbml.versions.v2 import VariableAnnot
10+
from pyenzyme.versions.v2 import DataTypes, Measurement
1011

1112

1213
class V1Annotation(

pyenzyme/sbml/versions/v2.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
from __future__ import annotations
1414

1515
import pandas as pd
16+
from mdmodels.units.unit_definition import UnitDefinition
1617
from pydantic import field_validator
17-
from pydantic_xml import element, attr, BaseXmlModel
18+
from pydantic_xml import BaseXmlModel, attr, element
1819

19-
from pyenzyme import DataTypes, Measurement, UnitDefinition
2020
from pyenzyme.sbml.utils import _get_unit
21+
from pyenzyme.versions.v2 import DataTypes, Measurement
2122

2223

2324
class BaseAnnot(BaseXmlModel):

pyenzyme/suite.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import httpx
44
import rich
55

6-
import pyenzyme as pe
6+
from pyenzyme.versions.io import EnzymeMLHandler
7+
from pyenzyme.versions.v2 import EnzymeMLDocument
78

89

910
class EnzymeMLSuite:
@@ -20,7 +21,7 @@ def __init__(self, url: str = "http://localhost:13452"):
2021
"""
2122
self.client = httpx.Client(base_url=url)
2223

23-
def get_current(self) -> pe.EnzymeMLDocument:
24+
def get_current(self) -> EnzymeMLDocument:
2425
"""
2526
Retrieves the current EnzymeML document from the service.
2627
@@ -42,9 +43,9 @@ def get_current(self) -> pe.EnzymeMLDocument:
4243

4344
content = response.json()["data"]["content"]
4445

45-
return pe.read_enzymeml_from_string(content)
46+
return EnzymeMLHandler.read_enzymeml_from_string(content)
4647

47-
def update_current(self, doc: pe.EnzymeMLDocument):
48+
def update_current(self, doc: EnzymeMLDocument):
4849
"""
4950
Updates the current EnzymeML document on the service.
5051

0 commit comments

Comments
 (0)