Skip to content
Commits on Source (9)
......@@ -15,7 +15,7 @@ from cobra import flux_analysis
from cobra import io
from cobra.util import show_versions
__version__ = "0.14.1"
__version__ = "0.14.2"
# set the warning format to be prettier and fit on one line
_cobra_path = _dirname(_abspath(__file__))
......
......@@ -19,7 +19,8 @@ from cobra.core.object import Object
from cobra.core.reaction import Reaction
from cobra.core.solution import get_solution
from cobra.exceptions import SolverNotFound
from cobra.medium import find_boundary_types, sbo_terms
from cobra.medium import (
find_boundary_types, find_external_compartment, sbo_terms)
from cobra.util.context import HistoryManager, get_context, resettable
from cobra.util.solver import (
add_cons_vars_to_problem, assert_optimal, interface_to_str,
......@@ -505,15 +506,22 @@ class Model(Object):
>>> demand.build_reaction_string()
'atp_c --> '
"""
if ub is None:
ub = CONFIGURATION.upper_bound
if lb is None:
lb = CONFIGURATION.lower_bound
ub = CONFIGURATION.upper_bound if ub is None else ub
lb = CONFIGURATION.lower_bound if lb is None else lb
types = {
"exchange": ("EX", lb, ub, sbo_terms["exchange"]),
"demand": ("DM", 0, ub, sbo_terms["demand"]),
"sink": ("SK", lb, ub, sbo_terms["sink"])
}
if type == "exchange":
external = find_external_compartment(self)
if metabolite.compartment != external:
raise ValueError("The metabolite is not an external metabolite"
" (compartment is `%s` but should be `%s`). "
"Did you mean to add a demand or sink? "
"If not, either change its compartment or "
"rename the model compartments to fix this." %
(metabolite.compartment, external))
if type in types:
prefix, lb, ub, default_term = types[type]
if reaction_id is None:
......
# -*- coding: utf-8 -*-
"""Lists and annotations for compartment names and reactions.
Please send a PR if you want to add something here :)
"""
excludes = {
"demand": ["SN_", "SK_", "sink", "EX_", "exchange"],
"exchange": ["demand", "DM_", "biosynthesis", "transcription",
"replication", "SN_", "SK_", "sink"],
"sink": ["demand", "DM_", "biosynthesis", "transcription",
"replication", "EX_", "exchange"]
}
"""A list of sub-strings in reaction IDs that usually indicate
that the reaction is *not* a reaction of the specified type."""
sbo_terms = {"demand": "SBO:0000628",
"exchange": "SBO:0000627",
"sink": "SBO:0000632",
"biomass": "SBO:0000629",
"pseudoreaction": "SBO:0000631"}
"""SBO term identifiers for various boundary types."""
compartment_shortlist = {
"ce": ["cell envelope"],
"c": ["cytoplasm", "cytosol", "default", "in", "intra cellular",
"intracellular", "intracellular region", "intracellular space"],
"er": ["endoplasmic reticulum"],
"erm": ["endoplasmic reticulum membrane"],
"e": ["extracellular", "extraorganism", "out", "extracellular space",
"extra organism", "extra cellular", "extra-organism", "external",
"external medium"],
"f": ["flagellum", "bacterial-type flagellum"],
"g": ["golgi", "golgi apparatus"],
"gm": ["golgi membrane"],
"h": ["chloroplast"],
"l": ["lysosome"],
"im": ["mitochondrial intermembrane space"],
"mm": ["mitochondrial membrane"],
"m": ["mitochondrion", "mitochondria"],
"n": ["nucleus"],
"p": ["periplasm", "periplasmic space"],
"x": ["peroxisome", "glyoxysome"],
"u": ["thylakoid"],
"vm": ["vacuolar membrane"],
"v": ["vacuole"],
"w": ["cell wall"],
"s": ["eyespot", "eyespot apparatus", "stigma"]
}
"""A list of common compartment abbreviations and alternative names."""
......@@ -15,23 +15,12 @@ http://doi.org/10.1038/nprot.2009.203
import logging
from collections import Counter
import pandas as pd
LOGGER = logging.getLogger(__name__)
from cobra.medium.annotations import compartment_shortlist, excludes, sbo_terms
excludes = {"demand": ["SN_", "SK_", "sink", "EX_", "exchange"],
"exchange": ["demand", "DM_", "biosynthesis", "transcription",
"replication", "SN_", "SK_", "sink"],
"sink": ["demand", "DM_", "biosynthesis", "transcription",
"replication", "EX_", "exchange"]}
"""A list of sub-strings in reaction IDs that usually indicate
that the reaction is *not* a reaction of the specified type."""
sbo_terms = {"demand": "SBO:0000628",
"exchange": "SBO:0000627",
"sink": "SBO:0000632",
"biomass": "SBO:0000629",
"pseudoreaction": "SBO:0000631"}
"""SBO term identifiers for various boundary types."""
LOGGER = logging.getLogger(__name__)
def find_external_compartment(model):
......@@ -50,25 +39,47 @@ def find_external_compartment(model):
str
The putative external compartment.
"""
if not model.boundary:
LOGGER.error("The heuristic for discovering an external compartment "
"relies on boundary reactions. Yet, there are no "
"boundary reactions in this model.")
raise RuntimeError(
"The external compartment cannot be identified. "
"The heuristic for discovering an external compartment "
"relies on boundary reactions. Yet, there are no "
"boundary reactions in this model.")
counts = Counter(tuple(r.compartments)[0] for r in model.boundary)
most = counts.most_common(1)[0][0]
if "e" in model.compartments:
if most == "e":
return "e"
if model.boundary:
counts = pd.Series(tuple(r.compartments)[0] for r in model.boundary)
most = counts.value_counts()
most = most.index[most == most.max()].to_series()
else:
LOGGER.warning("There is an `e` compartment but it does not look "
"like it is the actual external compartment.")
return most
return most
most = None
like_external = compartment_shortlist["e"] + ["e"]
matches = pd.Series([co in like_external for co in model.compartments],
index=model.compartments)
if matches.sum() == 1:
compartment = matches.index[matches][0]
LOGGER.info("Compartment `%s` sounds like an external compartment. "
"Using this one without counting boundary reactions" %
compartment)
return compartment
elif most is not None and matches.sum() > 1 and matches[most].sum() == 1:
compartment = most[matches[most]][0]
LOGGER.warning("There are several compartments that look like an "
"external compartment but `%s` has the most boundary "
"reactions, so using that as the external "
"compartment." % compartment)
return compartment
elif matches.sum() > 1:
raise RuntimeError("There are several compartments (%s) that look "
"like external compartments but we can't tell "
"which one to use. Consider renaming your "
"compartments please.")
if most is not None:
return most[0]
LOGGER.warning("Could not identify an external compartment by name and"
" choosing one with the most boundary reactions. That "
"might be complete nonsense or change suddenly. "
"Consider renaming your compartments using "
"`Model.compartments` to fix this.")
# No info in the model, so give up
raise RuntimeError("The heuristic for discovering an external compartment "
"relies on names and boundary reactions. Yet, there "
"are neither compartments with recognized names nor "
"boundary reactions in the model.")
def is_boundary_type(reaction, boundary_type, external_compartment):
......
......@@ -6,7 +6,7 @@ import pandas as pd
import pytest
import cobra.medium as medium
from cobra import Reaction
from cobra import Metabolite, Reaction
class TestModelMedium:
......@@ -54,7 +54,30 @@ class TestModelMedium:
class TestTypeDetection:
def test_external_compartment(self, model):
# by name
assert medium.find_external_compartment(model) == "e"
# from boundary counts
for m in model.metabolites:
if m.compartment == "e":
m.compartment = "outside"
for r in model.reactions:
r._compartments = None
assert medium.find_external_compartment(model) == "outside"
# names are always right
model.exchanges[0].reactants[0].compartment = "extracellular"
assert medium.find_external_compartment(model) == "extracellular"
def test_multi_external(self, model):
for r in model.reactions:
r._compartments = None
model.exchanges[0].reactants[0].compartment = "extracellular"
# still works due to different boundary numbers
assert medium.find_external_compartment(model) == "e"
model.exchanges[1].reactants[0].compartment = "extra cellular"
model.remove_reactions(model.exchanges)
# Now fails because same boundary count
with pytest.raises(RuntimeError):
medium.find_external_compartment(model)
def test_exchange(self, model):
ex = model.exchanges
......@@ -145,6 +168,14 @@ class TestErrorsAndExceptions:
def test_no_boundary_reactions(self, empty_model):
assert medium.find_boundary_types(empty_model, 'e', None) == []
def test_no_boundary_reactions(self, empty_model):
def test_no_names_or_boundary_reactions(self, empty_model):
with pytest.raises(RuntimeError):
medium.find_external_compartment(empty_model)
def test_bad_exchange(self, model):
with pytest.raises(ValueError):
m = Metabolite("baddy", compartment="nonsense")
model.add_boundary(m, type="exchange")
m = Metabolite("goody", compartment="e")
rxn = model.add_boundary(m, type="exchange")
assert isinstance(rxn, Reaction)
python-cobra (0.14.1-2) UNRELEASED; urgency=medium
python-cobra (0.14.2-1) unstable; urgency=medium
* Team upload.
* Do not install __pycache__
* debhelper 12
* Standards-Version: 4.3.0
* rename debian/tests/control.autodep8 to debian/tests/control
* Enable python3-sbml
* Build-/Test-Depends: python3-simplejson
-- Andreas Tille <tille@debian.org> Sat, 22 Dec 2018 08:08:01 +0100
-- Andreas Tille <tille@debian.org> Mon, 04 Feb 2019 15:12:37 +0100
python-cobra (0.14.1-1) unstable; urgency=medium
......
......@@ -4,7 +4,7 @@ Uploaders: Afif Elghraoui <afif@debian.org>
Section: python
Testsuite: autopkgtest-pkg-python
Priority: optional
Build-Depends: debhelper (>= 11~),
Build-Depends: debhelper (>= 12~),
dh-python,
libglpk-dev,
python3-all,
......@@ -17,16 +17,18 @@ Build-Depends: debhelper (>= 11~),
python3-ruamel.yaml,
python3-pandas (>= 0.17.0),
python3-pip,
python3-pipdeptree (>= 0.13.1),
python3-pipdeptree,
python3-requests,
python3-swiglpk,
python3-tabulate,
python3-sbml,
python3-simplejson,
cython3,
# Test-Depends:
python3-pytest,
python3-pytest-benchmark,
python3-jsonschema (>> 2.5.0)
Standards-Version: 4.2.1
Standards-Version: 4.3.0
Vcs-Browser: https://salsa.debian.org/med-team/python-cobra
Vcs-Git: https://salsa.debian.org/med-team/python-cobra.git
Homepage: http://opencobra.github.io/cobrapy/
......@@ -42,7 +44,7 @@ Recommends: python3-numpy,
python3-pandas (>= 0.17.0),
python3-simplejson,
python3-swiglpk,
python3-tabulate,
python3-tabulate
Suggests: python3-matplotlib,
qsopt-ex
Description: constraint-based modeling of biological networks with Python 3
......
......@@ -22,3 +22,4 @@ override_dh_install:
override_dh_auto_clean:
dh_auto_clean
rm -f cobra/solvers/cglpk.c
rm -rf .pytest_cache
......@@ -8,10 +8,9 @@ Depends:
python3-pytest-benchmark,
python3-jsonschema,
python3-simplejson,
# See the comment for the corresponding section in the python2 test above.
python3-scipy,
python3-numpy,
python3-pandas,
# Python2 test also contained python-sbml. Once python3-sbml might exist this should be probably added here
# python3-sbml
python3-sbml,
python3-simplejson
Restrictions: allow-stderr
# Release notes for cobrapy 0.14.2
## Fixes
* Better identification of the external compartment.
* Fix the installation of all optional dependencies, i.e., `pip install cobra[all]`.
[bumpversion]
current_version = 0.14.1
current_version = 0.14.2
commit = True
tag = True
parse = (?P<major>\d+)
......
......@@ -2,10 +2,11 @@
from __future__ import absolute_import
from warnings import warn
from sys import argv, version_info
from warnings import warn
from setuptools import find_packages, setup
from setuptools import setup, find_packages
if version_info[:2] == (3, 4):
warn("Support for Python 3.4 was dropped by pandas. Since cobrapy is a "
......@@ -23,7 +24,7 @@ extras = {
'array': ["scipy"],
'sbml': ["python-libsbml", "lxml"]
}
extras["all"] = sorted(list(extras))
extras["all"] = sorted(extras.values())
try:
with open('README.rst') as handle:
......@@ -37,7 +38,7 @@ except IOError:
if __name__ == "__main__":
setup(
name="cobra",
version="0.14.1",
version="0.14.2",
packages=find_packages(),
setup_requires=setup_requirements,
install_requires=[
......