# -*- coding: utf-8 -*-
# Copyright 2017 Novo Nordisk Foundation Center for Biosustainability,
# Technical University of Denmark.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for SBO terms performed on an instance of ``cobra.Model``."""
from __future__ import absolute_import, division
import pytest
import memote.support.basic as basic
import memote.support.helpers as helpers
import memote.support.sbo as sbo
from memote.utils import annotate, get_ids, truncate, wrapper
@annotate(title="Metabolite General SBO Presence", format_type="count")
@annotate(title="Reaction General SBO Presence", format_type="count")
[docs]def test_reaction_sbo_presence(model):
"""Expect all reactions to have a some form of SBO-Term annotation.
The Systems Biology Ontology (SBO) allows researchers to annotate a model
with terms which indicate the intended function of its individual
components. The available terms are controlled and relational and can be
viewed here http://www.ebi.ac.uk/sbo/main/tree.
Implementation:
Check if each cobra.Reaction has a non-zero "annotation"
attribute that contains the key "sbo".
"""
ann = test_reaction_sbo_presence.annotation
ann["data"] = get_ids(sbo.find_components_without_sbo_terms(model, "reactions"))
try:
ann["metric"] = len(ann["data"]) / len(model.reactions)
ann["message"] = wrapper.fill(
"""A total of {} reactions ({:.2%}) lack annotation with any type
of SBO term: {}""".format(
len(ann["data"]), ann["metric"], truncate(ann["data"])
)
)
except ZeroDivisionError:
ann["metric"] = 1.0
ann["message"] = "The model has no reactions."
pytest.skip(ann["message"])
assert len(ann["data"]) == len(model.reactions), ann["message"]
@annotate(title="Gene General SBO Presence", format_type="count")
[docs]def test_gene_sbo_presence(model):
"""Expect all genes to have a some form of SBO-Term annotation.
The Systems Biology Ontology (SBO) allows researchers to annotate a model
with terms which indicate the intended function of its individual
components. The available terms are controlled and relational and can be
viewed here http://www.ebi.ac.uk/sbo/main/tree.
Check if each cobra.Gene has a non-zero "annotation"
attribute that contains the key "sbo".
"""
ann = test_gene_sbo_presence.annotation
ann["data"] = get_ids(sbo.find_components_without_sbo_terms(model, "genes"))
try:
ann["metric"] = len(ann["data"]) / len(model.genes)
ann["message"] = wrapper.fill(
"""A total of {} genes ({:.2%}) lack annotation with any type of
SBO term: {}""".format(
len(ann["data"]), ann["metric"], truncate(ann["data"])
)
)
except ZeroDivisionError:
ann["metric"] = 1.0
ann["message"] = "The model has no genes."
pytest.skip(ann["message"])
assert len(ann["data"]) == len(model.genes), ann["message"]
@annotate(title="Metabolic Reaction SBO:0000176 Presence", format_type="count")
@annotate(title="Transport Reaction SBO:0000185 Presence", format_type="count")
[docs]def test_transport_reaction_specific_sbo_presence(model):
"""Expect all transport reactions to be annotated properly.
'SBO:0000185', 'SBO:0000588', 'SBO:0000587', 'SBO:0000655', 'SBO:0000654',
'SBO:0000660', 'SBO:0000659', 'SBO:0000657', and 'SBO:0000658' represent
the terms 'transport reaction' and 'translocation reaction', in addition
to their children (more specific transport reaction labels). Every
transport reaction that is not a pure metabolic or boundary reaction should
be annotated with one of these terms. The results shown are relative to the
total of all transport reactions.
Implementation:
Check if each transport reaction has a non-zero "annotation"
attribute that contains the key "sbo" with the associated
value being one of the SBO terms above.
"""
sbo_transport_terms = helpers.TRANSPORT_RXN_SBO_TERMS
ann = test_transport_reaction_specific_sbo_presence.annotation
transports = helpers.find_transport_reactions(model)
ann["data"] = get_ids(
sbo.check_component_for_specific_sbo_term(transports, sbo_transport_terms)
)
try:
ann["metric"] = len(ann["data"]) / len(transports)
ann["message"] = wrapper.fill(
"""A total of {} metabolic reactions ({:.2%} of all transport
reactions) lack annotation with one of the SBO terms: {} for
'biochemical reaction': {}""".format(
len(ann["data"]),
ann["metric"],
sbo_transport_terms,
truncate(ann["data"]),
)
)
except ZeroDivisionError:
ann["metric"] = 1.0
ann["message"] = "The model has no transport reactions."
pytest.skip(ann["message"])
assert len(ann["data"]) == len(transports), ann["message"]
@annotate(title="Metabolite SBO:0000247 Presence", format_type="count")
@annotate(title="Gene SBO:0000243 Presence", format_type="count")
[docs]def test_gene_specific_sbo_presence(model):
"""Expect all genes to be annotated with SBO:0000243.
SBO:0000243 represents the term 'gene'. Every gene should
be annotated with this.
Implementation:
Check if each cobra.Gene has a non-zero "annotation"
attribute that contains the key "sbo" with the associated
value being one of the SBO terms above.
"""
ann = test_gene_specific_sbo_presence.annotation
ann["data"] = get_ids(
sbo.check_component_for_specific_sbo_term(model.genes, "SBO:0000243")
)
try:
ann["metric"] = len(ann["data"]) / len(model.genes)
ann["message"] = wrapper.fill(
"""A total of {} genes ({:.2%} of all genes) lack
annotation with the SBO term "SBO:0000243" for
'gene': {}""".format(
len(ann["data"]), ann["metric"], truncate(ann["data"])
)
)
except ZeroDivisionError:
ann["metric"] = 1.0
ann["message"] = "The model has no genes."
pytest.skip(ann["message"])
assert len(ann["data"]) == len(model.genes), ann["message"]
@annotate(title="Exchange Reaction SBO:0000627 Presence", format_type="count")
[docs]def test_exchange_specific_sbo_presence(model):
"""Expect all exchange reactions to be annotated with SBO:0000627.
SBO:0000627 represents the term 'exchange reaction'. The Systems Biology
Ontology defines an exchange reaction as follows: 'A modeling process to
provide matter influx or efflux to a model, for example to replenish a
metabolic network with raw materials (eg carbon / energy sources). Such
reactions are conceptual, created solely for modeling purposes, and do not
have a physical correspondence. Exchange reactions, often represented as
'R_EX_', can operate in the negative (uptake) direction or positive
(secretion) direction. By convention, a negative flux through an exchange
reaction represents uptake of the corresponding metabolite, and a positive
flux represent discharge.' Every exchange reaction should be annotated with
this. Exchange reactions differ from demand reactions in that the
metabolites are removed from or added to the extracellular
environment only.
Implementation:
Check if each exchange reaction has a non-zero "annotation"
attribute that contains the key "sbo" with the associated
value being one of the SBO terms above.
"""
ann = test_exchange_specific_sbo_presence.annotation
exchanges = helpers.find_exchange_rxns(model)
ann["data"] = get_ids(
sbo.check_component_for_specific_sbo_term(exchanges, "SBO:0000627")
)
try:
ann["metric"] = len(ann["data"]) / len(exchanges)
ann["message"] = wrapper.fill(
"""A total of {} exchange reactions ({:.2%} of all exchange
reactions) lack annotation with the SBO term "SBO:0000627" for
'exchange reaction': {}""".format(
len(ann["data"]), ann["metric"], truncate(ann["data"])
)
)
except ZeroDivisionError:
ann["metric"] = 1.0
ann["message"] = "The model has no exchange reactions."
pytest.skip(ann["message"])
assert len(ann["data"]) == len(exchanges), ann["message"]
@annotate(title="Demand Reaction SBO:0000628 Presence", format_type="count")
[docs]def test_demand_specific_sbo_presence(model):
"""Expect all demand reactions to be annotated with SBO:0000627.
SBO:0000628 represents the term 'demand reaction'. The Systems Biology
Ontology defines a demand reaction as follows: 'A modeling process
analogous to exchange reaction, but which operates upon "internal"
metabolites. Metabolites that are consumed by these reactions are assumed
to be used in intra-cellular processes that are not part of the model.
Demand reactions, often represented 'R_DM_', can also deliver metabolites
(from intra-cellular processes that are not considered in the model).'
Every demand reaction should be annotated with
this. Demand reactions differ from exchange reactions in that the
metabolites are not removed from the extracellular environment, but from
any of the organism's compartments. Demand reactions differ from sink
reactions in that they are designated as irreversible.
Implementation:
Check if each demand reaction has a non-zero "annotation"
attribute that contains the key "sbo" with the associated
value being one of the SBO terms above.
"""
ann = test_demand_specific_sbo_presence.annotation
demands = helpers.find_demand_reactions(model)
ann["data"] = get_ids(
sbo.check_component_for_specific_sbo_term(demands, "SBO:0000628")
)
try:
ann["metric"] = len(ann["data"]) / len(demands)
ann["message"] = wrapper.fill(
"""A total of {} genes ({:.2%} of all demand reactions) lack
annotation with the SBO term "SBO:0000628" for
'demand reaction': {}""".format(
len(ann["data"]), ann["metric"], truncate(ann["data"])
)
)
except ZeroDivisionError:
ann["metric"] = 1.0
ann["message"] = "The model has no demand reactions."
pytest.skip(ann["message"])
assert len(ann["data"]) == len(demands), ann["message"]
@annotate(title="Sink Reactions SBO:0000632 Presence", format_type="count")
[docs]def test_sink_specific_sbo_presence(model):
"""Expect all sink reactions to be annotated with SBO:0000632.
SBO:0000632 represents the term 'sink reaction'. The Systems Biology
Ontology defines a sink reaction as follows: 'A modeling process to
provide matter influx or efflux to a model, for example to replenish a
metabolic network with raw materials (eg carbon / energy sources). Such
reactions are conceptual, created solely for modeling purposes, and do not
have a physical correspondence. Unlike the analogous demand (SBO:....)
reactions, which are usually designated as irreversible, sink reactions
always represent a reversible uptake/secretion processes, and act as a
metabolite source with no cost to the cell. Sink reactions, also referred
to as R_SINK_, are generally used for compounds that are metabolized by
the cell but are produced by non-metabolic, un-modeled cellular processes.'
Every sink reaction should be annotated with
this. Sink reactions differ from exchange reactions in that the metabolites
are not removed from the extracellular environment, but from any of the
organism's compartments.
Implementation:
Check if each sink reaction has a non-zero "annotation"
attribute that contains the key "sbo" with the associated
value being one of the SBO terms above.
"""
ann = test_sink_specific_sbo_presence.annotation
sinks = helpers.find_sink_reactions(model)
ann["data"] = get_ids(
sbo.check_component_for_specific_sbo_term(sinks, "SBO:0000632")
)
try:
ann["metric"] = len(ann["data"]) / len(sinks)
except ZeroDivisionError:
ann["metric"] = 1.0
ann["message"] = "No sink reactions found."
pytest.skip(ann["message"])
ann["message"] = wrapper.fill(
"""A total of {} genes ({:.2%} of all sink reactions) lack
annotation with the SBO term "SBO:0000632" for
'sink reaction': {}""".format(
len(ann["data"]), ann["metric"], truncate(ann["data"])
)
)
assert len(ann["data"]) == len(sinks), ann["message"]
@annotate(title="Biomass Reactions SBO:0000629 Presence", format_type="count")
[docs]def test_biomass_specific_sbo_presence(model):
"""Expect all biomass reactions to be annotated with SBO:0000629.
SBO:0000629 represents the term 'biomass production'. The Systems Biology
Ontology defines an exchange reaction as follows: 'Biomass production,
often represented 'R_BIOMASS_', is usually the optimization target reaction
of constraint-based models, and can consume multiple reactants to produce
multiple products. It is also assumed that parts of the reactants are also
consumed in unrepresented processes and hence products do not have to
reflect all the atom composition of the reactants. Formulation of a
biomass production process entails definition of the macromolecular
content (eg. cellular protein fraction), metabolic constitution of
each fraction (eg. amino acids), and subsequently the atomic composition
(eg. nitrogen atoms). More complex biomass functions can additionally
incorporate details of essential vitamins and cofactors required for
growth.'
Every reaction representing the biomass production should be annotated with
this.
Implementation:
Check if each biomass reaction has a non-zero "annotation"
attribute that contains the key "sbo" with the associated
value being one of the SBO terms above.
"""
ann = test_biomass_specific_sbo_presence.annotation
biomass = helpers.find_biomass_reaction(model)
ann["data"] = get_ids(
sbo.check_component_for_specific_sbo_term(biomass, "SBO:0000629")
)
try:
ann["metric"] = len(ann["data"]) / len(biomass)
except ZeroDivisionError:
ann["metric"] = 1.0
ann["message"] = "No biomass reactions found."
pytest.skip(ann["message"])
ann["message"] = wrapper.fill(
"""A total of {} biomass reactions ({:.2%} of all biomass reactions)
lack annotation with the SBO term "SBO:0000629" for
'biomass production': {}""".format(
len(ann["data"]), ann["metric"], truncate(ann["data"])
)
)
assert len(ann["data"]) == 0, ann["message"]