Source code for cocomico.model

# -*- coding: utf-8 -*-

"""
CoCoMiCo model objects.
"""

import logging
from typing import Set, cast

from cocomico.base import Metabolite, Reaction, Taxon

# Types

MRT = tuple[Metabolite, Reaction, Taxon]


# Model class


[docs] class Model: """ Models store bipartite metabolite-reaction relations. :param biomolecule: metabolites M in the model :param reactions: reactions R in the model :param relations: relations M x R or R x M in the model """ # pylint: disable=R0902,R0903 def __init__( # pylint: disable=R0913 self, biomolecule: set[Metabolite], tuples: ( set[tuple[Metabolite, Reaction] | tuple[Reaction, Metabolite]] | None ) = None, relations: dict[str, set[MRT]] | None = None, ) -> None: """ Initialize a model from a set of metabolites, reactions, and metabolite-reaction relations. """ self.biomolecule = biomolecule self.relations = relations or { "reactant": cast(Set[MRT], set()), "product": cast(Set[MRT], set()), } if tuples is not None: self._add_tuples(tuples) logging.debug( "Init %s {%s}", str(self), " ".join(sorted(str(r) for r in self.reactions)) ) self._log("Init") @property def reactions(self) -> set[Reaction]: """ The set of reactions defined by this model, extracted from the reaction and product triples. """ e_reactant = [r for _, r, _ in self.relations["reactant"]] e_product = [r for _, r, _ in self.relations["product"]] return cast(Set[Reaction], {*e_reactant, *e_product})
[docs] def remove_seed_reactions(self): """ Remove reactions with empty products or reactants, which otherwise would implicitly create seeds. Some modeling tools generate these to represent exchanges with the environment. """ for todo in self.reactions: reac = {rel for rel in self.relations["reactant"] if rel[1] == todo} prod = {rel for rel in self.relations["product"] if rel[1] == todo} if not bool(reac) or not bool(prod): logging.debug( "Removing seed reaction (%d) -%s-> (%d)", len(reac), todo, len(prod) ) self.relations["reactant"] -= reac self.relations["product"] -= prod self._log("Removed")
def _add_tuples(self, tuples): """ Add tuples to the relations, either reactant or product depending on which member is a metabolite. """ self.relations["reactant"].update( [(m, r, m.provenance) for m, r in tuples if isinstance(m, Metabolite)] ) self.relations["product"].update( [(m, r, m.provenance) for r, m in tuples if isinstance(m, Metabolite)] ) def _log(self, prefix="Model"): """Log model contents.""" for role in ["product", "reactant"]: for m, r, t in sorted(list(self.relations[role]), key=lambda mrt: mrt[1]): logging.debug( "%s relation %s %s (%s, %s, %s)", prefix, str(r.name), role, str(m.biomolecule), str(r.name), str(t), )
[docs] def __str__(self) -> str: """String representation of class Model.""" return f"Model<{hex(id(self))}>"