aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenoit Pierre <benoit.pierre@gmail.com>2019-08-23 23:18:02 +0200
committerBenoit Pierre <benoit.pierre@gmail.com>2019-10-07 23:32:58 +0200
commit3d811b93a83d5931b821916c6ca172a69c403a97 (patch)
treec45ef57a1e9c912eddb5d72cb853ecb1728dd350
parentbf069fe9ddcadaa2c029067601d06a07d037d4f7 (diff)
downloadexternal_python_setuptools-3d811b93a83d5931b821916c6ca172a69c403a97.tar.gz
external_python_setuptools-3d811b93a83d5931b821916c6ca172a69c403a97.tar.bz2
external_python_setuptools-3d811b93a83d5931b821916c6ca172a69c403a97.zip
wheel: switch to `packaging.tags` for checking PEP 425 tags
-rw-r--r--setuptools/glibc.py86
-rw-r--r--setuptools/pep425tags.py319
-rw-r--r--setuptools/tests/test_glibc.py52
-rw-r--r--setuptools/tests/test_pep425tags.py170
-rw-r--r--setuptools/wheel.py4
5 files changed, 2 insertions, 629 deletions
diff --git a/setuptools/glibc.py b/setuptools/glibc.py
deleted file mode 100644
index a134591c..00000000
--- a/setuptools/glibc.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# This file originally from pip:
-# https://github.com/pypa/pip/blob/8f4f15a5a95d7d5b511ceaee9ed261176c181970/src/pip/_internal/utils/glibc.py
-from __future__ import absolute_import
-
-import ctypes
-import re
-import warnings
-
-
-def glibc_version_string():
- "Returns glibc version string, or None if not using glibc."
-
- # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
- # manpage says, "If filename is NULL, then the returned handle is for the
- # main program". This way we can let the linker do the work to figure out
- # which libc our process is actually using.
- process_namespace = ctypes.CDLL(None)
- try:
- gnu_get_libc_version = process_namespace.gnu_get_libc_version
- except AttributeError:
- # Symbol doesn't exist -> therefore, we are not linked to
- # glibc.
- return None
-
- # Call gnu_get_libc_version, which returns a string like "2.5"
- gnu_get_libc_version.restype = ctypes.c_char_p
- version_str = gnu_get_libc_version()
- # py2 / py3 compatibility:
- if not isinstance(version_str, str):
- version_str = version_str.decode("ascii")
-
- return version_str
-
-
-# Separated out from have_compatible_glibc for easier unit testing
-def check_glibc_version(version_str, required_major, minimum_minor):
- # Parse string and check against requested version.
- #
- # We use a regexp instead of str.split because we want to discard any
- # random junk that might come after the minor version -- this might happen
- # in patched/forked versions of glibc (e.g. Linaro's version of glibc
- # uses version strings like "2.20-2014.11"). See gh-3588.
- m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
- if not m:
- warnings.warn("Expected glibc version with 2 components major.minor,"
- " got: %s" % version_str, RuntimeWarning)
- return False
- return (int(m.group("major")) == required_major and
- int(m.group("minor")) >= minimum_minor)
-
-
-def have_compatible_glibc(required_major, minimum_minor):
- version_str = glibc_version_string()
- if version_str is None:
- return False
- return check_glibc_version(version_str, required_major, minimum_minor)
-
-
-# platform.libc_ver regularly returns completely nonsensical glibc
-# versions. E.g. on my computer, platform says:
-#
-# ~$ python2.7 -c 'import platform; print(platform.libc_ver())'
-# ('glibc', '2.7')
-# ~$ python3.5 -c 'import platform; print(platform.libc_ver())'
-# ('glibc', '2.9')
-#
-# But the truth is:
-#
-# ~$ ldd --version
-# ldd (Debian GLIBC 2.22-11) 2.22
-#
-# This is unfortunate, because it means that the linehaul data on libc
-# versions that was generated by pip 8.1.2 and earlier is useless and
-# misleading. Solution: instead of using platform, use our code that actually
-# works.
-def libc_ver():
- """Try to determine the glibc version
-
- Returns a tuple of strings (lib, version) which default to empty strings
- in case the lookup fails.
- """
- glibc_version = glibc_version_string()
- if glibc_version is None:
- return ("", "")
- else:
- return ("glibc", glibc_version)
diff --git a/setuptools/pep425tags.py b/setuptools/pep425tags.py
deleted file mode 100644
index 48745a29..00000000
--- a/setuptools/pep425tags.py
+++ /dev/null
@@ -1,319 +0,0 @@
-# This file originally from pip:
-# https://github.com/pypa/pip/blob/8f4f15a5a95d7d5b511ceaee9ed261176c181970/src/pip/_internal/pep425tags.py
-"""Generate and work with PEP 425 Compatibility Tags."""
-from __future__ import absolute_import
-
-import distutils.util
-from distutils import log
-import platform
-import re
-import sys
-import sysconfig
-import warnings
-from collections import OrderedDict
-
-from .extern import six
-
-from . import glibc
-
-_osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)')
-
-
-def get_config_var(var):
- try:
- return sysconfig.get_config_var(var)
- except IOError as e: # Issue #1074
- warnings.warn("{}".format(e), RuntimeWarning)
- return None
-
-
-def get_abbr_impl():
- """Return abbreviated implementation name."""
- if hasattr(sys, 'pypy_version_info'):
- pyimpl = 'pp'
- elif sys.platform.startswith('java'):
- pyimpl = 'jy'
- elif sys.platform == 'cli':
- pyimpl = 'ip'
- else:
- pyimpl = 'cp'
- return pyimpl
-
-
-def get_impl_ver():
- """Return implementation version."""
- impl_ver = get_config_var("py_version_nodot")
- if not impl_ver or get_abbr_impl() == 'pp':
- impl_ver = ''.join(map(str, get_impl_version_info()))
- return impl_ver
-
-
-def get_impl_version_info():
- """Return sys.version_info-like tuple for use in decrementing the minor
- version."""
- if get_abbr_impl() == 'pp':
- # as per https://github.com/pypa/pip/issues/2882
- return (sys.version_info[0], sys.pypy_version_info.major,
- sys.pypy_version_info.minor)
- else:
- return sys.version_info[0], sys.version_info[1]
-
-
-def get_impl_tag():
- """
- Returns the Tag for this specific implementation.
- """
- return "{}{}".format(get_abbr_impl(), get_impl_ver())
-
-
-def get_flag(var, fallback, expected=True, warn=True):
- """Use a fallback method for determining SOABI flags if the needed config
- var is unset or unavailable."""
- val = get_config_var(var)
- if val is None:
- if warn:
- log.debug("Config variable '%s' is unset, Python ABI tag may "
- "be incorrect", var)
- return fallback()
- return val == expected
-
-
-def get_abi_tag():
- """Return the ABI tag based on SOABI (if available) or emulate SOABI
- (CPython 2, PyPy)."""
- soabi = get_config_var('SOABI')
- impl = get_abbr_impl()
- if not soabi and impl in {'cp', 'pp'} and hasattr(sys, 'maxunicode'):
- d = ''
- m = ''
- u = ''
- if get_flag('Py_DEBUG',
- lambda: hasattr(sys, 'gettotalrefcount'),
- warn=(impl == 'cp')):
- d = 'd'
- if get_flag('WITH_PYMALLOC',
- lambda: impl == 'cp',
- warn=(impl == 'cp')):
- m = 'm'
- if get_flag('Py_UNICODE_SIZE',
- lambda: sys.maxunicode == 0x10ffff,
- expected=4,
- warn=(impl == 'cp' and
- six.PY2)) \
- and six.PY2:
- u = 'u'
- abi = '%s%s%s%s%s' % (impl, get_impl_ver(), d, m, u)
- elif soabi and soabi.startswith('cpython-'):
- abi = 'cp' + soabi.split('-')[1]
- elif soabi:
- abi = soabi.replace('.', '_').replace('-', '_')
- else:
- abi = None
- return abi
-
-
-def _is_running_32bit():
- return sys.maxsize == 2147483647
-
-
-def get_platform():
- """Return our platform name 'win32', 'linux_x86_64'"""
- if sys.platform == 'darwin':
- # distutils.util.get_platform() returns the release based on the value
- # of MACOSX_DEPLOYMENT_TARGET on which Python was built, which may
- # be significantly older than the user's current machine.
- release, _, machine = platform.mac_ver()
- split_ver = release.split('.')
-
- if machine == "x86_64" and _is_running_32bit():
- machine = "i386"
- elif machine == "ppc64" and _is_running_32bit():
- machine = "ppc"
-
- return 'macosx_{}_{}_{}'.format(split_ver[0], split_ver[1], machine)
-
- # XXX remove distutils dependency
- result = distutils.util.get_platform().replace('.', '_').replace('-', '_')
- if result == "linux_x86_64" and _is_running_32bit():
- # 32 bit Python program (running on a 64 bit Linux): pip should only
- # install and run 32 bit compiled extensions in that case.
- result = "linux_i686"
-
- return result
-
-
-def is_manylinux1_compatible():
- # Only Linux, and only x86-64 / i686
- if get_platform() not in {"linux_x86_64", "linux_i686"}:
- return False
-
- # Check for presence of _manylinux module
- try:
- import _manylinux
- return bool(_manylinux.manylinux1_compatible)
- except (ImportError, AttributeError):
- # Fall through to heuristic check below
- pass
-
- # Check glibc version. CentOS 5 uses glibc 2.5.
- return glibc.have_compatible_glibc(2, 5)
-
-
-def get_darwin_arches(major, minor, machine):
- """Return a list of supported arches (including group arches) for
- the given major, minor and machine architecture of a macOS machine.
- """
- arches = []
-
- def _supports_arch(major, minor, arch):
- # Looking at the application support for macOS versions in the chart
- # provided by https://en.wikipedia.org/wiki/OS_X#Versions it appears
- # our timeline looks roughly like:
- #
- # 10.0 - Introduces ppc support.
- # 10.4 - Introduces ppc64, i386, and x86_64 support, however the ppc64
- # and x86_64 support is CLI only, and cannot be used for GUI
- # applications.
- # 10.5 - Extends ppc64 and x86_64 support to cover GUI applications.
- # 10.6 - Drops support for ppc64
- # 10.7 - Drops support for ppc
- #
- # Given that we do not know if we're installing a CLI or a GUI
- # application, we must be conservative and assume it might be a GUI
- # application and behave as if ppc64 and x86_64 support did not occur
- # until 10.5.
- #
- # Note: The above information is taken from the "Application support"
- # column in the chart not the "Processor support" since I believe
- # that we care about what instruction sets an application can use
- # not which processors the OS supports.
- if arch == 'ppc':
- return (major, minor) <= (10, 5)
- if arch == 'ppc64':
- return (major, minor) == (10, 5)
- if arch == 'i386':
- return (major, minor) >= (10, 4)
- if arch == 'x86_64':
- return (major, minor) >= (10, 5)
- if arch in groups:
- for garch in groups[arch]:
- if _supports_arch(major, minor, garch):
- return True
- return False
-
- groups = OrderedDict([
- ("fat", ("i386", "ppc")),
- ("intel", ("x86_64", "i386")),
- ("fat64", ("x86_64", "ppc64")),
- ("fat32", ("x86_64", "i386", "ppc")),
- ])
-
- if _supports_arch(major, minor, machine):
- arches.append(machine)
-
- for garch in groups:
- if machine in groups[garch] and _supports_arch(major, minor, garch):
- arches.append(garch)
-
- arches.append('universal')
-
- return arches
-
-
-def get_supported(versions=None, noarch=False, platform=None,
- impl=None, abi=None):
- """Return a list of supported tags for each version specified in
- `versions`.
-
- :param versions: a list of string versions, of the form ["33", "32"],
- or None. The first version will be assumed to support our ABI.
- :param platform: specify the exact platform you want valid
- tags for, or None. If None, use the local system platform.
- :param impl: specify the exact implementation you want valid
- tags for, or None. If None, use the local interpreter impl.
- :param abi: specify the exact abi you want valid
- tags for, or None. If None, use the local interpreter abi.
- """
- supported = []
-
- # Versions must be given with respect to the preference
- if versions is None:
- versions = []
- version_info = get_impl_version_info()
- major = version_info[:-1]
- # Support all previous minor Python versions.
- for minor in range(version_info[-1], -1, -1):
- versions.append(''.join(map(str, major + (minor,))))
-
- impl = impl or get_abbr_impl()
-
- abis = []
-
- abi = abi or get_abi_tag()
- if abi:
- abis[0:0] = [abi]
-
- abi3s = set()
- import imp
- for suffix in imp.get_suffixes():
- if suffix[0].startswith('.abi'):
- abi3s.add(suffix[0].split('.', 2)[1])
-
- abis.extend(sorted(list(abi3s)))
-
- abis.append('none')
-
- if not noarch:
- arch = platform or get_platform()
- if arch.startswith('macosx'):
- # support macosx-10.6-intel on macosx-10.9-x86_64
- match = _osx_arch_pat.match(arch)
- if match:
- name, major, minor, actual_arch = match.groups()
- tpl = '{}_{}_%i_%s'.format(name, major)
- arches = []
- for m in reversed(range(int(minor) + 1)):
- for a in get_darwin_arches(int(major), m, actual_arch):
- arches.append(tpl % (m, a))
- else:
- # arch pattern didn't match (?!)
- arches = [arch]
- elif platform is None and is_manylinux1_compatible():
- arches = [arch.replace('linux', 'manylinux1'), arch]
- else:
- arches = [arch]
-
- # Current version, current API (built specifically for our Python):
- for abi in abis:
- for arch in arches:
- supported.append(('%s%s' % (impl, versions[0]), abi, arch))
-
- # abi3 modules compatible with older version of Python
- for version in versions[1:]:
- # abi3 was introduced in Python 3.2
- if version in {'31', '30'}:
- break
- for abi in abi3s: # empty set if not Python 3
- for arch in arches:
- supported.append(("%s%s" % (impl, version), abi, arch))
-
- # Has binaries, does not use the Python API:
- for arch in arches:
- supported.append(('py%s' % (versions[0][0]), 'none', arch))
-
- # No abi / arch, but requires our implementation:
- supported.append(('%s%s' % (impl, versions[0]), 'none', 'any'))
- # Tagged specifically as being cross-version compatible
- # (with just the major version specified)
- supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any'))
-
- # No abi / arch, generic Python
- for i, version in enumerate(versions):
- supported.append(('py%s' % (version,), 'none', 'any'))
- if i == 0:
- supported.append(('py%s' % (version[0]), 'none', 'any'))
-
- return supported
-
-
-implementation_tag = get_impl_tag()
diff --git a/setuptools/tests/test_glibc.py b/setuptools/tests/test_glibc.py
deleted file mode 100644
index 795fdc56..00000000
--- a/setuptools/tests/test_glibc.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import warnings
-
-import pytest
-
-from setuptools.glibc import check_glibc_version
-
-__metaclass__ = type
-
-
-@pytest.fixture(params=[
- "2.20",
- # used by "linaro glibc", see gh-3588
- "2.20-2014.11",
- # weird possibilities that I just made up
- "2.20+dev",
- "2.20-custom",
- "2.20.1",
- ])
-def two_twenty(request):
- return request.param
-
-
-@pytest.fixture(params=["asdf", "", "foo.bar"])
-def bad_string(request):
- return request.param
-
-
-class TestGlibc:
- def test_manylinux1_check_glibc_version(self, two_twenty):
- """
- Test that the check_glibc_version function is robust against weird
- glibc version strings.
- """
- assert check_glibc_version(two_twenty, 2, 15)
- assert check_glibc_version(two_twenty, 2, 20)
- assert not check_glibc_version(two_twenty, 2, 21)
- assert not check_glibc_version(two_twenty, 3, 15)
- assert not check_glibc_version(two_twenty, 1, 15)
-
- def test_bad_versions(self, bad_string):
- """
- For unparseable strings, warn and return False
- """
- with warnings.catch_warnings(record=True) as ws:
- warnings.filterwarnings("always")
- assert not check_glibc_version(bad_string, 2, 5)
- for w in ws:
- if "Expected glibc version with" in str(w.message):
- break
- else:
- # Didn't find the warning we were expecting
- assert False
diff --git a/setuptools/tests/test_pep425tags.py b/setuptools/tests/test_pep425tags.py
deleted file mode 100644
index 30afdec7..00000000
--- a/setuptools/tests/test_pep425tags.py
+++ /dev/null
@@ -1,170 +0,0 @@
-import sys
-
-import pytest
-from mock import patch
-
-from setuptools import pep425tags
-
-__metaclass__ = type
-
-
-class TestPEP425Tags:
-
- def mock_get_config_var(self, **kwd):
- """
- Patch sysconfig.get_config_var for arbitrary keys.
- """
- get_config_var = pep425tags.sysconfig.get_config_var
-
- def _mock_get_config_var(var):
- if var in kwd:
- return kwd[var]
- return get_config_var(var)
- return _mock_get_config_var
-
- def abi_tag_unicode(self, flags, config_vars):
- """
- Used to test ABI tags, verify correct use of the `u` flag
- """
- config_vars.update({'SOABI': None})
- base = pep425tags.get_abbr_impl() + pep425tags.get_impl_ver()
-
- if sys.version_info < (3, 3):
- config_vars.update({'Py_UNICODE_SIZE': 2})
- mock_gcf = self.mock_get_config_var(**config_vars)
- with patch(
- 'setuptools.pep425tags.sysconfig.get_config_var',
- mock_gcf):
- abi_tag = pep425tags.get_abi_tag()
- assert abi_tag == base + flags
-
- config_vars.update({'Py_UNICODE_SIZE': 4})
- mock_gcf = self.mock_get_config_var(**config_vars)
- with patch('setuptools.pep425tags.sysconfig.get_config_var',
- mock_gcf):
- abi_tag = pep425tags.get_abi_tag()
- assert abi_tag == base + flags + 'u'
-
- else:
- # On Python >= 3.3, UCS-4 is essentially permanently enabled, and
- # Py_UNICODE_SIZE is None. SOABI on these builds does not include
- # the 'u' so manual SOABI detection should not do so either.
- config_vars.update({'Py_UNICODE_SIZE': None})
- mock_gcf = self.mock_get_config_var(**config_vars)
- with patch('setuptools.pep425tags.sysconfig.get_config_var',
- mock_gcf):
- abi_tag = pep425tags.get_abi_tag()
- assert abi_tag == base + flags
-
- def test_broken_sysconfig(self):
- """
- Test that pep425tags still works when sysconfig is broken.
- Can be a problem on Python 2.7
- Issue #1074.
- """
- def raises_ioerror(var):
- raise IOError("I have the wrong path!")
-
- with patch('setuptools.pep425tags.sysconfig.get_config_var',
- raises_ioerror):
- with pytest.warns(RuntimeWarning):
- assert len(pep425tags.get_supported())
-
- def test_no_hyphen_tag(self):
- """
- Test that no tag contains a hyphen.
- """
- mock_gcf = self.mock_get_config_var(SOABI='cpython-35m-darwin')
-
- with patch('setuptools.pep425tags.sysconfig.get_config_var',
- mock_gcf):
- supported = pep425tags.get_supported()
-
- for (py, abi, plat) in supported:
- assert '-' not in py
- assert '-' not in abi
- assert '-' not in plat
-
- def test_manual_abi_noflags(self):
- """
- Test that no flags are set on a non-PyDebug, non-Pymalloc ABI tag.
- """
- self.abi_tag_unicode('', {'Py_DEBUG': False, 'WITH_PYMALLOC': False})
-
- def test_manual_abi_d_flag(self):
- """
- Test that the `d` flag is set on a PyDebug, non-Pymalloc ABI tag.
- """
- self.abi_tag_unicode('d', {'Py_DEBUG': True, 'WITH_PYMALLOC': False})
-
- def test_manual_abi_m_flag(self):
- """
- Test that the `m` flag is set on a non-PyDebug, Pymalloc ABI tag.
- """
- self.abi_tag_unicode('m', {'Py_DEBUG': False, 'WITH_PYMALLOC': True})
-
- def test_manual_abi_dm_flags(self):
- """
- Test that the `dm` flags are set on a PyDebug, Pymalloc ABI tag.
- """
- self.abi_tag_unicode('dm', {'Py_DEBUG': True, 'WITH_PYMALLOC': True})
-
-
-class TestManylinux1Tags:
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'linux_x86_64')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: True)
- def test_manylinux1_compatible_on_linux_x86_64(self):
- """
- Test that manylinux1 is enabled on linux_x86_64
- """
- assert pep425tags.is_manylinux1_compatible()
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'linux_i686')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: True)
- def test_manylinux1_compatible_on_linux_i686(self):
- """
- Test that manylinux1 is enabled on linux_i686
- """
- assert pep425tags.is_manylinux1_compatible()
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'linux_x86_64')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: False)
- def test_manylinux1_2(self):
- """
- Test that manylinux1 is disabled with incompatible glibc
- """
- assert not pep425tags.is_manylinux1_compatible()
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'arm6vl')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: True)
- def test_manylinux1_3(self):
- """
- Test that manylinux1 is disabled on arm6vl
- """
- assert not pep425tags.is_manylinux1_compatible()
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'linux_x86_64')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: True)
- @patch('sys.platform', 'linux2')
- def test_manylinux1_tag_is_first(self):
- """
- Test that the more specific tag manylinux1 comes first.
- """
- groups = {}
- for pyimpl, abi, arch in pep425tags.get_supported():
- groups.setdefault((pyimpl, abi), []).append(arch)
-
- for arches in groups.values():
- if arches == ['any']:
- continue
- # Expect the most specific arch first:
- if len(arches) == 3:
- assert arches == ['manylinux1_x86_64', 'linux_x86_64', 'any']
- else:
- assert arches == ['manylinux1_x86_64', 'linux_x86_64']
diff --git a/setuptools/wheel.py b/setuptools/wheel.py
index e11f0a1d..502f8410 100644
--- a/setuptools/wheel.py
+++ b/setuptools/wheel.py
@@ -11,9 +11,9 @@ import zipfile
import pkg_resources
import setuptools
from pkg_resources import parse_version
+from setuptools.extern.packaging.tags import sys_tags
from setuptools.extern.packaging.utils import canonicalize_name
from setuptools.extern.six import PY3
-from setuptools import pep425tags
from setuptools.command.egg_info import write_requirements
@@ -76,7 +76,7 @@ class Wheel:
def is_compatible(self):
'''Is the wheel is compatible with the current platform?'''
- supported_tags = pep425tags.get_supported()
+ supported_tags = set(map(str, sys_tags()))
return next((True for t in self.tags() if t in supported_tags), False)
def egg_name(self):