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

Skip to content

Commit 369beee

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 39575ed commit 369beee

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
@@ -174,20 +174,20 @@ Dependencies
174174
Matplotlib requires a large number of dependencies:
175175

176176
* `Python <https://www.python.org/downloads/>`_ (>= 2.7 or >= 3.4)
177-
* `NumPy <http://www.numpy.org>`_ (>= |minimum_numpy_version|)
178-
* `setuptools <https://setuptools.readthedocs.io/en/latest/>`__
177+
* `setuptools <https://setuptools.readthedocs.io/en/latest/>`_
178+
* `NumPy <http://www.numpy.org>`_ (>= 1.7.1)
179+
* `cycler <http://matplotlib.org/cycler/>`_ (>= 0.10.0)
179180
* `dateutil <https://pypi.python.org/pypi/python-dateutil>`_ (>= 2.0)
180-
* `pyparsing <https://pyparsing.wikispaces.com/>`__
181-
* `libpng <http://www.libpng.org>`__ (>= 1.2)
182-
* `pytz <http://pytz.sourceforge.net/>`__
183-
* FreeType (>= 2.3)
184-
* `cycler <http://matplotlib.org/cycler/>`__ (>= 0.10.0)
185-
* `six <https://pypi.python.org/pypi/six>`_
181+
* `pyparsing <https://pyparsing.wikispaces.com/>`_ (>= 2.1.7; some older
182+
versions may work)
183+
* `pytz <http://pytz.sourceforge.net/>`_
184+
* `six <https://pypi.python.org/pypi/six>`_ (>= 1.10)
186185
* `backports.functools_lru_cache <https://pypi.python.org/pypi/backports.functools_lru_cache>`_
187186
(for Python 2.7 only)
188187
* `subprocess32 <https://pypi.python.org/pypi/subprocess32/>`_ (for Python
189188
2.7 only, on Linux and macOS only)
190-
189+
* `FreeType <https://www.freetype.org>`_ (>= 2.3)
190+
* `libpng <http://www.libpng.org>`_ (>= 1.2)
191191

192192
Optionally, you can also install a number of packages to enable better user
193193
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
@@ -328,10 +328,6 @@ def _check_deps():
328328
# documentation
329329
autoclass_content = 'both'
330330

331-
rst_epilog = """
332-
.. |minimum_numpy_version| replace:: %s
333-
""" % matplotlib.__version__numpy__
334-
335331
texinfo_documents = [
336332
("contents", 'matplotlib', 'Matplotlib Documentation',
337333
'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
unicode_literals)
104100

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

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
@@ -119,17 +128,16 @@
119128
import tempfile
120129
import warnings
121130

131+
from six.moves.urllib.request import urlopen
132+
from six.moves import reload_module as reload
133+
122134
# cbook must import matplotlib only within function
123135
# definitions, so it is safe to import from it here.
124136
from . import cbook
125-
from matplotlib.cbook import (
137+
from .cbook import (
126138
_backports, mplDeprecation, dedent, get_label, sanitize_sequence)
127-
from matplotlib.compat import subprocess
128-
from matplotlib.rcsetup import defaultParams, validate_backend, cycler
129-
130-
import numpy
131-
from six.moves.urllib.request import urlopen
132-
from six.moves import reload_module as reload
139+
from .compat import subprocess
140+
from .rcsetup import defaultParams, validate_backend, cycler
133141

134142
# Get the version from the _version.py versioneer file. For a git checkout,
135143
# this is computed based on the number of commits since the last tag.
@@ -169,41 +177,11 @@ def compare_versions(a, b):
169177
a = a.decode('ascii')
170178
if isinstance(b, bytes):
171179
b = b.decode('ascii')
172-
a = distutils.version.LooseVersion(a)
173-
b = distutils.version.LooseVersion(b)
174-
return a >= b
180+
return LooseVersion(a) >= LooseVersion(b)
175181
else:
176182
return False
177183

178184

179-
try:
180-
import dateutil
181-
except ImportError:
182-
raise ImportError("Matplotlib requires dateutil")
183-
184-
185-
if not compare_versions(six.__version__, '1.10'):
186-
raise ImportError(
187-
"Matplotlib requires six>=1.10; you have %s" % six.__version__)
188-
189-
190-
try:
191-
import pyparsing
192-
except ImportError:
193-
raise ImportError("Matplotlib requires pyparsing")
194-
else:
195-
if not compare_versions(pyparsing.__version__, '2.0.1'):
196-
raise ImportError(
197-
"Matplotlib requires pyparsing>=2.0.1; you have %s"
198-
% pyparsing.__version__)
199-
200-
201-
if not compare_versions(numpy.__version__, __version__numpy__):
202-
raise ImportError(
203-
"Matplotlib requires numpy>=%s; you have %s" % (
204-
__version__numpy__, numpy.__version__))
205-
206-
207185
if not hasattr(sys, 'argv'): # for modpython
208186
sys.argv = [str('modpython')]
209187

setupext.py

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

135135

136-
def extract_versions():
137-
"""
138-
Extracts version values from the main matplotlib __init__.py and
139-
returns them as a dictionary.
140-
"""
141-
with open('lib/matplotlib/__init__.py') as fd:
142-
for line in fd.readlines():
143-
if (line.startswith('__version__numpy__')):
144-
exec(line.strip())
145-
return locals()
146-
147-
148136
def has_include_file(include_dirs, filename):
149137
"""
150138
Returns `True` if `filename` can be found in one of the
@@ -966,7 +954,8 @@ def include_dirs_hook():
966954
return [numpy.get_include()]
967955

968956
def check(self):
969-
min_version = extract_versions()['__version__numpy__']
957+
# Remember to keep the version in INSTALL.rst in sync.
958+
min_version = "1.7.1"
970959
try:
971960
import numpy
972961
except ImportError:
@@ -1457,6 +1446,7 @@ def check(self):
14571446
return "handled by setuptools"
14581447

14591448
def get_install_requires(self):
1449+
# Remember to keep the list in INSTALL.rst in sync.
14601450
install_requires = [
14611451
"cycler>=0.10",
14621452
"pyparsing>=2.0.1,!=2.0.4,!=2.1.2,!=2.1.6",

0 commit comments

Comments
 (0)