Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions pyenzyme/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

from mdmodels.units.unit_definition import UnitDefinition, UnitType

from .versions.v2 import * # noqa: F403
from .versions.io import EnzymeMLHandler
from .fetcher import * # noqa: F403
from .composer import compose
from .suite import EnzymeMLSuite
from .fetcher import * # noqa: F403
from .plotting import plot, plot_interactive
from .pretty import summary
from .suite import EnzymeMLSuite
from .tools import group_measurements
from .versions.io import EnzymeMLHandler
from .versions.v2 import * # noqa: F403

# Input functions
from_csv = EnzymeMLHandler.from_csv
Expand Down Expand Up @@ -41,6 +42,7 @@
"plot",
"plot_interactive",
"summary",
"group_measurements",
]

__version__ = "2.0.0"
4 changes: 2 additions & 2 deletions pyenzyme/petab/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
from pyenzyme.sbml.serializer import to_sbml
from pyenzyme.versions import v2

from .petab import PEtab, Problem
from .conditions import ConditionRow
from .observables import ObservableRow
from .measurements import MeasurementRow
from .observables import ObservableRow
from .parameters import ParameterRow
from .petab import PEtab, Problem

# Default filenames for PEtab format components
PARAMETER_FILENAME = "parameters.tsv"
Expand Down
4 changes: 1 addition & 3 deletions pyenzyme/sbml/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@

import pyenzyme as pe
import pyenzyme.tools as tools

from pyenzyme import rdf
from pyenzyme import UnitDefinition, rdf
from pyenzyme import xmlutils as _xml
from pyenzyme.logging import add_logger
from pyenzyme.sbml import create_sbml_omex
from pyenzyme.sbml.validation import validate_sbml_export
from pyenzyme.sbml.versions import v2
from pyenzyme.tabular import to_pandas
from pyenzyme import UnitDefinition

NSMAP = {"enzymeml": "https://www.enzymeml.org/v2"}
CELSIUS_CONVERSION_FACTOR = 273.15
Expand Down
36 changes: 22 additions & 14 deletions pyenzyme/sbml/validation.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
from loguru import logger
from mdmodels.units.unit_definition import UnitDefinition

import pyenzyme as pe
import pyenzyme.tools as tools
from pyenzyme.versions.v2 import (
EnzymeMLDocument,
EquationType,
MeasurementData,
Parameter,
ReactionElement,
)


def validate_sbml_export(doc: pe.EnzymeMLDocument) -> bool:
def validate_sbml_export(doc: EnzymeMLDocument) -> bool:
"""This function validates the SBML export of an EnzymeML document.

Args:
Expand All @@ -26,7 +33,7 @@ def validate_sbml_export(doc: pe.EnzymeMLDocument) -> bool:
return result


def _check_consistent_vessel_ids(doc: pe.EnzymeMLDocument) -> bool:
def _check_consistent_vessel_ids(doc: EnzymeMLDocument) -> bool:
"""This validator checks whether all species have a vessel id that exists in the document.

SBML documents require that all species have a vessel id that exists in the document and
Expand Down Expand Up @@ -62,7 +69,7 @@ def _check_consistent_vessel_ids(doc: pe.EnzymeMLDocument) -> bool:
return all(result)


def _check_equation_either_rule_or_reaction(doc: pe.EnzymeMLDocument) -> bool:
def _check_equation_either_rule_or_reaction(doc: EnzymeMLDocument) -> bool:
"""This validator checks whether there are either rules or reactions in the document.

SBML documents require that there are either rules or reactions in the document. For instance,
Expand All @@ -78,10 +85,10 @@ def _check_equation_either_rule_or_reaction(doc: pe.EnzymeMLDocument) -> bool:
"""

species_w_rate = {
eq.species_id for eq in doc.equations if eq.equation_type == pe.EquationType.ODE
eq.species_id for eq in doc.equations if eq.equation_type == EquationType.ODE
}

all_reaction_elements = tools.extract(obj=doc, target=pe.ReactionElement)
all_reaction_elements = tools.extract(obj=doc, target=ReactionElement)
result, validated = [], set()

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


def _check_units_exist(doc: pe.EnzymeMLDocument) -> bool:
def _check_units_exist(doc: EnzymeMLDocument) -> bool:
"""This validator checks whether all units in the document are defined in the SBML standard.

Args:
Expand All @@ -109,26 +116,27 @@ def _check_units_exist(doc: pe.EnzymeMLDocument) -> bool:
"""

mandatory_unit_objects = [
*tools.extract(obj=doc, target=pe.MeasurementData),
*tools.extract(obj=doc, target=MeasurementData),
]
print(f"Found {len(mandatory_unit_objects)} mandatory unit objects.")
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug print statement should be removed before production. Use logger.debug() instead if debug information is needed.

Suggested change
print(f"Found {len(mandatory_unit_objects)} mandatory unit objects.")
logger.debug(f"Found {len(mandatory_unit_objects)} mandatory unit objects.")

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use the global logger to keep the logging consistent, but I am also fine with using print or rich (for some color and formatting)


optional_unit_objects = [
*tools.extract(obj=doc, target=pe.Parameter),
*tools.extract(obj=doc, target=Parameter),
]

result = []

for unit_obj in mandatory_unit_objects:
units = tools.extract(obj=unit_obj, target=pe.UnitDefinition)
units = tools.extract(obj=unit_obj, target=UnitDefinition)

if len(units) == 0:
logger.error(
f"Object of type '{type(unit_obj).__name__}' with id '{unit_obj.id}' does not have a unit defined."
f"Object of type '{type(unit_obj).__name__}' with id '{unit_obj.species_id}' does not have a unit defined."
)
result.append(False)

for unit_obj in optional_unit_objects:
units = tools.extract(obj=unit_obj, target=pe.UnitDefinition)
units = tools.extract(obj=unit_obj, target=UnitDefinition)

if len(units) == 0:
logger.warning(
Expand All @@ -140,7 +148,7 @@ def _check_units_exist(doc: pe.EnzymeMLDocument) -> bool:
return all(result)


def _check_assigned_params_are_not_constant(doc: pe.EnzymeMLDocument) -> bool:
def _check_assigned_params_are_not_constant(doc: EnzymeMLDocument) -> bool:
"""This validator checks whether all assigned parameters are not constant.

If a parameter is assigned a value through an assignment rule, it should not be constant.
Expand All @@ -154,7 +162,7 @@ def _check_assigned_params_are_not_constant(doc: pe.EnzymeMLDocument) -> bool:
bool: True if all assigned parameters are valid, False otherwise.
"""

assignments = doc.filter_equations(equation_type=pe.EquationType.ASSIGNMENT)
assignments = doc.filter_equations(equation_type=EquationType.ASSIGNMENT)
result = []

for assignment in assignments:
Expand Down
5 changes: 3 additions & 2 deletions pyenzyme/sbml/versions/v1.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from __future__ import annotations

import pandas as pd
from mdmodels.units.unit_definition import UnitDefinition
from pydantic import computed_field
from pydantic_xml import element, BaseXmlModel, attr, wrapped
from pydantic_xml import BaseXmlModel, attr, element, wrapped

from pyenzyme import Measurement, UnitDefinition, DataTypes
from pyenzyme.sbml.utils import _get_unit
from pyenzyme.sbml.versions.v2 import VariableAnnot
from pyenzyme.versions.v2 import DataTypes, Measurement


class V1Annotation(
Expand Down
5 changes: 3 additions & 2 deletions pyenzyme/sbml/versions/v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
from __future__ import annotations

import pandas as pd
from mdmodels.units.unit_definition import UnitDefinition
from pydantic import field_validator
from pydantic_xml import element, attr, BaseXmlModel
from pydantic_xml import BaseXmlModel, attr, element

from pyenzyme import DataTypes, Measurement, UnitDefinition
from pyenzyme.sbml.utils import _get_unit
from pyenzyme.versions.v2 import DataTypes, Measurement


class BaseAnnot(BaseXmlModel):
Expand Down
9 changes: 5 additions & 4 deletions pyenzyme/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import httpx
import rich

import pyenzyme as pe
from pyenzyme.versions.io import EnzymeMLHandler
from pyenzyme.versions.v2 import EnzymeMLDocument


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

def get_current(self) -> pe.EnzymeMLDocument:
def get_current(self) -> EnzymeMLDocument:
"""
Retrieves the current EnzymeML document from the service.

Expand All @@ -42,9 +43,9 @@ def get_current(self) -> pe.EnzymeMLDocument:

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

return pe.read_enzymeml_from_string(content)
return EnzymeMLHandler.read_enzymeml_from_string(content)

def update_current(self, doc: pe.EnzymeMLDocument):
def update_current(self, doc: EnzymeMLDocument):
"""
Updates the current EnzymeML document on the service.

Expand Down
Loading