diff options
Diffstat (limited to 'libraries/matplotlib/setupext.py')
-rw-r--r-- | libraries/matplotlib/setupext.py | 2158 |
1 files changed, 0 insertions, 2158 deletions
diff --git a/libraries/matplotlib/setupext.py b/libraries/matplotlib/setupext.py deleted file mode 100644 index 68ab368443..0000000000 --- a/libraries/matplotlib/setupext.py +++ /dev/null @@ -1,2158 +0,0 @@ -from __future__ import print_function, absolute_import - -from importlib import import_module - -from distutils import sysconfig -from distutils import version -from distutils.core import Extension -import distutils.command.build_ext -import glob -import multiprocessing -import os -import platform -import re -import subprocess -from subprocess import check_output -import sys -import warnings -from textwrap import fill -import shutil -import versioneer - - -PY3min = (sys.version_info[0] >= 3) - - -def _get_xdg_cache_dir(): - """ - Return the XDG cache directory. - - See https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - """ - cache_dir = os.environ.get('XDG_CACHE_HOME') - if not cache_dir: - cache_dir = os.path.expanduser('~/.cache') - if cache_dir.startswith('~/'): # Expansion failed. - return None - return os.path.join(cache_dir, 'matplotlib') - - -# SHA256 hashes of the FreeType tarballs -_freetype_hashes = { - '2.6.1': '0a3c7dfbda6da1e8fce29232e8e96d987ababbbf71ebc8c75659e4132c367014', - '2.6.2': '8da42fc4904e600be4b692555ae1dcbf532897da9c5b9fb5ebd3758c77e5c2d4', - '2.6.3': '7942096c40ee6fea882bd4207667ad3f24bff568b96b10fd3885e11a7baad9a3', - '2.6.4': '27f0e38347a1850ad57f84fc4dfed68ba0bc30c96a6fa6138ef84d485dd9a8d7', - '2.6.5': '3bb24add9b9ec53636a63ea8e867ed978c4f8fdd8f1fa5ccfd41171163d4249a', - '2.7': '7b657d5f872b0ab56461f3bd310bd1c5ec64619bd15f0d8e08282d494d9cfea4', - '2.7.1': '162ef25aa64480b1189cdb261228e6c5c44f212aac4b4621e28cf2157efb59f5', - '2.8': '33a28fabac471891d0523033e99c0005b95e5618dc8ffa7fa47f9dadcacb1c9b', - '2.8.1': '876711d064a6a1bd74beb18dd37f219af26100f72daaebd2d86cb493d7cd7ec6', -} -# This is the version of FreeType to use when building a local -# version. It must match the value in -# lib/matplotlib.__init__.py and also needs to be changed below in the -# embedded windows build script (grep for "REMINDER" in this file) -LOCAL_FREETYPE_VERSION = '2.6.1' -LOCAL_FREETYPE_HASH = _freetype_hashes.get(LOCAL_FREETYPE_VERSION, 'unknown') - -if sys.platform != 'win32': - if not PY3min: - from commands import getstatusoutput - else: - from subprocess import getstatusoutput - - -if PY3min: - import configparser -else: - import ConfigParser as configparser - - -# matplotlib build options, which can be altered using setup.cfg -options = { - 'display_status': True, - 'verbose': False, - 'backend': None, - 'basedirlist': None - } - - -setup_cfg = os.environ.get('MPLSETUPCFG', 'setup.cfg') -if os.path.exists(setup_cfg): - if PY3min: - config = configparser.ConfigParser() - else: - config = configparser.SafeConfigParser() - config.read(setup_cfg) - - if config.has_option('status', 'suppress'): - options['display_status'] = not config.getboolean("status", "suppress") - - if config.has_option('rc_options', 'backend'): - options['backend'] = config.get("rc_options", "backend") - - if config.has_option('directories', 'basedirlist'): - options['basedirlist'] = [ - x.strip() for x in - config.get("directories", "basedirlist").split(',')] - - if config.has_option('test', 'local_freetype'): - options['local_freetype'] = config.getboolean("test", "local_freetype") -else: - config = None - -lft = bool(os.environ.get('MPLLOCALFREETYPE', False)) -options['local_freetype'] = lft or options.get('local_freetype', False) - - -def get_win32_compiler(): - """ - Determine the compiler being used on win32. - """ - # Used to determine mingw32 or msvc - # This is pretty bad logic, someone know a better way? - for v in sys.argv: - if 'mingw32' in v: - return 'mingw32' - return 'msvc' -win32_compiler = get_win32_compiler() - - -def extract_versions(): - """ - Extracts version values from the main matplotlib __init__.py and - returns them as a dictionary. - """ - with open('lib/matplotlib/__init__.py') as fd: - for line in fd.readlines(): - if (line.startswith('__version__numpy__')): - exec(line.strip()) - return locals() - - -def has_include_file(include_dirs, filename): - """ - Returns `True` if `filename` can be found in one of the - directories in `include_dirs`. - """ - if sys.platform == 'win32': - include_dirs = list(include_dirs) # copy before modify - include_dirs += os.environ.get('INCLUDE', '.').split(os.pathsep) - for dir in include_dirs: - if os.path.exists(os.path.join(dir, filename)): - return True - return False - - -def check_include_file(include_dirs, filename, package): - """ - Raises an exception if the given include file can not be found. - """ - if not has_include_file(include_dirs, filename): - raise CheckFailed( - "The C/C++ header for %s (%s) could not be found. You " - "may need to install the development package." % - (package, filename)) - - -def get_base_dirs(): - """ - Returns a list of standard base directories on this platform. - """ - if options['basedirlist']: - return options['basedirlist'] - - if os.environ.get('MPLBASEDIRLIST'): - return os.environ.get('MPLBASEDIRLIST').split(os.pathsep) - - win_bases = ['win32_static', ] - # on conda windows, we also add the <conda_env_dir>\Library, - # as conda installs libs/includes there - # env var names mess: https://github.com/conda/conda/issues/2312 - conda_env_path = os.getenv('CONDA_PREFIX') # conda >= 4.1 - if not conda_env_path: - conda_env_path = os.getenv('CONDA_DEFAULT_ENV') # conda < 4.1 - if conda_env_path and os.path.isdir(conda_env_path): - win_bases.append(os.path.join(conda_env_path, "Library")) - - basedir_map = { - 'win32': win_bases, - 'darwin': ['/usr/local/', '/usr', '/usr/X11', - '/opt/X11', '/opt/local'], - 'sunos5': [os.getenv('MPLIB_BASE') or '/usr/local', ], - 'gnu0': ['/usr'], - 'aix5': ['/usr/local'], - } - return basedir_map.get(sys.platform, ['/usr/local', '/usr']) - - -def get_include_dirs(): - """ - Returns a list of standard include directories on this platform. - """ - include_dirs = [os.path.join(d, 'include') for d in get_base_dirs()] - if sys.platform != 'win32': - # gcc includes this dir automatically, so also look for headers in - # these dirs - include_dirs.extend( - os.environ.get('CPLUS_INCLUDE_PATH', '').split(os.pathsep)) - return include_dirs - - -def is_min_version(found, minversion): - """ - Returns `True` if `found` is at least as high a version as - `minversion`. - """ - expected_version = version.LooseVersion(minversion) - found_version = version.LooseVersion(found) - return found_version >= expected_version - - -# Define the display functions only if display_status is True. -if options['display_status']: - def print_line(char='='): - print(char * 76) - - def print_status(package, status): - initial_indent = "%22s: " % package - indent = ' ' * 24 - print(fill(str(status), width=76, - initial_indent=initial_indent, - subsequent_indent=indent)) - - def print_message(message): - indent = ' ' * 24 + "* " - print(fill(str(message), width=76, - initial_indent=indent, - subsequent_indent=indent)) - - def print_raw(section): - print(section) -else: - def print_line(*args, **kwargs): - pass - print_status = print_message = print_raw = print_line - - -# Remove the -Wstrict-prototypes option, is it's not valid for C++ -customize_compiler = distutils.command.build_ext.customize_compiler - - -def my_customize_compiler(compiler): - retval = customize_compiler(compiler) - try: - compiler.compiler_so.remove('-Wstrict-prototypes') - except (ValueError, AttributeError): - pass - return retval - -distutils.command.build_ext.customize_compiler = my_customize_compiler - - -def make_extension(name, files, *args, **kwargs): - """ - Make a new extension. Automatically sets include_dirs and - library_dirs to the base directories appropriate for this - platform. - - `name` is the name of the extension. - - `files` is a list of source files. - - Any additional arguments are passed to the - `distutils.core.Extension` constructor. - """ - ext = DelayedExtension(name, files, *args, **kwargs) - for dir in get_base_dirs(): - include_dir = os.path.join(dir, 'include') - if os.path.exists(include_dir): - ext.include_dirs.append(include_dir) - for lib in ('lib', 'lib64'): - lib_dir = os.path.join(dir, lib) - if os.path.exists(lib_dir): - ext.library_dirs.append(lib_dir) - ext.include_dirs.append('.') - - return ext - - -def get_file_hash(filename): - """ - Get the SHA256 hash of a given filename. - """ - import hashlib - BLOCKSIZE = 1 << 16 - hasher = hashlib.sha256() - with open(filename, 'rb') as fd: - buf = fd.read(BLOCKSIZE) - while len(buf) > 0: - hasher.update(buf) - buf = fd.read(BLOCKSIZE) - return hasher.hexdigest() - - -class PkgConfig(object): - """ - This is a class for communicating with pkg-config. - """ - def __init__(self): - """ - Determines whether pkg-config exists on this machine. - """ - if sys.platform == 'win32': - self.has_pkgconfig = False - else: - try: - self.pkg_config = os.environ['PKG_CONFIG'] - except KeyError: - self.pkg_config = 'pkg-config' - - self.set_pkgconfig_path() - status, output = getstatusoutput(self.pkg_config + " --help") - self.has_pkgconfig = (status == 0) - if not self.has_pkgconfig: - print("IMPORTANT WARNING:") - print( - " pkg-config is not installed.\n" - " matplotlib may not be able to find some of its dependencies") - - def set_pkgconfig_path(self): - pkgconfig_path = sysconfig.get_config_var('LIBDIR') - if pkgconfig_path is None: - return - - pkgconfig_path = os.path.join(pkgconfig_path, 'pkgconfig') - if not os.path.isdir(pkgconfig_path): - return - - try: - os.environ['PKG_CONFIG_PATH'] += ':' + pkgconfig_path - except KeyError: - os.environ['PKG_CONFIG_PATH'] = pkgconfig_path - - def setup_extension(self, ext, package, default_include_dirs=[], - default_library_dirs=[], default_libraries=[], - alt_exec=None): - """ - Add parameters to the given `ext` for the given `package`. - """ - flag_map = { - '-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} - - executable = alt_exec - if self.has_pkgconfig: - executable = (self.pkg_config + ' {0}').format(package) - - use_defaults = True - - if executable is not None: - command = "{0} --libs --cflags ".format(executable) - - try: - output = check_output(command, shell=True, - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError: - pass - else: - output = output.decode(sys.getfilesystemencoding()) - use_defaults = False - for token in output.split(): - attr = flag_map.get(token[:2]) - if attr is not None: - getattr(ext, attr).insert(0, token[2:]) - - if use_defaults: - basedirs = get_base_dirs() - for base in basedirs: - for include in default_include_dirs: - dir = os.path.join(base, include) - if os.path.exists(dir): - ext.include_dirs.append(dir) - for lib in default_library_dirs: - dir = os.path.join(base, lib) - if os.path.exists(dir): - ext.library_dirs.append(dir) - ext.libraries.extend(default_libraries) - return True - - return False - - def get_version(self, package): - """ - Get the version of the package from pkg-config. - """ - if not self.has_pkgconfig: - return None - - status, output = getstatusoutput( - self.pkg_config + " %s --modversion" % (package)) - if status == 0: - return output - return None - - -# The PkgConfig class should be used through this singleton -pkg_config = PkgConfig() - - -class CheckFailed(Exception): - """ - Exception thrown when a `SetupPackage.check` method fails. - """ - pass - - -class SetupPackage(object): - optional = False - pkg_names = { - "apt-get": None, - "yum": None, - "dnf": None, - "brew": None, - "port": None, - "windows_url": None - } - - def check(self): - """ - Checks whether the build dependencies are met. Should raise a - `CheckFailed` exception if the dependency could not be met, otherwise - return a string indicating a version number or some other message - indicating what was found. - """ - pass - - def runtime_check(self): - """ - True if the runtime dependencies of the backend are met. Assumes that - the build-time dependencies are met. - """ - return True - - def get_packages(self): - """ - Get a list of package names to add to the configuration. - These are added to the `packages` list passed to - `distutils.setup`. - """ - return [] - - def get_namespace_packages(self): - """ - Get a list of namespace package names to add to the configuration. - These are added to the `namespace_packages` list passed to - `distutils.setup`. - """ - return [] - - def get_py_modules(self): - """ - Get a list of top-level modules to add to the configuration. - These are added to the `py_modules` list passed to - `distutils.setup`. - """ - return [] - - def get_package_data(self): - """ - Get a package data dictionary to add to the configuration. - These are merged into to the `package_data` list passed to - `distutils.setup`. - """ - return {} - - def get_extension(self): - """ - Get a list of C extensions (`distutils.core.Extension` - objects) to add to the configuration. These are added to the - `extensions` list passed to `distutils.setup`. - """ - return None - - def get_install_requires(self): - """ - Get a list of Python packages that we require. - pip/easy_install will attempt to download and install this - package if it is not installed. - """ - return [] - - def get_setup_requires(self): - """ - Get a list of Python packages that we require at build time. - pip/easy_install will attempt to download and install this - package if it is not installed. - """ - return [] - - def _check_for_pkg_config(self, package, include_file, min_version=None, - version=None): - """ - A convenience function for writing checks for a - pkg_config-defined dependency. - - `package` is the pkg_config package name. - - `include_file` is a top-level include file we expect to find. - - `min_version` is the minimum version required. - - `version` will override the found version if this package - requires an alternate method for that. Set version='unknown' - if the version is not known but you still want to disabled - pkg_config version check. - """ - if version is None: - version = pkg_config.get_version(package) - - if version is None: - raise CheckFailed( - "pkg-config information for '%s' could not be found." % - package) - - if min_version == 'PATCH': - raise CheckFailed( - "Requires patches that have not been merged upstream.") - - if min_version and version != 'unknown': - if (not is_min_version(version, min_version)): - raise CheckFailed( - "Requires %s %s or later. Found %s." % - (package, min_version, version)) - - ext = self.get_extension() - if ext is None: - ext = make_extension('test', []) - pkg_config.setup_extension(ext, package) - - check_include_file( - ext.include_dirs + get_include_dirs(), include_file, package) - - return 'version %s' % version - - def do_custom_build(self): - """ - If a package needs to do extra custom things, such as building a - third-party library, before building an extension, it should - override this method. - """ - pass - - def install_help_msg(self): - """ - Do not override this method ! - - Generate the help message to show if the package is not installed. - To use this in subclasses, simply add the dictionary `pkg_names` as - a class variable: - - pkg_names = { - "apt-get": <Name of the apt-get package>, - "yum": <Name of the yum package>, - "dnf": <Name of the dnf package>, - "brew": <Name of the brew package>, - "port": <Name of the port package>, - "windows_url": <The url which has installation instructions> - } - - All the dictionary keys are optional. If a key is not present or has - the value `None` no message is provided for that platform. - """ - def _try_managers(*managers): - for manager in managers: - pkg_name = self.pkg_names.get(manager, None) - if pkg_name: - try: - # `shutil.which()` can be used when Python 2.7 support - # is dropped. It is available in Python 3.3+ - _ = check_output(["which", manager], - stderr=subprocess.STDOUT) - if manager == 'port': - pkgconfig = 'pkgconfig' - else: - pkgconfig = 'pkg-config' - return ('Try installing {0} with `{1} install {2}` ' - 'and pkg-config with `{1} install {3}`' - .format(self.name, manager, pkg_name, - pkgconfig)) - except subprocess.CalledProcessError: - pass - - message = None - if sys.platform == "win32": - url = self.pkg_names.get("windows_url", None) - if url: - message = ('Please check {0} for instructions to install {1}' - .format(url, self.name)) - elif sys.platform == "darwin": - message = _try_managers("brew", "port") - elif sys.platform.startswith("linux"): - release = platform.linux_distribution()[0].lower() - if release in ('debian', 'ubuntu'): - message = _try_managers('apt-get') - elif release in ('centos', 'redhat', 'fedora'): - message = _try_managers('dnf', 'yum') - return message - - -class OptionalPackage(SetupPackage): - optional = True - force = False - config_category = "packages" - default_config = "auto" - - @classmethod - def get_config(cls): - """ - Look at `setup.cfg` and return one of ["auto", True, False] indicating - if the package is at default state ("auto"), forced by the user (case - insensitively defined as 1, true, yes, on for True) or opted-out (case - insensitively defined as 0, false, no, off for False). - """ - conf = cls.default_config - if config is not None and config.has_option(cls.config_category, cls.name): - try: - conf = config.getboolean(cls.config_category, cls.name) - except ValueError: - conf = config.get(cls.config_category, cls.name) - return conf - - def check(self): - """ - Do not override this method! - - For custom dependency checks override self.check_requirements(). - Two things are checked: Configuration file and requirements. - """ - # Check configuration file - conf = self.get_config() - # Default "auto" state or install forced by user - if conf in [True, 'auto']: - message = "installing" - # Set non-optional if user sets `True` in config - if conf is True: - self.optional = False - # Configuration opt-out by user - else: - # Some backend extensions (e.g. Agg) need to be built for certain - # other GUI backends (e.g. TkAgg) even when manually disabled - if self.force is True: - message = "installing forced (config override)" - else: - raise CheckFailed("skipping due to configuration") - - # Check requirements and add extra information (if any) to message. - # If requirements are not met a CheckFailed should be raised in there. - additional_info = self.check_requirements() - if additional_info: - message += ", " + additional_info - - # No CheckFailed raised until now, return install message. - return message - - def check_requirements(self): - """ - Override this method to do custom dependency checks. - - - Raise CheckFailed() if requirements are not met. - - Return message with additional information, or an empty string - (or None) for no additional information. - """ - return "" - - -class OptionalBackendPackage(OptionalPackage): - config_category = "gui_support" - - -class Platform(SetupPackage): - name = "platform" - - def check(self): - return sys.platform - - -class Python(SetupPackage): - name = "python" - - def check(self): - major, minor1, minor2, s, tmp = sys.version_info - - if major < 2: - raise CheckFailed( - "Requires Python 2.7 or later") - elif major == 2 and minor1 < 7: - raise CheckFailed( - "Requires Python 2.7 or later (in the 2.x series)") - elif major == 3 and minor1 < 4: - raise CheckFailed( - "Requires Python 3.4 or later (in the 3.x series)") - - return sys.version - - -class Matplotlib(SetupPackage): - name = "matplotlib" - - def check(self): - return versioneer.get_version() - - def get_packages(self): - return [ - 'matplotlib', - 'matplotlib.backends', - 'matplotlib.backends.qt_editor', - 'matplotlib.compat', - 'matplotlib.projections', - 'matplotlib.axes', - 'matplotlib.sphinxext', - 'matplotlib.style', - 'matplotlib.testing', - 'matplotlib.testing._nose', - 'matplotlib.testing._nose.plugins', - 'matplotlib.testing.jpl_units', - 'matplotlib.tri', - 'matplotlib.cbook' - ] - - def get_py_modules(self): - return ['pylab'] - - def get_package_data(self): - return { - 'matplotlib': - [ - 'mpl-data/fonts/afm/*.afm', - 'mpl-data/fonts/pdfcorefonts/*.afm', - 'mpl-data/fonts/pdfcorefonts/*.txt', - 'mpl-data/fonts/ttf/*.ttf', - 'mpl-data/fonts/ttf/LICENSE_STIX', - 'mpl-data/fonts/ttf/COPYRIGHT.TXT', - 'mpl-data/fonts/ttf/README.TXT', - 'mpl-data/fonts/ttf/RELEASENOTES.TXT', - 'mpl-data/images/*.xpm', - 'mpl-data/images/*.svg', - 'mpl-data/images/*.gif', - 'mpl-data/images/*.pdf', - 'mpl-data/images/*.png', - 'mpl-data/images/*.ppm', - 'mpl-data/example/*.npy', - 'mpl-data/matplotlibrc', - 'backends/web_backend/*.*', - 'backends/web_backend/js/*.*', - 'backends/web_backend/jquery/js/*.min.js', - 'backends/web_backend/jquery/css/themes/base/*.min.css', - 'backends/web_backend/jquery/css/themes/base/images/*', - 'backends/web_backend/css/*.*', - 'backends/Matplotlib.nib/*', - 'mpl-data/stylelib/*.mplstyle', - ]} - - -class SampleData(OptionalPackage): - """ - This handles the sample data that ships with matplotlib. It is - technically optional, though most often will be desired. - """ - name = "sample_data" - - def get_package_data(self): - return { - 'matplotlib': - [ - 'mpl-data/sample_data/*.*', - 'mpl-data/sample_data/axes_grid/*.*', - ]} - - -class Toolkits(OptionalPackage): - name = "toolkits" - - def get_packages(self): - return [ - 'mpl_toolkits', - 'mpl_toolkits.mplot3d', - 'mpl_toolkits.axes_grid', - 'mpl_toolkits.axes_grid1', - 'mpl_toolkits.axisartist', - ] - - def get_namespace_packages(self): - return ['mpl_toolkits'] - - -class Tests(OptionalPackage): - name = "tests" - pytest_min_version = '3.1' - default_config = False - - def check(self): - super(Tests, self).check() - - msgs = [] - msg_template = ('{package} is required to run the Matplotlib test ' - 'suite. Please install it with pip or your preferred ' - 'tool to run the test suite') - - bad_pytest = msg_template.format( - package='pytest %s or later' % self.pytest_min_version - ) - try: - import pytest - if is_min_version(pytest.__version__, self.pytest_min_version): - msgs += ['using pytest version %s' % pytest.__version__] - else: - msgs += [bad_pytest] - except ImportError: - msgs += [bad_pytest] - - if PY3min: - msgs += ['using unittest.mock'] - else: - try: - import mock - msgs += ['using mock %s' % mock.__version__] - except ImportError: - msgs += [msg_template.format(package='mock')] - - return ' / '.join(msgs) - - def get_packages(self): - return [ - 'matplotlib.tests', - 'matplotlib.sphinxext.tests', - ] - - def get_package_data(self): - baseline_images = [ - 'tests/baseline_images/%s/*' % x - for x in os.listdir('lib/matplotlib/tests/baseline_images')] - - return { - 'matplotlib': - baseline_images + - [ - 'tests/cmr10.pfb', - 'tests/mpltest.ttf', - 'tests/test_rcparams.rc', - 'tests/test_utf32_be_rcparams.rc', - 'sphinxext/tests/tinypages/*.rst', - 'sphinxext/tests/tinypages/*.py', - 'sphinxext/tests/tinypages/_static/*', - ]} - - -class Toolkits_Tests(Tests): - name = "toolkits_tests" - - def check_requirements(self): - conf = self.get_config() - toolkits_conf = Toolkits.get_config() - tests_conf = Tests.get_config() - - if conf is True: - Tests.force = True - Toolkits.force = True - elif conf == "auto" and not (toolkits_conf and tests_conf): - # Only auto-install if both toolkits and tests are set - # to be installed - raise CheckFailed("toolkits_tests needs 'toolkits' and 'tests'") - return "" - - def get_packages(self): - return [ - 'mpl_toolkits.tests', - ] - - def get_package_data(self): - baseline_images = [ - 'tests/baseline_images/%s/*' % x - for x in os.listdir('lib/mpl_toolkits/tests/baseline_images')] - - return {'mpl_toolkits': baseline_images} - - def get_namespace_packages(self): - return ['mpl_toolkits'] - - -class DelayedExtension(Extension, object): - """ - A distutils Extension subclass where some of its members - may have delayed computation until reaching the build phase. - - This is so we can, for example, get the Numpy include dirs - after pip has installed Numpy for us if it wasn't already - on the system. - """ - def __init__(self, *args, **kwargs): - super(DelayedExtension, self).__init__(*args, **kwargs) - self._finalized = False - self._hooks = {} - - def add_hook(self, member, func): - """ - Add a hook to dynamically compute a member. - - Parameters - ---------- - member : string - The name of the member - - func : callable - The function to call to get dynamically-computed values - for the member. - """ - self._hooks[member] = func - - def finalize(self): - self._finalized = True - - class DelayedMember(property): - def __init__(self, name): - self._name = name - - def __get__(self, obj, objtype=None): - result = getattr(obj, '_' + self._name, []) - - if obj._finalized: - if self._name in obj._hooks: - result = obj._hooks[self._name]() + result - - return result - - def __set__(self, obj, value): - setattr(obj, '_' + self._name, value) - - include_dirs = DelayedMember('include_dirs') - - -class Numpy(SetupPackage): - name = "numpy" - - @staticmethod - def include_dirs_hook(): - if PY3min: - import builtins - if hasattr(builtins, '__NUMPY_SETUP__'): - del builtins.__NUMPY_SETUP__ - import imp - import numpy - imp.reload(numpy) - else: - import __builtin__ - if hasattr(__builtin__, '__NUMPY_SETUP__'): - del __builtin__.__NUMPY_SETUP__ - import numpy - reload(numpy) - - ext = Extension('test', []) - ext.include_dirs.append(numpy.get_include()) - if not has_include_file( - ext.include_dirs, os.path.join("numpy", "arrayobject.h")): - warnings.warn( - "The C headers for numpy could not be found. " - "You may need to install the development package") - - return [numpy.get_include()] - - def check(self): - min_version = extract_versions()['__version__numpy__'] - try: - import numpy - except ImportError: - return 'not found. pip may install it below.' - - if not is_min_version(numpy.__version__, min_version): - raise SystemExit( - "Requires numpy %s or later to build. (Found %s)" % - (min_version, numpy.__version__)) - - return 'version %s' % numpy.__version__ - - def add_flags(self, ext): - # Ensure that PY_ARRAY_UNIQUE_SYMBOL is uniquely defined for - # each extension - array_api_name = 'MPL_' + ext.name.replace('.', '_') + '_ARRAY_API' - - ext.define_macros.append(('PY_ARRAY_UNIQUE_SYMBOL', array_api_name)) - ext.add_hook('include_dirs', self.include_dirs_hook) - - ext.define_macros.append(('NPY_NO_DEPRECATED_API', - 'NPY_1_7_API_VERSION')) - - # Allow NumPy's printf format specifiers in C++. - ext.define_macros.append(('__STDC_FORMAT_MACROS', 1)) - - def get_setup_requires(self): - return ['numpy>=1.7.1'] - - def get_install_requires(self): - return ['numpy>=1.7.1'] - - -class LibAgg(SetupPackage): - name = 'libagg' - - def check(self): - self.__class__.found_external = True - try: - return self._check_for_pkg_config( - 'libagg', 'agg2/agg_basics.h', min_version='PATCH') - except CheckFailed as e: - self.__class__.found_external = False - return str(e) + ' Using local copy.' - - def add_flags(self, ext, add_sources=True): - if self.found_external: - pkg_config.setup_extension(ext, 'libagg') - else: - ext.include_dirs.insert(0, 'extern/agg24-svn/include') - if add_sources: - agg_sources = [ - 'agg_bezier_arc.cpp', - 'agg_curves.cpp', - 'agg_image_filters.cpp', - 'agg_trans_affine.cpp', - 'agg_vcgen_contour.cpp', - 'agg_vcgen_dash.cpp', - 'agg_vcgen_stroke.cpp', - 'agg_vpgen_segmentator.cpp' - ] - ext.sources.extend( - os.path.join('extern', 'agg24-svn', 'src', x) for x in agg_sources) - - -class FreeType(SetupPackage): - name = "freetype" - pkg_names = { - "apt-get": "libfreetype6-dev", - "yum": "freetype-devel", - "dnf": "freetype-devel", - "brew": "freetype", - "port": "freetype", - "windows_url": "http://gnuwin32.sourceforge.net/packages/freetype.htm" - } - - def check(self): - if options.get('local_freetype'): - return "Using local version for testing" - - if sys.platform == 'win32': - try: - check_include_file(get_include_dirs(), 'ft2build.h', 'freetype') - except CheckFailed: - check_include_file(get_include_dirs(), 'freetype2\\ft2build.h', 'freetype') - return 'Using unknown version found on system.' - - status, output = getstatusoutput("freetype-config --ftversion") - if status == 0: - version = output - else: - version = None - - # Early versions of freetype grep badly inside freetype-config, - # so catch those cases. (tested with 2.5.3). - if version is None or 'No such file or directory\ngrep:' in version: - version = self.version_from_header() - - # pkg_config returns the libtool version rather than the - # freetype version so we need to explicitly pass the version - # to _check_for_pkg_config - return self._check_for_pkg_config( - 'freetype2', 'ft2build.h', - min_version='2.3', version=version) - - def version_from_header(self): - version = 'unknown' - ext = self.get_extension() - if ext is None: - return version - # Return the first version found in the include dirs. - for include_dir in ext.include_dirs: - header_fname = os.path.join(include_dir, 'freetype.h') - if os.path.exists(header_fname): - major, minor, patch = 0, 0, 0 - with open(header_fname, 'r') as fh: - for line in fh: - if line.startswith('#define FREETYPE_'): - value = line.rsplit(' ', 1)[1].strip() - if 'MAJOR' in line: - major = value - elif 'MINOR' in line: - minor = value - else: - patch = value - return '.'.join([major, minor, patch]) - - def add_flags(self, ext): - if options.get('local_freetype'): - src_path = os.path.join( - 'build', 'freetype-{0}'.format(LOCAL_FREETYPE_VERSION)) - # Statically link to the locally-built freetype. - # This is certainly broken on Windows. - ext.include_dirs.insert(0, os.path.join(src_path, 'include')) - if sys.platform == 'win32': - libfreetype = 'libfreetype.lib' - else: - libfreetype = 'libfreetype.a' - ext.extra_objects.insert( - 0, os.path.join(src_path, 'objs', '.libs', libfreetype)) - ext.define_macros.append(('FREETYPE_BUILD_TYPE', 'local')) - else: - pkg_config.setup_extension( - ext, 'freetype2', - default_include_dirs=[ - 'include/freetype2', 'freetype2', - 'lib/freetype2/include', - 'lib/freetype2/include/freetype2'], - default_library_dirs=[ - 'freetype2/lib'], - default_libraries=['freetype', 'z']) - ext.define_macros.append(('FREETYPE_BUILD_TYPE', 'system')) - - def do_custom_build(self): - # We're using a system freetype - if not options.get('local_freetype'): - return - - src_path = os.path.join( - 'build', 'freetype-{0}'.format(LOCAL_FREETYPE_VERSION)) - - # We've already built freetype - if sys.platform == 'win32': - libfreetype = 'libfreetype.lib' - else: - libfreetype = 'libfreetype.a' - - if os.path.isfile(os.path.join(src_path, 'objs', '.libs', libfreetype)): - return - - tarball = 'freetype-{0}.tar.gz'.format(LOCAL_FREETYPE_VERSION) - tarball_path = os.path.join('build', tarball) - try: - tarball_cache_dir = _get_xdg_cache_dir() - tarball_cache_path = os.path.join(tarball_cache_dir, tarball) - except: - # again, do not really care if this fails - tarball_cache_dir = None - tarball_cache_path = None - if not os.path.isfile(tarball_path): - if (tarball_cache_path is not None and - os.path.isfile(tarball_cache_path)): - if get_file_hash(tarball_cache_path) == LOCAL_FREETYPE_HASH: - try: - os.makedirs('build') - except OSError: - # Don't care if it exists. - pass - try: - shutil.copy(tarball_cache_path, tarball_path) - print('Using cached tarball: {}' - .format(tarball_cache_path)) - except OSError: - # If this fails, oh well just re-download - pass - - if not os.path.isfile(tarball_path): - if PY3min: - from urllib.request import urlretrieve - else: - from urllib import urlretrieve - - if not os.path.exists('build'): - os.makedirs('build') - - url_fmts = [ - 'https://downloads.sourceforge.net/project/freetype' - '/freetype2/{version}/{tarball}', - 'https://download.savannah.gnu.org/releases/freetype' - '/{tarball}' - ] - for url_fmt in url_fmts: - tarball_url = url_fmt.format( - version=LOCAL_FREETYPE_VERSION, tarball=tarball) - - print("Downloading {0}".format(tarball_url)) - try: - urlretrieve(tarball_url, tarball_path) - except IOError: # URLError (a subclass) on Py3. - print("Failed to download {0}".format(tarball_url)) - else: - if get_file_hash(tarball_path) != LOCAL_FREETYPE_HASH: - print("Invalid hash.") - else: - break - else: - raise IOError("Failed to download freetype. " - "You can download the file by " - "alternative means and copy it " - " to '{0}'".format(tarball_path)) - try: - os.makedirs(tarball_cache_dir) - except OSError: - # Don't care if it exists. - pass - try: - shutil.copy(tarball_path, tarball_cache_path) - print('Cached tarball at: {}'.format(tarball_cache_path)) - except OSError: - # If this fails, we can always re-download. - pass - - if get_file_hash(tarball_path) != LOCAL_FREETYPE_HASH: - raise IOError( - "{0} does not match expected hash.".format(tarball)) - - print("Building {0}".format(tarball)) - if sys.platform != 'win32': - # compilation on all other platforms than windows - cflags = 'CFLAGS="{0} -fPIC" '.format(os.environ.get('CFLAGS', '')) - - subprocess.check_call( - ['tar', 'zxf', tarball], cwd='build') - subprocess.check_call( - [cflags + './configure --with-zlib=no --with-bzip2=no ' - '--with-png=no --with-harfbuzz=no'], shell=True, cwd=src_path) - subprocess.check_call( - [cflags + 'make'], shell=True, cwd=src_path) - else: - # compilation on windows - FREETYPE_BUILD_CMD = """\ -call "%ProgramFiles%\\Microsoft SDKs\\Windows\\v7.0\\Bin\\SetEnv.Cmd" /Release /{xXX} /xp -call "{vcvarsall}" {xXX} -set MSBUILD=C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe -rd /S /Q %FREETYPE%\\objs -%MSBUILD% %FREETYPE%\\builds\\windows\\{vc20xx}\\freetype.sln /t:Clean;Build /p:Configuration="{config}";Platform={WinXX} -echo Build completed, moving result" -:: move to the "normal" path for the unix builds... -mkdir %FREETYPE%\\objs\\.libs -:: REMINDER: fix when changing the version -copy %FREETYPE%\\objs\\{vc20xx}\\{xXX}\\freetype261.lib %FREETYPE%\\objs\\.libs\\libfreetype.lib -if errorlevel 1 ( - rem This is a py27 version, which has a different location for the lib file :-/ - copy %FREETYPE%\\objs\\win32\\{vc20xx}\\freetype261.lib %FREETYPE%\\objs\\.libs\\libfreetype.lib -) -""" - from setup_external_compile import fixproj, prepare_build_cmd, VS2010, X64, tar_extract - # Note: freetype has no build profile for 2014, so we don't bother... - vc = 'vc2010' if VS2010 else 'vc2008' - WinXX = 'x64' if X64 else 'Win32' - tar_extract(tarball_path, "build") - # This is only false for py2.7, even on py3.5... - if not VS2010: - fixproj(os.path.join(src_path, 'builds', 'windows', vc, 'freetype.sln'), WinXX) - fixproj(os.path.join(src_path, 'builds', 'windows', vc, 'freetype.vcproj'), WinXX) - - cmdfile = os.path.join("build", 'build_freetype.cmd') - with open(cmdfile, 'w') as cmd: - cmd.write(prepare_build_cmd(FREETYPE_BUILD_CMD, vc20xx=vc, WinXX=WinXX, - config='Release' if VS2010 else 'LIB Release')) - - os.environ['FREETYPE'] = src_path - subprocess.check_call([cmdfile], shell=True) - - -class FT2Font(SetupPackage): - name = 'ft2font' - - def get_extension(self): - sources = [ - 'src/ft2font.cpp', - 'src/ft2font_wrapper.cpp', - 'src/mplutils.cpp' - ] - ext = make_extension('matplotlib.ft2font', sources) - FreeType().add_flags(ext) - Numpy().add_flags(ext) - return ext - - -class Png(SetupPackage): - name = "png" - pkg_names = { - "apt-get": "libpng12-dev", - "yum": "libpng-devel", - "dnf": "libpng-devel", - "brew": "libpng", - "port": "libpng", - "windows_url": "http://gnuwin32.sourceforge.net/packages/libpng.htm" - } - - def check(self): - if sys.platform == 'win32': - check_include_file(get_include_dirs(), 'png.h', 'png') - return 'Using unknown version found on system.' - - status, output = getstatusoutput("libpng-config --version") - if status == 0: - version = output - else: - version = None - - try: - return self._check_for_pkg_config( - 'libpng', 'png.h', - min_version='1.2', version=version) - except CheckFailed as e: - if has_include_file(get_include_dirs(), 'png.h'): - return str(e) + ' Using unknown version found on system.' - raise - - def get_extension(self): - sources = [ - 'src/_png.cpp', - 'src/mplutils.cpp' - ] - ext = make_extension('matplotlib._png', sources) - pkg_config.setup_extension( - ext, 'libpng', default_libraries=['png', 'z'], - alt_exec='libpng-config --ldflags') - Numpy().add_flags(ext) - return ext - - -class Qhull(SetupPackage): - name = "qhull" - - def check(self): - self.__class__.found_external = True - try: - return self._check_for_pkg_config( - 'libqhull', 'libqhull/qhull_a.h', min_version='2015.2') - except CheckFailed as e: - self.__class__.found_pkgconfig = False - self.__class__.found_external = False - return str(e) + ' Using local copy.' - - def add_flags(self, ext): - if self.found_external: - pkg_config.setup_extension(ext, 'qhull', - default_libraries=['qhull']) - else: - ext.include_dirs.insert(0, 'extern') - ext.sources.extend(sorted(glob.glob('extern/libqhull/*.c'))) - if sysconfig.get_config_var('LIBM') == '-lm': - ext.libraries.extend('m') - - -class TTConv(SetupPackage): - name = "ttconv" - - def get_extension(self): - sources = [ - 'src/_ttconv.cpp', - 'extern/ttconv/pprdrv_tt.cpp', - 'extern/ttconv/pprdrv_tt2.cpp', - 'extern/ttconv/ttutil.cpp' - ] - ext = make_extension('matplotlib.ttconv', sources) - Numpy().add_flags(ext) - ext.include_dirs.insert(0, 'extern') - return ext - - -class Path(SetupPackage): - name = "path" - - def get_extension(self): - sources = [ - 'src/py_converters.cpp', - 'src/_path_wrapper.cpp' - ] - - ext = make_extension('matplotlib._path', sources) - Numpy().add_flags(ext) - LibAgg().add_flags(ext) - return ext - - -class Image(SetupPackage): - name = "image" - - def get_extension(self): - sources = [ - 'src/_image.cpp', - 'src/mplutils.cpp', - 'src/_image_wrapper.cpp', - 'src/py_converters.cpp' - ] - ext = make_extension('matplotlib._image', sources) - Numpy().add_flags(ext) - LibAgg().add_flags(ext) - - return ext - - -class Contour(SetupPackage): - name = "contour" - - def get_extension(self): - sources = [ - "src/_contour.cpp", - "src/_contour_wrapper.cpp", - ] - ext = make_extension('matplotlib._contour', sources) - Numpy().add_flags(ext) - return ext - - -class QhullWrap(SetupPackage): - name = "qhull_wrap" - - def get_extension(self): - sources = ['src/qhull_wrap.c'] - ext = make_extension('matplotlib._qhull', sources, - define_macros=[('MPL_DEVNULL', os.devnull)]) - Numpy().add_flags(ext) - Qhull().add_flags(ext) - return ext - - -class Tri(SetupPackage): - name = "tri" - - def get_extension(self): - sources = [ - "lib/matplotlib/tri/_tri.cpp", - "lib/matplotlib/tri/_tri_wrapper.cpp", - "src/mplutils.cpp" - ] - ext = make_extension('matplotlib._tri', sources) - Numpy().add_flags(ext) - return ext - - -class InstallRequires(SetupPackage): - name = "install_requires" - - def check(self): - not_available = [] - wrong_version = [] - inst_req = self.get_install_requires() - for pack_inf in inst_req: - pack_inf_disp = pack_inf.split('>=') - if 'dateutil' in pack_inf_disp[0]: - pack_inf_disp[0] = 'dateutil' - pack_name = pack_inf_disp[0] - try: - import_module(pack_name) - if pack_name != pack_inf_disp[-1]: - # This means that we have to check for the version - pack_ver = sys.modules[pack_name].__version__ - pack_ver = [int(ele) for ele in pack_ver.split('.')] - ver_cond = pack_inf_disp[1].split(',!=') - # Check for minimum version - if pack_ver < [int(ele) for ele in ver_cond[0].split('.')]: - if len(ver_cond[1:]) > 0: - wrong_version.append(pack_name - +" is not at least at version " - +ver_cond[0]+os.linesep - +"Please upgrade!"+os.linesep - +"WARNING: Version(s) " - +", ".join(ver_cond[1:]) - +" have issues and must be " - +"avoided.") - else: - wrong_version.append(pack_name - +" is not at least at version " - +ver_cond[0]+os.linesep - +"Please upgrade!") - continue - # Check for forbidden versions if any - for ver in ver_cond[1:]: - if pack_ver == [int(ele) for ele in ver.split('.')]: - wrong_version.append(pack_name+" is at version " - +ver+" which is not allowed."+os.linesep - +"Please use a version newer than "+ver_cond[0] - +" but different from "+", ".join(ver_cond[1:])) - break - except ImportError: - not_available.append(pack_name+" could not be found") - if not_available or wrong_version: - sp_mult = min(1, len(wrong_version)) - req_fail_msg = "ERROR: At least one third-party python package " + \ - "is missing or has the wrong version:" + os.linesep - req_fail_msg += (os.linesep.join(not_available) + - os.linesep*(2*sp_mult)) * min(1, len(not_available)) - req_fail_msg += (os.linesep*2).join(wrong_version) - print_status(package.name, req_fail_msg) - raise CheckFailed("missing or faulty third-party python packages") - return "all third-party python packages are present" - - def get_install_requires(self): - install_requires = [ - "cycler>=0.10", - "pyparsing>=2.0.1,!=2.0.4,!=2.1.2,!=2.1.6", - "python-dateutil>=2.1", - "pytz", - "six>=1.10", - "kiwisolver>=1.0.1", - ] - if sys.version_info < (3,): - install_requires += ["backports.functools_lru_cache"] - if sys.version_info < (3,) and os.name == "posix": - install_requires += ["subprocess32"] - return install_requires - - -class BackendAgg(OptionalBackendPackage): - name = "agg" - force = True - - def get_extension(self): - sources = [ - "src/mplutils.cpp", - "src/py_converters.cpp", - "src/_backend_agg.cpp", - "src/_backend_agg_wrapper.cpp" - ] - ext = make_extension('matplotlib.backends._backend_agg', sources) - Numpy().add_flags(ext) - LibAgg().add_flags(ext) - FreeType().add_flags(ext) - return ext - - -class BackendTkAgg(OptionalBackendPackage): - name = "tkagg" - force = True - - def check(self): - return "installing; run-time loading from Python Tcl / Tk" - - def runtime_check(self): - """ Checks whether TkAgg runtime dependencies are met - """ - pkg_name = 'tkinter' if PY3min else 'Tkinter' - try: - import_module(pkg_name) - except ImportError: - return False - return True - - def get_extension(self): - sources = [ - 'src/_tkagg.cpp' - ] - - ext = make_extension('matplotlib.backends._tkagg', sources) - self.add_flags(ext) - LibAgg().add_flags(ext, add_sources=False) - return ext - - def add_flags(self, ext): - ext.include_dirs.insert(0, 'src') - if sys.platform == 'win32': - # PSAPI library needed for finding Tcl / Tk at run time - ext.libraries.extend(['psapi']) - elif sys.platform.startswith('linux'): - ext.libraries.extend(['dl']) - - -class BackendGtk(OptionalBackendPackage): - name = "gtk" - - def check_requirements(self): - try: - import gtk - except ImportError: - raise CheckFailed("Requires pygtk") - except RuntimeError: - raise CheckFailed('pygtk present, but import failed.') - else: - version = (2, 2, 0) - if gtk.pygtk_version < version: - raise CheckFailed( - "Requires pygtk %d.%d.%d or later. " - "Found %d.%d.%d" % (version + gtk.pygtk_version)) - - ext = self.get_extension() - self.add_flags(ext) - check_include_file(ext.include_dirs, - os.path.join("gtk", "gtk.h"), - 'gtk') - check_include_file(ext.include_dirs, - os.path.join("pygtk", "pygtk.h"), - 'pygtk') - - return 'Gtk: %s pygtk: %s' % ( - ".".join(str(x) for x in gtk.gtk_version), - ".".join(str(x) for x in gtk.pygtk_version)) - - def get_package_data(self): - return {'matplotlib': ['mpl-data/*.glade']} - - def get_extension(self): - sources = [ - 'src/_backend_gdk.c' - ] - ext = make_extension('matplotlib.backends._backend_gdk', sources) - self.add_flags(ext) - Numpy().add_flags(ext) - return ext - - def add_flags(self, ext): - if sys.platform == 'win32': - def getoutput(s): - ret = os.popen(s).read().strip() - return ret - - if 'PKG_CONFIG_PATH' not in os.environ: - # If Gtk+ is installed, pkg-config is required to be installed - os.environ['PKG_CONFIG_PATH'] = 'C:\\GTK\\lib\\pkgconfig' - - # popen broken on my win32 platform so I can't use pkgconfig - ext.library_dirs.extend( - ['C:/GTK/bin', 'C:/GTK/lib']) - - ext.include_dirs.extend( - ['win32_static/include/pygtk-2.0', - 'C:/GTK/include', - 'C:/GTK/include/gobject', - 'C:/GTK/include/gext', - 'C:/GTK/include/glib', - 'C:/GTK/include/pango', - 'C:/GTK/include/atk', - 'C:/GTK/include/X11', - 'C:/GTK/include/cairo', - 'C:/GTK/include/gdk', - 'C:/GTK/include/gdk-pixbuf', - 'C:/GTK/include/gtk', - ]) - - pygtkIncludes = getoutput( - 'pkg-config --cflags-only-I pygtk-2.0').split() - gtkIncludes = getoutput( - 'pkg-config --cflags-only-I gtk+-2.0').split() - includes = pygtkIncludes + gtkIncludes - ext.include_dirs.extend([include[2:] for include in includes]) - - pygtkLinker = getoutput('pkg-config --libs pygtk-2.0').split() - gtkLinker = getoutput('pkg-config --libs gtk+-2.0').split() - linkerFlags = pygtkLinker + gtkLinker - - ext.libraries.extend( - [flag[2:] for flag in linkerFlags if flag.startswith('-l')]) - - ext.library_dirs.extend( - [flag[2:] for flag in linkerFlags if flag.startswith('-L')]) - - ext.extra_link_args.extend( - [flag for flag in linkerFlags if not - (flag.startswith('-l') or flag.startswith('-L'))]) - - # visual studio doesn't need the math library - if (sys.platform == 'win32' and - win32_compiler == 'msvc' and - 'm' in ext.libraries): - ext.libraries.remove('m') - - elif sys.platform != 'win32': - pkg_config.setup_extension(ext, 'pygtk-2.0') - pkg_config.setup_extension(ext, 'gtk+-2.0') - - -class BackendGtkAgg(BackendGtk): - name = "gtkagg" - - def get_package_data(self): - return {'matplotlib': ['mpl-data/*.glade']} - - def get_extension(self): - sources = [ - 'src/py_converters.cpp', - 'src/_gtkagg.cpp', - 'src/mplutils.cpp' - ] - ext = make_extension('matplotlib.backends._gtkagg', sources) - self.add_flags(ext) - LibAgg().add_flags(ext) - Numpy().add_flags(ext) - return ext - - -def backend_gtk3agg_internal_check(x): - try: - import gi - except ImportError: - return (False, "Requires pygobject to be installed.") - - try: - gi.require_version("Gtk", "3.0") - except ValueError: - return (False, "Requires gtk3 development files to be installed.") - except AttributeError: - return (False, "pygobject version too old.") - - try: - from gi.repository import Gtk, Gdk, GObject - except (ImportError, RuntimeError): - return (False, "Requires pygobject to be installed.") - - return (True, "version %s.%s.%s" % ( - Gtk.get_major_version(), - Gtk.get_micro_version(), - Gtk.get_minor_version())) - - -class BackendGtk3Agg(OptionalBackendPackage): - name = "gtk3agg" - - def check_requirements(self): - if 'TRAVIS' in os.environ: - raise CheckFailed("Can't build with Travis") - - # This check needs to be performed out-of-process, because - # importing gi and then importing regular old pygtk afterward - # segfaults the interpreter. - try: - p = multiprocessing.Pool() - except: - return "unknown (can not use multiprocessing to determine)" - try: - res = p.map_async(backend_gtk3agg_internal_check, [0]) - success, msg = res.get(timeout=10)[0] - except multiprocessing.TimeoutError: - p.terminate() - # No result returned. Probably hanging, terminate the process. - success = False - raise CheckFailed("Check timed out") - except: - p.close() - # Some other error. - success = False - msg = "Could not determine" - raise - else: - p.close() - finally: - p.join() - - if success: - return msg - else: - raise CheckFailed(msg) - - def get_package_data(self): - return {'matplotlib': ['mpl-data/*.glade']} - - -def backend_gtk3cairo_internal_check(x): - try: - import cairocffi - except ImportError: - try: - import cairo - except ImportError: - return (False, "Requires cairocffi or pycairo to be installed.") - - try: - import gi - except ImportError: - return (False, "Requires pygobject to be installed.") - - try: - gi.require_version("Gtk", "3.0") - except ValueError: - return (False, "Requires gtk3 development files to be installed.") - except AttributeError: - return (False, "pygobject version too old.") - - try: - from gi.repository import Gtk, Gdk, GObject - except (RuntimeError, ImportError): - return (False, "Requires pygobject to be installed.") - - return (True, "version %s.%s.%s" % ( - Gtk.get_major_version(), - Gtk.get_micro_version(), - Gtk.get_minor_version())) - - -class BackendGtk3Cairo(OptionalBackendPackage): - name = "gtk3cairo" - - def check_requirements(self): - if 'TRAVIS' in os.environ: - raise CheckFailed("Can't build with Travis") - - # This check needs to be performed out-of-process, because - # importing gi and then importing regular old pygtk afterward - # segfaults the interpreter. - try: - p = multiprocessing.Pool() - except: - return "unknown (can not use multiprocessing to determine)" - try: - res = p.map_async(backend_gtk3cairo_internal_check, [0]) - success, msg = res.get(timeout=10)[0] - except multiprocessing.TimeoutError: - p.terminate() - # No result returned. Probably hanging, terminate the process. - success = False - raise CheckFailed("Check timed out") - except: - p.close() - success = False - raise - else: - p.close() - finally: - p.join() - - if success: - return msg - else: - raise CheckFailed(msg) - - def get_package_data(self): - return {'matplotlib': ['mpl-data/*.glade']} - - -class BackendWxAgg(OptionalBackendPackage): - name = "wxagg" - - def check_requirements(self): - wxversioninstalled = True - try: - import wxversion - except ImportError: - wxversioninstalled = False - - if wxversioninstalled: - try: - _wx_ensure_failed = wxversion.AlreadyImportedError - except AttributeError: - _wx_ensure_failed = wxversion.VersionError - - try: - wxversion.ensureMinimal('2.9') - except _wx_ensure_failed: - pass - - try: - import wx - backend_version = wx.VERSION_STRING - except ImportError: - raise CheckFailed("requires wxPython") - - if not is_min_version(backend_version, "2.9"): - raise CheckFailed( - "Requires wxPython 2.9, found %s" % backend_version) - - return "version %s" % backend_version - - -class BackendMacOSX(OptionalBackendPackage): - name = 'macosx' - - def check_requirements(self): - if sys.platform != 'darwin': - raise CheckFailed("Mac OS-X only") - - return 'darwin' - - def get_extension(self): - sources = [ - 'src/_macosx.m' - ] - - ext = make_extension('matplotlib.backends._macosx', sources) - ext.extra_link_args.extend(['-framework', 'Cocoa']) - return ext - - -class Windowing(OptionalBackendPackage): - """ - Builds the windowing extension. - """ - name = "windowing" - - def check_requirements(self): - if sys.platform != 'win32': - raise CheckFailed("Microsoft Windows only") - config = self.get_config() - if config is False: - raise CheckFailed("skipping due to configuration") - return "" - - def get_extension(self): - sources = [ - "src/_windowing.cpp" - ] - ext = make_extension('matplotlib._windowing', sources) - ext.include_dirs.extend(['C:/include']) - ext.libraries.extend(['user32']) - ext.library_dirs.extend(['C:/lib']) - ext.extra_link_args.append("-mwindows") - return ext - - -class BackendQtBase(OptionalBackendPackage): - - def convert_qt_version(self, version): - version = '%x' % version - temp = [] - while len(version) > 0: - version, chunk = version[:-2], version[-2:] - temp.insert(0, str(int(chunk, 16))) - return '.'.join(temp) - - def check_requirements(self): - ''' - If PyQt4/PyQt5 is already imported, importing PyQt5/PyQt4 will fail - so we need to test in a subprocess (as for Gtk3). - ''' - try: - p = multiprocessing.Pool() - - except: - # Can't do multiprocessing, fall back to normal approach - # (this will fail if importing both PyQt4 and PyQt5). - try: - # Try in-process - msg = self.callback(self) - except RuntimeError: - raise CheckFailed( - "Could not import: are PyQt4 & PyQt5 both installed?") - - else: - # Multiprocessing OK - try: - res = p.map_async(self.callback, [self]) - msg = res.get(timeout=10)[0] - except multiprocessing.TimeoutError: - p.terminate() - # No result returned. Probably hanging, terminate the process. - raise CheckFailed("Check timed out") - except: - # Some other error. - p.close() - raise - else: - # Clean exit - p.close() - finally: - # Tidy up multiprocessing - p.join() - - return msg - - -def backend_pyside_internal_check(self): - try: - from PySide import __version__ - from PySide import QtCore - except ImportError: - raise CheckFailed("PySide not found") - else: - return ("Qt: %s, PySide: %s" % - (QtCore.__version__, __version__)) - - -def backend_pyqt4_internal_check(self): - try: - from PyQt4 import QtCore - except ImportError: - raise CheckFailed("PyQt4 not found") - - try: - qt_version = QtCore.QT_VERSION - pyqt_version_str = QtCore.PYQT_VERSION_STR - except AttributeError: - raise CheckFailed('PyQt4 not correctly imported') - else: - return ("Qt: %s, PyQt: %s" % (self.convert_qt_version(qt_version), pyqt_version_str)) - - -def backend_qt4_internal_check(self): - successes = [] - failures = [] - try: - successes.append(backend_pyside_internal_check(self)) - except CheckFailed as e: - failures.append(str(e)) - - try: - successes.append(backend_pyqt4_internal_check(self)) - except CheckFailed as e: - failures.append(str(e)) - - if len(successes) == 0: - raise CheckFailed('; '.join(failures)) - return '; '.join(successes + failures) - - -class BackendQt4(BackendQtBase): - name = "qt4agg" - - def __init__(self, *args, **kwargs): - BackendQtBase.__init__(self, *args, **kwargs) - self.callback = backend_qt4_internal_check - -def backend_pyside2_internal_check(self): - try: - from PySide2 import __version__ - from PySide2 import QtCore - except ImportError: - raise CheckFailed("PySide2 not found") - else: - return ("Qt: %s, PySide2: %s" % - (QtCore.__version__, __version__)) - -def backend_pyqt5_internal_check(self): - try: - from PyQt5 import QtCore - except ImportError: - raise CheckFailed("PyQt5 not found") - - try: - qt_version = QtCore.QT_VERSION - pyqt_version_str = QtCore.PYQT_VERSION_STR - except AttributeError: - raise CheckFailed('PyQt5 not correctly imported') - else: - return ("Qt: %s, PyQt: %s" % (self.convert_qt_version(qt_version), pyqt_version_str)) - -def backend_qt5_internal_check(self): - successes = [] - failures = [] - try: - successes.append(backend_pyside2_internal_check(self)) - except CheckFailed as e: - failures.append(str(e)) - - try: - successes.append(backend_pyqt5_internal_check(self)) - except CheckFailed as e: - failures.append(str(e)) - - if len(successes) == 0: - raise CheckFailed('; '.join(failures)) - return '; '.join(successes + failures) - -class BackendQt5(BackendQtBase): - name = "qt5agg" - - def __init__(self, *args, **kwargs): - BackendQtBase.__init__(self, *args, **kwargs) - self.callback = backend_qt5_internal_check - - -class BackendCairo(OptionalBackendPackage): - name = "cairo" - - def check_requirements(self): - try: - import cairocffi - except ImportError: - try: - import cairo - except ImportError: - raise CheckFailed("cairocffi or pycairo not found") - else: - return "pycairo version %s" % cairo.version - else: - return "cairocffi version %s" % cairocffi.version - - -class DviPng(SetupPackage): - name = "dvipng" - optional = True - - def check(self): - try: - output = check_output('dvipng -version', shell=True, - stderr=subprocess.STDOUT) - return "version %s" % output.splitlines()[1].decode().split()[-1] - except (IndexError, ValueError, subprocess.CalledProcessError): - raise CheckFailed() - - -class Ghostscript(SetupPackage): - name = "ghostscript" - optional = True - - def check(self): - if sys.platform == 'win32': - # mgs is the name in miktex - gs_execs = ['gswin32c', 'gswin64c', 'mgs', 'gs'] - else: - gs_execs = ['gs'] - for gs_exec in gs_execs: - try: - command = gs_exec + ' --version' - output = check_output(command, shell=True, - stderr=subprocess.STDOUT) - return "version %s" % output.decode()[:-1] - except (IndexError, ValueError, subprocess.CalledProcessError): - pass - - raise CheckFailed() - - -class LaTeX(SetupPackage): - name = "latex" - optional = True - - def check(self): - try: - output = check_output('latex -version', shell=True, - stderr=subprocess.STDOUT) - line = output.splitlines()[0].decode() - pattern = r'(3\.1\d+)|(MiKTeX \d+.\d+)' - match = re.search(pattern, line) - return "version %s" % match.group(0) - except (IndexError, ValueError, AttributeError, subprocess.CalledProcessError): - raise CheckFailed() - - -class PdfToPs(SetupPackage): - name = "pdftops" - optional = True - - def check(self): - try: - output = check_output('pdftops -v', shell=True, - stderr=subprocess.STDOUT) - for line in output.splitlines(): - line = line.decode() - if 'version' in line: - return "version %s" % line.split()[2] - except (IndexError, ValueError, subprocess.CalledProcessError): - pass - - raise CheckFailed() - - -class OptionalPackageData(OptionalPackage): - config_category = "package_data" - - -class Dlls(OptionalPackageData): - """ - On Windows, this packages any DLL files that can be found in the - lib/matplotlib/* directories. - """ - name = "dlls" - - def check_requirements(self): - if sys.platform != 'win32': - raise CheckFailed("Microsoft Windows only") - - def get_package_data(self): - return {'': ['*.dll']} - - @classmethod - def get_config(cls): - """ - Look at `setup.cfg` and return one of ["auto", True, False] indicating - if the package is at default state ("auto"), forced by the user (True) - or opted-out (False). - """ - try: - return config.getboolean(cls.config_category, cls.name) - except: - return False # <-- default |