[med-svn] [python-cobra] 01/07: Imported Upstream version 0.4.2~b1

Afif Elghraoui afif at moszumanska.debian.org
Sun Jul 17 23:52:50 UTC 2016


This is an automated email from the git hooks/post-receive script.

afif pushed a commit to branch master
in repository python-cobra.

commit 191cd73b22fbc7052077425185782261e1354265
Author: Afif Elghraoui <afif at ghraoui.name>
Date:   Sat Jul 16 20:12:30 2016 -0700

    Imported Upstream version 0.4.2~b1
---
 .gitignore                           |   1 +
 INSTALL.md                           |  11 +--
 README.md                            |   7 +-
 appveyor.yml                         |  20 +++--
 appveyor/build_glpk.py               |   4 +-
 cobra/VERSION                        |   2 +-
 cobra/core/DictList.py               |   4 +-
 cobra/io/json.py                     |   4 +-
 cobra/io/mat.py                      |  10 ++-
 cobra/io/sbml.py                     |   5 ++
 cobra/manipulation/modify.py         |  52 +++++++++++-
 cobra/solvers/gurobi_solver.py       |   5 +-
 cobra/solvers/mosek.py               |   2 +
 cobra/test/flux_analysis.py          |  42 ++++++----
 cobra/test/manipulation.py           |  25 ++++++
 cobra/test/solvers.py                |   2 +-
 documentation_builder/loopless.ipynb | 156 +++++++++++++++++++++++++----------
 ez_setup.py                          |  77 ++++++++++++-----
 setup.py                             |   4 +-
 19 files changed, 318 insertions(+), 115 deletions(-)

diff --git a/.gitignore b/.gitignore
index 7c0be42..854e81a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,3 +88,4 @@ libglpk.a
 .idea/
 .DS_Store
 .eggs/
+*\.swp
diff --git a/INSTALL.md b/INSTALL.md
index 125b291..c58d35b 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -19,17 +19,10 @@ cobrapy, they are not explicitly supported (yet!).
 cobrapy can be installed with any recent installation of pip. Instructions
 for several operating systems are below:
 
-### Mac OS X
+### Mac OS X or Linux
 0. [install pip](http://pip.readthedocs.org/en/latest/installing.html).
 1. In a terminal, run ```sudo pip install cobra```
 
-### Ubuntu or Debian Linux
-0. [install pip](http://pip.readthedocs.org/en/latest/installing.html).
-1. Install the python and glpk development libraries. On debian-based
-   systems (including Ubuntu and Mint), this can be done with
-   ```sudo apt-get install python-dev libglpk-dev```
-3. In a terminal, run ```sudo pip install cobra```
-
 ### Microsoft Windows
 The preferred installation method on Windows is also to use pip. The latest
 Windows installers for Python 2.7 and 3.4 include pip, so if you use those you
@@ -107,3 +100,5 @@ from cobra.test import test_all
 test_all()
 ```
 
+You should see some skipped tests and expected failures, and the function should return ```False```.
+
diff --git a/README.md b/README.md
index 5b96ea6..75b0e2b 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ cobrapy
 COnstraint-Based Reconstruction and Analysis (COBRA) methods are widely used
 for genome-scale modeling of metabolic networks in both prokaryotes and
 eukaryotes. COBRApy is a constraint-based modeling package that is designed to
-accomodate the biological complexity of the next generation of COBRA models and
+accommodate the biological complexity of the next generation of COBRA models and
 provides access to commonly used COBRA methods, such as flux balance analysis,
 flux variability analysis, and gene deletion analyses.
 
@@ -31,9 +31,8 @@ License
 -------
 The cobrapy source is released under both the GPL and LGPL licenses.  You may
 choose which license you choose to use the software under. However, please note
-that binary packages which include GLPK (such as the binary wheels for Windows
-and Mac OS X distributed at https://pypi.python.org/pypi/cobra) will be bound
-by its license as well.
+that binary packages which include GLPK (such as the binary wheels distributed
+at https://pypi.python.org/pypi/cobra) will be bound by its license as well.
 
 This program is free software: you can redistribute it and/or modify it under
 the terms of the GNU General Public License or the Lesser GNU General Public
diff --git a/appveyor.yml b/appveyor.yml
index 09aa50b..decb8ff 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -9,27 +9,27 @@ environment:
 
   matrix:
     - PYTHON: "C:\\Python27"
-      PYTHON_VERSION: "2.7.11"
+      PYTHON_VERSION: "2.7.12"
       PYTHON_ARCH: "32"
 
     - PYTHON: "C:\\Python34"
-      PYTHON_VERSION: "3.4.4"
+      PYTHON_VERSION: "3.4.5"
       PYTHON_ARCH: "32"
 
     - PYTHON: "C:\\Python35"
-      PYTHON_VERSION: "3.5.1"
+      PYTHON_VERSION: "3.5.2"
       PYTHON_ARCH: "32"
 
     - PYTHON: "C:\\Python27-x64"
-      PYTHON_VERSION: "2.7.11"
+      PYTHON_VERSION: "2.7.12"
       PYTHON_ARCH: "64"
 
     - PYTHON: "C:\\Python34-x64"
-      PYTHON_VERSION: "3.4.4"
+      PYTHON_VERSION: "3.4.5"
       PYTHON_ARCH: "64"
 
     - PYTHON: "C:\\Python35-x64"
-      PYTHON_VERSION: "3.5.1"
+      PYTHON_VERSION: "3.5.2"
       PYTHON_ARCH: "64"
 
 clone_depth: 25
@@ -47,7 +47,7 @@ install:
   - ps: Start-FileDownload 'https://bitbucket.org/gutworth/six/raw/default/six.py'
   - "%WITH_COMPILER% %PYTHON%/python appveyor/build_glpk.py"
   - "%PYTHON%/python -m pip install pip setuptools wheel --upgrade"
-  - "%PYTHON%/python -m pip install Cython jsonschema"
+  - "%PYTHON%/python -m pip install Cython jsonschema numpy twine pypandoc==1.1.3"
 
 build: off
 
@@ -60,5 +60,11 @@ after_test:
 artifacts:
   - path: dist\*
 
+deploy_script:
+  - ps: >-
+      if($env:appveyor_repo_tag -eq 'True') {
+          Invoke-Expression "$env:PYTHON/Scripts/twine upload dist/* --username $env:PYPI_USERNAME --password $env:PYPI_PASSWORD"
+      }
+
 #on_success:
 #  - TODO: upload the content of dist/*.whl to a public wheelhouse
diff --git a/appveyor/build_glpk.py b/appveyor/build_glpk.py
index 1aff5cd..1e9dfe1 100644
--- a/appveyor/build_glpk.py
+++ b/appveyor/build_glpk.py
@@ -11,8 +11,8 @@ except ImportError:  # python 3
     import urllib.request as urllib2
 
 # these need to be set to the latest glpk version
-glpk_version = "4.59"
-glpk_md5 = "c84ce7b8286ab91f2e871cd82050e2fe"
+glpk_version = "4.60"
+glpk_md5 = "eda7965907f6919ffc69801646f13c3e"
 
 glpk_build_dir = "glpk_build/glpk-%s" % glpk_version
 url = "http://ftp.gnu.org/gnu/glpk/glpk-%s.tar.gz" % glpk_version
diff --git a/cobra/VERSION b/cobra/VERSION
index 267577d..9901f66 100644
--- a/cobra/VERSION
+++ b/cobra/VERSION
@@ -1 +1 @@
-0.4.1
+0.4.2b1
diff --git a/cobra/core/DictList.py b/cobra/core/DictList.py
index 8925965..2feb0ac 100644
--- a/cobra/core/DictList.py
+++ b/cobra/core/DictList.py
@@ -323,7 +323,9 @@ class DictList(list):
             list.__setitem__(self, i, y)
             self._generate_index()
             return
-        self._dict.pop(self[i].id)
+        # in case a rename has occured
+        if self._dict.get(self[i].id) == i:
+            self._dict.pop(self[i].id)
         the_id = y.id
         self._check(the_id)
         list.__setitem__(self, i, y)
diff --git a/cobra/io/json.py b/cobra/io/json.py
index f04a9b5..fe78550 100644
--- a/cobra/io/json.py
+++ b/cobra/io/json.py
@@ -85,7 +85,7 @@ def _from_dict(obj):
     for gene in obj['genes']:
         new_gene = Gene(gene["id"])
         for k, v in iteritems(gene):
-            setattr(new_gene, k, _fix_type(v))
+            setattr(new_gene, k, v)
         model.genes.append(new_gene)
     # add reactions
     new_reactions = []
@@ -99,7 +99,7 @@ def _from_dict(obj):
                     {model.metabolites.get_by_id(str(met)): coeff
                      for met, coeff in iteritems(v)})
             else:
-                setattr(new_reaction, k, _fix_type(v))
+                setattr(new_reaction, k, v)
         new_reactions.append(new_reaction)
     model.add_reactions(new_reactions)
     for k, v in iteritems(obj):
diff --git a/cobra/io/mat.py b/cobra/io/mat.py
index 5ee1c76..801c551 100644
--- a/cobra/io/mat.py
+++ b/cobra/io/mat.py
@@ -4,7 +4,7 @@ from warnings import warn
 
 from numpy import array, object as np_object
 from scipy.io import loadmat, savemat
-from scipy.sparse import coo_matrix
+from scipy.sparse import coo_matrix, dok_matrix
 
 from .. import Model, Metabolite, Reaction
 
@@ -108,6 +108,14 @@ def create_mat_dict(model):
         # can't have any None entries for charge, or this will fail
         pass
     mat["genes"] = _cell(model.genes.list_attr("id"))
+    # make a matrix for rxnGeneMat
+    # reactions are rows, genes are columns
+    rxnGene = dok_matrix((len(model.reactions), len(model.genes)))
+    if min(rxnGene.shape) > 0:
+        for i, reaction in enumerate(model.reactions):
+            for gene in reaction.genes:
+                rxnGene[i, model.genes.index(gene)] = 1
+        mat["rxnGeneMat"] = rxnGene
     mat["grRules"] = _cell(rxns.list_attr("gene_reaction_rule"))
     mat["rxns"] = _cell(rxns.list_attr("id"))
     mat["rxnNames"] = _cell(rxns.list_attr("name"))
diff --git a/cobra/io/sbml.py b/cobra/io/sbml.py
index c4cf4cf..5a9bf30 100644
--- a/cobra/io/sbml.py
+++ b/cobra/io/sbml.py
@@ -209,6 +209,11 @@ def create_cobra_model_from_sbml_file(sbml_filename, old_sbml=False, legacy_meta
                         cobra_metabolites.pop(tmp_metabolite)
                 else:
                     cobra_metabolites[tmp_metabolite] = sbml_metabolite.getStoichiometry()
+        # check for nan
+        for met, v in iteritems(cobra_metabolites):
+            if isnan(v) or isinf(v):
+                warn("invalid value %s for metabolite '%s' in reaction '%s'" %
+                     (str(v), met.id, reaction.id))
         reaction.add_metabolites(cobra_metabolites)
         #Parse the kinetic law info here.
         parameter_dict = {}
diff --git a/cobra/manipulation/modify.py b/cobra/manipulation/modify.py
index 75a2e9d..7866e4d 100644
--- a/cobra/manipulation/modify.py
+++ b/cobra/manipulation/modify.py
@@ -5,7 +5,7 @@ from ast import NodeTransformer
 
 from six import iteritems
 
-from .. import Reaction, Metabolite
+from .. import Reaction, Metabolite, Gene
 from .delete import get_compiled_gene_reaction_rules
 from ..core.Gene import ast2str
 
@@ -42,7 +42,7 @@ def _escape_str_id(id_str):
     return id_str
 
 
-class _GeneRenamer(NodeTransformer):
+class _GeneEscaper(NodeTransformer):
 
     def visit_Name(self, node):
         node.id = _escape_str_id(node.id)
@@ -57,12 +57,58 @@ def escape_ID(cobra_model):
                    cobra_model.genes):
         x.id = _escape_str_id(x.id)
     cobra_model.repair()
-    gene_renamer = _GeneRenamer()
+    gene_renamer = _GeneEscaper()
     for rxn, rule in iteritems(get_compiled_gene_reaction_rules(cobra_model)):
         if rule is not None:
             rxn._gene_reaction_rule = ast2str(gene_renamer.visit(rule))
 
 
+def rename_genes(cobra_model, rename_dict):
+    """renames genes in a model from the rename_dict"""
+    recompute_reactions = set()  # need to recomptue related genes
+    remove_genes = []
+    for old_name, new_name in iteritems(rename_dict):
+        # undefined if there a value matches a different key
+        # because dict is unordered
+        try:
+            gene_index = cobra_model.genes.index(old_name)
+        except ValueError:
+            gene_index = None
+        old_gene_present = gene_index is not None
+        new_gene_present = new_name in cobra_model.genes
+        if old_gene_present and new_gene_present:
+            old_gene = cobra_model.genes.get_by_id(old_name)
+            remove_genes.append(old_gene)
+            recompute_reactions.update(old_gene._reaction)
+        elif old_gene_present and not new_gene_present:
+            # rename old gene to new gene
+            gene = cobra_model.genes[gene_index]
+            # trick DictList into updating index
+            cobra_model.genes._dict.pop(gene.id)  # ugh
+            gene.id = new_name
+            cobra_model.genes[gene_index] = gene
+        elif not old_gene_present and new_gene_present:
+            pass
+        else:  # not old gene_present and not new_gene_present
+            # the new gene's _model will be set by repair
+            cobra_model.genes.append(Gene(new_name))
+    cobra_model.repair()
+
+    class Renamer(NodeTransformer):
+        def visit_Name(self, node):
+            node.id = rename_dict.get(node.id, node.id)
+            return node
+    gene_renamer = Renamer()
+    for rxn, rule in iteritems(get_compiled_gene_reaction_rules(cobra_model)):
+        if rule is not None:
+            rxn._gene_reaction_rule = ast2str(gene_renamer.visit(rule))
+
+    for rxn in recompute_reactions:
+        rxn.gene_reaction_rule = rxn._gene_reaction_rule
+    for i in remove_genes:
+        cobra_model.genes.remove(i)
+
+
 def initialize_growth_medium(cobra_model, the_medium='MgM',
                              external_boundary_compartment='e',
                              external_boundary_reactions=None,
diff --git a/cobra/solvers/gurobi_solver.py b/cobra/solvers/gurobi_solver.py
index b2953b8..c7a3972 100644
--- a/cobra/solvers/gurobi_solver.py
+++ b/cobra/solvers/gurobi_solver.py
@@ -188,6 +188,9 @@ def create_problem(cobra_model, quadratic_component=None, **kwargs):
         the_parameters = parameter_defaults.copy()
         the_parameters.update(kwargs)
 
+    # Set verbosity first to quiet infos on parameter changes
+    if "verbose" in the_parameters:
+        set_parameter(lp, "verbose", the_parameters["verbose"])
     for k, v in iteritems(the_parameters):
         set_parameter(lp, k, v)
 
@@ -260,7 +263,7 @@ def solve_problem(lp, **kwargs):
     status = get_status(lp)
     return status
 
-    
+
 def solve(cobra_model, **kwargs):
     """
 
diff --git a/cobra/solvers/mosek.py b/cobra/solvers/mosek.py
index 8078fa7..683b9d3 100644
--- a/cobra/solvers/mosek.py
+++ b/cobra/solvers/mosek.py
@@ -71,6 +71,7 @@ def create_problem(cobra_model, objective_sense="maximize",
     lp.putdouparam(mosek.dparam.basis_tol_s, 1e-9)
     lp.putdouparam(mosek.dparam.basis_rel_tol_s, 0.)
     lp.putdouparam(mosek.dparam.simplex_abs_tol_piv, 1e-12)
+    lp.putdouparam(mosek.dparam.intpnt_tol_rel_gap, 1e-6)
     lp.putdouparam(mosek.dparam.presolve_tol_aij, 1e-15)
     lp.putdouparam(mosek.dparam.presolve_tol_abs_lindep, 0.)
     lp.putdouparam(mosek.dparam.presolve_tol_s, 0.)
@@ -124,6 +125,7 @@ def set_objective_sense(lp, objective_sense):
 
 
 def set_parameter(lp, parameter_name, parameter_value):
+    parameter_name = parameter_name.lower()
     parameter_name = param_aliases.get(parameter_name, parameter_name)
     if parameter_name == "verbose":
         if parameter_value:
diff --git a/cobra/test/flux_analysis.py b/cobra/test/flux_analysis.py
index 60d6cce..0e79699 100644
--- a/cobra/test/flux_analysis.py
+++ b/cobra/test/flux_analysis.py
@@ -107,27 +107,37 @@ class TestCobraFluxAnalysis(TestCase):
                 optimize_minimal_flux(model, solver=solver)
             model.reactions.ATPM.lower_bound = atpm
 
-    def test_single_gene_deletion(self):
+    def test_single_gene_deletion_fba(self):
         cobra_model = create_test_model("textbook")
         # expected knockouts for textbook model
-        growth_dict = {"fba": {"b0008": 0.87, "b0114": 0.80, "b0116": 0.78,
-                               "b2276": 0.21, "b1779": 0.00},
-                       "moma": {"b0008": 0.87, "b0114": 0.71, "b0116": 0.56,
-                                "b2276": 0.11, "b1779": 0.00},
-                       }
-
-        # MOMA requires cplex or gurobi
+        growth_dict = {"b0008": 0.87, "b0114": 0.80, "b0116": 0.78,
+                       "b2276": 0.21, "b1779": 0.00}
+
+        rates, statuses = single_gene_deletion(cobra_model,
+                                               gene_list=growth_dict.keys(),
+                                               method="fba")
+        for gene, expected_value in iteritems(growth_dict):
+            self.assertEqual(statuses[gene], 'optimal')
+            self.assertAlmostEqual(rates[gene], expected_value, places=2)
+
+    def test_single_gene_deletion_moma(self):
+        # MOMA requires a QP solver
         try:
             get_solver_name(qp=True)
         except:
-            growth_dict.pop('moma')
-        for method, expected in growth_dict.items():
-            rates, statuses = single_gene_deletion(cobra_model,
-                                                   gene_list=expected.keys(),
-                                                   method=method)
-            for gene, expected_value in iteritems(expected):
-                self.assertEqual(statuses[gene], 'optimal')
-                self.assertAlmostEqual(rates[gene], expected_value, places=2)
+            self.skipTest("no qp support")
+
+        cobra_model = create_test_model("textbook")
+        # expected knockouts for textbook model
+        growth_dict = {"b0008": 0.87, "b0114": 0.71, "b0116": 0.56,
+                       "b2276": 0.11, "b1779": 0.00}
+
+        rates, statuses = single_gene_deletion(cobra_model,
+                                               gene_list=growth_dict.keys(),
+                                               method="moma")
+        for gene, expected_value in iteritems(growth_dict):
+            self.assertEqual(statuses[gene], 'optimal')
+            self.assertAlmostEqual(rates[gene], expected_value, places=2)
 
     def test_single_reaction_deletion(self):
         cobra_model = create_test_model("textbook")
diff --git a/cobra/test/manipulation.py b/cobra/test/manipulation.py
index 3bca63d..30f5c08 100644
--- a/cobra/test/manipulation.py
+++ b/cobra/test/manipulation.py
@@ -82,6 +82,31 @@ class TestManipulation(TestCase):
         escape_ID(model)
         self.assertNotIn("a.b", model.genes)
 
+    def test_rename_gene(self):
+        model = create_test_model('textbook')
+        original_name = model.genes.b1241.name
+        rename_dict = {"b1241": "foo", "hello": "world",
+                       "b2465": "b3919", "bar": "2935"}
+        modify.rename_genes(model, rename_dict)
+        for i in rename_dict:
+            self.assertNotIn(i, model.genes)
+        self.assertIn("foo", model.genes)
+        # make sure the object name was preserved
+        self.assertEqual(model.genes.foo.name, original_name)
+        # make sure the reactions are correct
+        self.assertEqual(len(model.genes.foo.reactions), 2)
+        self.assertEqual(model.reactions.ACALD.gene_reaction_rule,
+                         "b0351 or foo")
+        self.assertEqual(model.reactions.TPI.gene_reaction_rule, "b3919")
+        self.assertEqual(model.reactions.TPI.genes, {model.genes.b3919})
+        self.assertEqual(model.reactions.TKT1.gene_reaction_rule,
+                         "b2935 or b3919")
+        self.assertEqual(model.reactions.TKT1.genes,
+                         {model.genes.b2935, model.genes.b3919})
+        self.assertEqual(model.genes.b3919.reactions,
+                         {model.reactions.get_by_id(i)
+                          for i in ("TKT1", "TKT2", "TPI")})
+
     def test_gene_knockout_computation(self):
         cobra_model = create_test_model()
 
diff --git a/cobra/test/solvers.py b/cobra/test/solvers.py
index ceed550..a417e96 100644
--- a/cobra/test/solvers.py
+++ b/cobra/test/solvers.py
@@ -103,8 +103,8 @@ class TestCobraSolver(object):
         solver.solve_problem(minimize)
         max_solution = solver.format_solution(maximize, self.model)
         min_solution = solver.format_solution(minimize, self.model)
-        self.assertAlmostEqual(0, min_solution.f, places=4)
         self.assertEqual(min_solution.status, "optimal")
+        self.assertAlmostEqual(0, min_solution.f, places=4)
         self.assertAlmostEqual(self.old_solution, max_solution.f, places=4)
         self.assertEqual(max_solution.status, "optimal")
         # if we set minimize at creation, can we override it at solve
diff --git a/documentation_builder/loopless.ipynb b/documentation_builder/loopless.ipynb
index c3bdc00..30e6a6d 100644
--- a/documentation_builder/loopless.ipynb
+++ b/documentation_builder/loopless.ipynb
@@ -65,6 +65,7 @@
     "import cobra.test\n",
     "from cobra import Reaction, Metabolite, Model\n",
     "from cobra.flux_analysis.loopless import construct_loopless_model\n",
+    "from cobra.flux_analysis import optimize_minimal_flux\n",
     "from cobra.solvers import get_solver_name"
    ]
   },
@@ -84,10 +85,10 @@
    "outputs": [
     {
      "data": {
-      "application/pdf": "JVBERi0xLjQKJazcIKu6CjEgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL1BhZ2VzIDIgMCBSID4+\nCmVuZG9iago4IDAgb2JqCjw8IC9QYXR0ZXJuIDUgMCBSIC9YT2JqZWN0IDcgMCBSCi9Qcm9jU2V0\nIFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9Gb250IDMgMCBSIC9TaGFk\naW5nIDYgMCBSCi9FeHRHU3RhdGUgNCAwIFIgPj4KZW5kb2JqCjEwIDAgb2JqCjw8IC9UeXBlIC9Q\nYWdlIC9Hcm91cCA8PCAvVHlwZSAvR3JvdXAgL1MgL1RyYW5zcGFyZW5jeSAvQ1MgL0RldmljZVJH\nQiA+PgovQ29udGVudHMgOSAwIFIgL1Jlc291cmNlcyA4IDAgUiAvTWVkaWFCb3ggWyAwIDAgNjI4 [...]
+      "application/pdf": "JVBERi0xLjQKJazcIKu6CjEgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL1BhZ2VzIDIgMCBSID4+\nCmVuZG9iago4IDAgb2JqCjw8IC9QYXR0ZXJuIDUgMCBSIC9TaGFkaW5nIDYgMCBSCi9Qcm9jU2V0\nIFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9YT2JqZWN0IDcgMCBSIC9G\nb250IDMgMCBSCi9FeHRHU3RhdGUgNCAwIFIgPj4KZW5kb2JqCjEwIDAgb2JqCjw8IC9UeXBlIC9Q\nYWdlIC9Hcm91cCA8PCAvVHlwZSAvR3JvdXAgL1MgL1RyYW5zcGFyZW5jeSAvQ1MgL0RldmljZVJH\nQiA+PgovUGFyZW50IDIgMCBSIC9Db250ZW50cyA5IDAgUiAvUmVzb3VyY2VzIDggMCBSIC9Bbm5v [...]
       "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnQAAAEcCAYAAABOJillAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xe4JFWd//H3dwJMIo0iCEiQsLpG1B3BBCtmAUHSGhhZ\nVBQHI6YVFzBhzmDARaIRRAXUURGVIEEFFFFBJYiAyA9wgAnAzHx/f5y6zuVy8+3u6up+v56nn7rd\nXdX1vTNd3Z97TtU5kZlIkiSpuabVXYAkSZKmxkAnSZLUcAY6SZKkhjPQSZIkNZyBTpIkqeEMdJIk\nSQ1noJMkSWo4A50kSVLDGegkSZIazkAnSZLUcAY6SZKkhjPQSZIkNZyBTpIkqeEMdJIkSQ1noJMk\nSWo4A50kSVLDGegkSZIazkAnSZLUcAY6SZKkhjPQSZIkNZyBTpIkqeEMdJIkSQ1noJMkSWo4A50k\nSVLD [...]
       "text/plain": [
-       "<matplotlib.figure.Figure at 0x7fc7e517e748>"
+       "<matplotlib.figure.Figure at 0x7f92b021c908>"
       ]
      },
      "metadata": {},
@@ -107,21 +108,17 @@
    "outputs": [],
    "source": [
     "test_model = Model()\n",
-    "test_model.add_metabolites(Metabolite(\"A\"))\n",
-    "test_model.add_metabolites(Metabolite(\"B\"))\n",
-    "test_model.add_metabolites(Metabolite(\"C\"))\n",
-    "EX_A = Reaction(\"EX_A\")\n",
-    "EX_A.add_metabolites({test_model.metabolites.A: 1})\n",
-    "DM_C = Reaction(\"DM_C\")\n",
-    "DM_C.add_metabolites({test_model.metabolites.C: -1})\n",
-    "v1 = Reaction(\"v1\")\n",
-    "v1.add_metabolites({test_model.metabolites.A: -1, test_model.metabolites.B: 1})\n",
-    "v2 = Reaction(\"v2\")\n",
-    "v2.add_metabolites({test_model.metabolites.B: -1, test_model.metabolites.C: 1})\n",
-    "v3 = Reaction(\"v3\")\n",
-    "v3.add_metabolites({test_model.metabolites.C: -1, test_model.metabolites.A: 1})\n",
-    "DM_C.objective_coefficient = 1\n",
-    "test_model.add_reactions([EX_A, DM_C, v1, v2, v3])"
+    "test_model.add_metabolites([Metabolite(i) for i in \"ABC\"])\n",
+    "test_model.add_reactions([Reaction(i) for i in\n",
+    "                          [\"EX_A\", \"DM_C\", \"v1\", \"v2\", \"v3\"]])\n",
+    "\n",
+    "test_model.reactions.EX_A.add_metabolites({\"A\": 1})\n",
+    "test_model.reactions.DM_C.add_metabolites({\"C\": -1})\n",
+    "test_model.reactions.DM_C.objective_coefficient = 1\n",
+    "\n",
+    "test_model.reactions.v1.add_metabolites({\"A\": -1, \"B\": 1})\n",
+    "test_model.reactions.v2.add_metabolites({\"B\": -1, \"C\": 1})\n",
+    "test_model.reactions.v3.add_metabolites({\"C\": -1, \"A\": 1})"
    ]
   },
   {
@@ -139,25 +136,25 @@
    },
    "outputs": [
     {
-     "data": {
-      "text/plain": [
-       "<Solution 1000.00 at 0x7fc7bd7a3b38>"
-      ]
-     },
-     "execution_count": 4,
-     "metadata": {},
-     "output_type": "execute_result"
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "loopless solution: status = optimal\n",
+      "loopless solution: v3 = 0.0\n"
+     ]
     }
    ],
    "source": [
-    "construct_loopless_model(test_model).optimize()"
+    "solution = construct_loopless_model(test_model).optimize()\n",
+    "print(\"loopless solution: status = \" + solution.status)\n",
+    "print(\"loopless solution: v3 = %.1f\" % solution.x_dict[\"v3\"])"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "However, if flux is forced through v3, then there is no longer a feasible loopless solution."
+    "If there there is no forced flux through a loopless reaction, parsimonious FBA will also have no flux through the loop."
    ]
   },
   {
@@ -168,26 +165,25 @@
    },
    "outputs": [
     {
-     "data": {
-      "text/plain": [
-       "<Solution 'infeasible' at 0x7fc7bd550208>"
-      ]
-     },
-     "execution_count": 5,
-     "metadata": {},
-     "output_type": "execute_result"
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "parsimonious solution: status = optimal\n",
+      "parsimonious solution: v3 = 0.0\n"
+     ]
     }
    ],
    "source": [
-    "v3.lower_bound = 1\n",
-    "construct_loopless_model(test_model).optimize()"
+    "solution = optimize_minimal_flux(test_model)\n",
+    "print(\"parsimonious solution: status = \" + solution.status)\n",
+    "print(\"parsimonious solution: v3 = %.1f\" % solution.x_dict[\"v3\"])"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Loopless FBA is also possible on genome scale models, but it requires a capable MILP solver."
+    "However, if flux is forced through v3, then there is no longer a feasible loopless solution, but the parsimonious solution will still exist."
    ]
   },
   {
@@ -198,24 +194,94 @@
    },
    "outputs": [
     {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "loopless solution: status = infeasible\n"
+     ]
+    }
+   ],
+   "source": [
+    "test_model.reactions.v3.lower_bound = 1\n",
+    "solution = construct_loopless_model(test_model).optimize()\n",
+    "print(\"loopless solution: status = \" + solution.status)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "parsimonious solution: status = optimal\n",
+      "parsimonious solution: v3 = 1.0\n"
+     ]
+    }
+   ],
+   "source": [
+    "solution = optimize_minimal_flux(test_model)\n",
+    "print(\"parsimonious solution: status = \" + solution.status)\n",
+    "print(\"parsimonious solution: v3 = %.1f\" % solution.x_dict[\"v3\"])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Loopless FBA is also possible on genome scale models, but it requires a capable MILP solver. If one is installed, cobrapy can detect it automatically using the get_solver_name function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "cplex\n"
+     ]
+    }
+   ],
+   "source": [
+    "mip_solver = get_solver_name(mip=True)\n",
+    "print(mip_solver)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
      "data": {
       "text/plain": [
-       "<Solution 0.38 at 0x7fc7b6d2d048>"
+       "<Solution 0.38 at 0x7f9285d7ffd0>"
       ]
      },
-     "execution_count": 6,
+     "execution_count": 9,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
     "salmonella = cobra.test.create_test_model(\"salmonella\")\n",
-    "construct_loopless_model(salmonella).optimize(solver=get_solver_name(mip=True))"
+    "construct_loopless_model(salmonella).optimize(solver=mip_solver)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 10,
    "metadata": {
     "collapsed": false
    },
@@ -223,17 +289,17 @@
     {
      "data": {
       "text/plain": [
-       "<Solution 0.98 at 0x7fc7b74ad240>"
+       "<Solution 0.98 at 0x7f9285c89470>"
       ]
      },
-     "execution_count": 7,
+     "execution_count": 10,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
     "ecoli = cobra.test.create_test_model(\"ecoli\")\n",
-    "construct_loopless_model(ecoli).optimize(solver=get_solver_name(mip=True))"
+    "construct_loopless_model(ecoli).optimize(solver=mip_solver)"
    ]
   }
  ],
diff --git a/ez_setup.py b/ez_setup.py
index 6804679..4ef3ee0 100644
--- a/ez_setup.py
+++ b/ez_setup.py
@@ -3,6 +3,8 @@
 """
 Setuptools bootstrapping installer.
 
+Maintained at https://github.com/pypa/setuptools/tree/bootstrap.
+
 Run this script to install or upgrade setuptools.
 """
 
@@ -16,22 +18,26 @@ import subprocess
 import platform
 import textwrap
 import contextlib
-import warnings
+import json
+import codecs
 
 from distutils import log
 
 try:
     from urllib.request import urlopen
+    from urllib.parse import urljoin
 except ImportError:
     from urllib2 import urlopen
+    from urlparse import urljoin
 
 try:
     from site import USER_SITE
 except ImportError:
     USER_SITE = None
 
-DEFAULT_VERSION = "15.2"
-DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
+LATEST = object()
+DEFAULT_VERSION = LATEST
+DEFAULT_URL = "https://pypi.io/packages/source/s/setuptools/"
 DEFAULT_SAVE_DIR = os.curdir
 
 
@@ -114,18 +120,19 @@ def archive_context(filename):
 
 def _do_download(version, download_base, to_dir, download_delay):
     """Download Setuptools."""
-    egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg'
-                       % (version, sys.version_info[0], sys.version_info[1]))
+    py_desig = 'py{sys.version_info[0]}.{sys.version_info[1]}'.format(sys=sys)
+    tp = 'setuptools-{version}-{py_desig}.egg'
+    egg = os.path.join(to_dir, tp.format(**locals()))
     if not os.path.exists(egg):
         archive = download_setuptools(version, download_base,
-                                      to_dir, download_delay)
+            to_dir, download_delay)
         _build_egg(egg, archive, to_dir)
     sys.path.insert(0, egg)
 
     # Remove previously-imported pkg_resources if present (see
     # https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
     if 'pkg_resources' in sys.modules:
-        del sys.modules['pkg_resources']
+        _unload_pkg_resources()
 
     import setuptools
     setuptools.bootstrap_install_from = egg
@@ -140,6 +147,7 @@ def use_setuptools(
     Return None. Raise SystemExit if the requested version
     or later cannot be installed.
     """
+    version = _resolve_version(version)
     to_dir = os.path.abspath(to_dir)
 
     # prior to importing, capture the module state for
@@ -189,6 +197,11 @@ def _conflict_bail(VC_err, version):
 
 
 def _unload_pkg_resources():
+    sys.meta_path = [
+        importer
+        for importer in sys.meta_path
+        if importer.__class__.__module__ != 'pkg_resources.extern'
+    ]
     del_modules = [
         name for name in sys.modules
         if name.startswith('pkg_resources')
@@ -222,8 +235,8 @@ def download_file_powershell(url, target):
     ps_cmd = (
         "[System.Net.WebRequest]::DefaultWebProxy.Credentials = "
         "[System.Net.CredentialCache]::DefaultCredentials; "
-        "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)"
-        % vars()
+        '(new-object System.Net.WebClient).DownloadFile("%(url)s", "%(target)s")'
+        % locals()
     )
     cmd = [
         'powershell',
@@ -248,7 +261,7 @@ download_file_powershell.viable = has_powershell
 
 
 def download_file_curl(url, target):
-    cmd = ['curl', url, '--silent', '--output', target]
+    cmd = ['curl', url, '--location', '--silent', '--output', target]
     _clean_check(cmd, target)
 
 
@@ -321,6 +334,7 @@ def download_setuptools(
     ``downloader_factory`` should be a function taking no arguments and
     returning a function for downloading a URL to a target.
     """
+    version = _resolve_version(version)
     # making sure we use the absolute path
     to_dir = os.path.abspath(to_dir)
     zip_name = "setuptools-%s.zip" % version
@@ -333,6 +347,27 @@ def download_setuptools(
     return os.path.realpath(saveto)
 
 
+def _resolve_version(version):
+    """
+    Resolve LATEST version
+    """
+    if version is not LATEST:
+        return version
+
+    meta_url = urljoin(DEFAULT_URL, '/pypi/setuptools/json')
+    resp = urlopen(meta_url)
+    with contextlib.closing(resp):
+        try:
+            charset = resp.info().get_content_charset()
+        except Exception:
+            # Python 2 compat; assume UTF-8
+            charset = 'UTF-8'
+        reader = codecs.getreader(charset)
+        doc = json.load(reader(resp))
+
+    return str(doc['info']['version'])
+
+
 def _build_install_args(options):
     """
     Build the arguments to 'python setup.py install' on the setuptools package.
@@ -347,7 +382,7 @@ def _parse_args():
     parser = optparse.OptionParser()
     parser.add_option(
         '--user', dest='user_install', action='store_true', default=False,
-        help='install in user site package (requires Python 2.6 or later)')
+        help='install in user site package')
     parser.add_option(
         '--download-base', dest='download_base', metavar="URL",
         default=DEFAULT_URL,
@@ -362,9 +397,9 @@ def _parse_args():
         default=DEFAULT_VERSION,
     )
     parser.add_option(
-    	'--to-dir',
-    	help="Directory to save (and re-use) package",
-    	default=DEFAULT_SAVE_DIR,
+        '--to-dir',
+        help="Directory to save (and re-use) package",
+        default=DEFAULT_SAVE_DIR,
     )
     options, args = parser.parse_args()
     # positional arguments are ignored
@@ -372,13 +407,13 @@ def _parse_args():
 
 
 def _download_args(options):
-	"""Return args for download_setuptools function from cmdline args."""
-	return dict(
-		version=options.version,
-		download_base=options.download_base,
-		downloader_factory=options.downloader_factory,
-		to_dir=options.to_dir,
-	)
+    """Return args for download_setuptools function from cmdline args."""
+    return dict(
+        version=options.version,
+        download_base=options.download_base,
+        downloader_factory=options.downloader_factory,
+        to_dir=options.to_dir,
+    )
 
 
 def main():
diff --git a/setup.py b/setup.py
index 23bb89b..dd88390 100644
--- a/setup.py
+++ b/setup.py
@@ -135,8 +135,8 @@ except Exception as e:
 extras = {
     'matlab': ["pymatbridge"],
     'sbml': ["python-libsbml", "lxml"],
-    'array': ["numpy>=1.6", "scipy>=11.0"],
-    'display': ["matplotlib", "palettable", "pandas"]
+    'array': ["numpy>=1.6", "scipy>=0.11.0"],
+    'display': ["matplotlib", "palettable", "pandas>=0.17.0"]
 }
 
 all_extras = {'Cython>=0.21'}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/python-cobra.git



More information about the debian-med-commit mailing list