Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4effa6f

Browse files
committed
Check dependencies at runtime as declared in setup.py.
The goal is to list the requirements exactly once in code (in setupext.py) and once in the docs (in INSTALL.rst). Instead of manually importing and checking that (python) dependencies are installed with the correct versions, rely on pkg_resources, which allows automatically keeping things in sync with setupext, as well as correctly check e.g. the complex version requirements on pyparsing. Remove the overly complex way to specify the minimum numpy version. Add comments reminding to update INSTALL.rst when the requirements are changed in setupext.py; reorder dependencies in INSTALL.rst in a more logical order. Remove unneeded reference to MATLAB being a registered trademark. Note that if you are running Matplotlib from source by manipulating PYTHONPATH, then it will not appear to pkg_resources. In this case, there is no check for other dependencies (you are assumed to be responsible enough for that). Conversely, Matplotlib will fail to import if it is installed into site-packages but some dependency (six, etc.) is only available in PYTHONPATH instead of being correctly installed. I think this is acceptable (or we could just completely drop the import checks and let bad installs fail with normal ImportErrors).
1 parent 4753f6c commit 4effa6f

File tree

4 files changed

+34
-70
lines changed

4 files changed

+34
-70
lines changed

INSTALL.rst

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -168,20 +168,20 @@ Dependencies
168168
Matplotlib requires a large number of dependencies:
169169

170170
* `Python <https://www.python.org/downloads/>`_ (>= 2.7 or >= 3.4)
171-
* `NumPy <http://www.numpy.org>`_ (>= |minimum_numpy_version|)
172-
* `setuptools <https://setuptools.readthedocs.io/en/latest/>`__
171+
* `setuptools <https://setuptools.readthedocs.io/en/latest/>`_
172+
* `NumPy <http://www.numpy.org>`_ (>= 1.7.1)
173+
* `cycler <http://matplotlib.org/cycler/>`_ (>= 0.10.0)
173174
* `dateutil <https://pypi.python.org/pypi/python-dateutil>`_ (>= 2.1)
174-
* `pyparsing <https://pyparsing.wikispaces.com/>`__
175-
* `libpng <http://www.libpng.org>`__ (>= 1.2)
176-
* `pytz <http://pytz.sourceforge.net/>`__
177-
* FreeType (>= 2.3)
178-
* `cycler <http://matplotlib.org/cycler/>`__ (>= 0.10.0)
179-
* `six <https://pypi.python.org/pypi/six>`_
175+
* `pyparsing <https://pyparsing.wikispaces.com/>`_ (>= 2.1.7; some older
176+
versions may work)
177+
* `pytz <http://pytz.sourceforge.net/>`_
178+
* `six <https://pypi.python.org/pypi/six>`_ (>= 1.10)
180179
* `backports.functools_lru_cache <https://pypi.python.org/pypi/backports.functools_lru_cache>`_
181180
(for Python 2.7 only)
182181
* `subprocess32 <https://pypi.python.org/pypi/subprocess32/>`_ (for Python
183182
2.7 only, on Linux and macOS only)
184-
183+
* `FreeType <https://www.freetype.org>`_ (>= 2.3)
184+
* `libpng <http://www.libpng.org>`_ (>= 1.2)
185185

186186
Optionally, you can also install a number of packages to enable better user
187187
interface toolkits. See :ref:`what-is-a-backend` for more details on the

doc/conf.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,6 @@ def _check_deps():
322322
# documentation
323323
autoclass_content = 'both'
324324

325-
rst_epilog = """
326-
.. |minimum_numpy_version| replace:: %s
327-
""" % matplotlib.__version__numpy__
328-
329325
texinfo_documents = [
330326
("contents", 'matplotlib', 'Matplotlib Documentation',
331327
'John Hunter@*Darren Dale@*Eric Firing@*Michael Droettboom@*'

lib/matplotlib/__init__.py

Lines changed: 22 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,29 @@
9494
9595
matplotlib was initially written by John D. Hunter (1968-2012) and is now
9696
developed and maintained by a host of others.
97-
98-
Occasionally the internal documentation (python docstrings) will refer
99-
to MATLAB&reg;, a registered trademark of The MathWorks, Inc.
100-
10197
"""
10298
from __future__ import absolute_import, division, print_function
10399

100+
import pkg_resources
101+
102+
try:
103+
pkg_resources.get_distribution("matplotlib")
104+
except pkg_resources.DistributionNotFound:
105+
# Running from source -- you're on your own.
106+
pass
107+
else:
108+
try:
109+
# Check that dependencies are correctly installed.
110+
pkg_resources.require("matplotlib")
111+
except pkg_resources.ResolutionError as e:
112+
raise ImportError("Matplotlib requires {}".format(e.req))
113+
104114
import six
105115

106116
import atexit
107117
from collections import MutableMapping
108118
import contextlib
109-
import distutils.version
110-
import distutils.sysconfig
119+
from distutils.version import LooseVersion
111120
import functools
112121
import io
113122
import inspect
@@ -122,17 +131,16 @@
122131
import tempfile
123132
import warnings
124133

134+
from six.moves.urllib.request import urlopen
135+
from six.moves import reload_module as reload
136+
125137
# cbook must import matplotlib only within function
126138
# definitions, so it is safe to import from it here.
127139
from . import cbook
128-
from matplotlib.cbook import (
140+
from .cbook import (
129141
_backports, mplDeprecation, dedent, get_label, sanitize_sequence)
130-
from matplotlib.compat import subprocess
131-
from matplotlib.rcsetup import defaultParams, validate_backend, cycler
132-
133-
import numpy
134-
from six.moves.urllib.request import urlopen
135-
from six.moves import reload_module as reload
142+
from .compat import subprocess
143+
from .rcsetup import defaultParams, validate_backend, cycler
136144

137145
# Get the version from the _version.py versioneer file. For a git checkout,
138146
# this is computed based on the number of commits since the last tag.
@@ -177,41 +185,11 @@ def compare_versions(a, b):
177185
a = a.decode('ascii')
178186
if isinstance(b, bytes):
179187
b = b.decode('ascii')
180-
a = distutils.version.LooseVersion(a)
181-
b = distutils.version.LooseVersion(b)
182-
return a >= b
188+
return LooseVersion(a) >= LooseVersion(b)
183189
else:
184190
return False
185191

186192

187-
try:
188-
import dateutil
189-
except ImportError:
190-
raise ImportError("Matplotlib requires dateutil")
191-
192-
193-
if not compare_versions(six.__version__, '1.10'):
194-
raise ImportError(
195-
"Matplotlib requires six>=1.10; you have %s" % six.__version__)
196-
197-
198-
try:
199-
import pyparsing
200-
except ImportError:
201-
raise ImportError("Matplotlib requires pyparsing")
202-
else:
203-
if not compare_versions(pyparsing.__version__, '2.0.1'):
204-
raise ImportError(
205-
"Matplotlib requires pyparsing>=2.0.1; you have %s"
206-
% pyparsing.__version__)
207-
208-
209-
if not compare_versions(numpy.__version__, __version__numpy__):
210-
raise ImportError(
211-
"Matplotlib requires numpy>=%s; you have %s" % (
212-
__version__numpy__, numpy.__version__))
213-
214-
215193
if not hasattr(sys, 'argv'): # for modpython
216194
sys.argv = [str('modpython')]
217195

setupext.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,18 +119,6 @@ def get_win32_compiler():
119119
win32_compiler = get_win32_compiler()
120120

121121

122-
def extract_versions():
123-
"""
124-
Extracts version values from the main matplotlib __init__.py and
125-
returns them as a dictionary.
126-
"""
127-
with open('lib/matplotlib/__init__.py') as fd:
128-
for line in fd.readlines():
129-
if (line.startswith('__version__numpy__')):
130-
exec(line.strip())
131-
return locals()
132-
133-
134122
def has_include_file(include_dirs, filename):
135123
"""
136124
Returns `True` if `filename` can be found in one of the
@@ -958,7 +946,8 @@ def include_dirs_hook():
958946
return [numpy.get_include()]
959947

960948
def check(self):
961-
min_version = extract_versions()['__version__numpy__']
949+
# Remember to keep the version in INSTALL.rst in sync.
950+
min_version = "1.7.1"
962951
try:
963952
import numpy
964953
except ImportError:
@@ -1429,6 +1418,7 @@ def check(self):
14291418
return "handled by setuptools"
14301419

14311420
def get_install_requires(self):
1421+
# Remember to keep the list in INSTALL.rst in sync.
14321422
install_requires = [
14331423
"cycler>=0.10",
14341424
"pyparsing>=2.0.1,!=2.0.4,!=2.1.2,!=2.1.6",

0 commit comments

Comments
 (0)