Skip to content

Commit

Permalink
Add manylinux2014 support
Browse files Browse the repository at this point in the history
  • Loading branch information
mayeut committed Oct 9, 2019
1 parent 90aeec9 commit 62d84a5
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 7 deletions.
4 changes: 4 additions & 0 deletions news/7102.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Implement manylinux2014 platform tag support. manylinux2014 is the successor
to manylinux2010. It allows carefully compiled binary wheels to be installed
on compatible Linux platforms. The manylinux2014 platform tag definition can
be found in `PEP599 <https://www.python.org/dev/peps/pep-0599/>`_.
32 changes: 32 additions & 0 deletions src/pip/_internal/pep425tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,26 @@ def is_manylinux2010_compatible():
return pip._internal.utils.glibc.have_compatible_glibc(2, 12)


def is_manylinux2014_compatible():
# type: () -> bool
# Only Linux and only x86-64, i686, aarch64, armv7l, ppc64, ppc64le, s390x
if get_platform() not in {"linux_x86_64", "linux_i686", "linux_aarch64",
"linux_armv7l", "linux_ppc64", "linux_ppc64le",
"linux_s390x"}:
return False

# Check for presence of _manylinux module
try:
import _manylinux
return bool(_manylinux.manylinux2014_compatible)
except (ImportError, AttributeError):
# Fall through to heuristic check below
pass

# Check glibc version. CentOS 7 uses glibc 2.17.
return pip._internal.utils.glibc.have_compatible_glibc(2, 17)


def get_darwin_arches(major, minor, machine):
# type: (int, int, str) -> List[str]
"""Return a list of supported arches (including group arches) for
Expand Down Expand Up @@ -333,6 +353,16 @@ def get_supported(
else:
# arch pattern didn't match (?!)
arches = [arch]
elif arch_prefix == 'manylinux2014':
arches = [arch]
# manylinux1/manylinux2010 wheels run on most manylinux2014 systems
# with the exception of wheels depending on ncurses. PEP 599 states
# manylinux1/manylinux2010 wheels should be considered
# manylinux2014 wheels:
# https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels
if arch_suffix in {'i686', 'x86_64'}:
arches.append('manylinux2010' + arch_sep + arch_suffix)
arches.append('manylinux1' + arch_sep + arch_suffix)
elif arch_prefix == 'manylinux2010':
# manylinux1 wheels run on most manylinux2010 systems with the
# exception of wheels depending on ncurses. PEP 571 states
Expand All @@ -341,6 +371,8 @@ def get_supported(
arches = [arch, 'manylinux1' + arch_sep + arch_suffix]
elif platform is None:
arches = []
if is_manylinux2014_compatible():
arches.append('manylinux2014' + arch_sep + arch_suffix)
if is_manylinux2010_compatible():
arches.append('manylinux2010' + arch_sep + arch_suffix)
if is_manylinux1_compatible():
Expand Down
4 changes: 4 additions & 0 deletions tests/functional/test_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ class TestDownloadPlatformManylinuxes(object):
"linux_x86_64",
"manylinux1_x86_64",
"manylinux2010_x86_64",
"manylinux2014_x86_64",
])
def test_download_universal(self, platform, script, data):
"""
Expand All @@ -353,6 +354,9 @@ def test_download_universal(self, platform, script, data):
("manylinux1_x86_64", "manylinux1_x86_64"),
("manylinux1_x86_64", "manylinux2010_x86_64"),
("manylinux2010_x86_64", "manylinux2010_x86_64"),
("manylinux1_x86_64", "manylinux2014_x86_64"),
("manylinux2010_x86_64", "manylinux2014_x86_64"),
("manylinux2014_x86_64", "manylinux2014_x86_64"),
])
def test_download_compatible_manylinuxes(
self, wheel_abi, platform, script, data,
Expand Down
71 changes: 64 additions & 7 deletions tests/unit/test_pep425tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def test_manual_abi_dm_flags(self):
@pytest.mark.parametrize('is_manylinux_compatible', [
pep425tags.is_manylinux1_compatible,
pep425tags.is_manylinux2010_compatible,
pep425tags.is_manylinux2014_compatible,
])
class TestManylinuxTags(object):
"""
Expand All @@ -156,28 +157,28 @@ def test_manylinux_compatible_on_linux_x86_64(self,
@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_i686')
@patch('pip._internal.utils.glibc.have_compatible_glibc',
lambda major, minor: True)
def test_manylinux1_compatible_on_linux_i686(self,
is_manylinux_compatible):
def test_manylinux_compatible_on_linux_i686(self,
is_manylinux_compatible):
"""
Test that manylinux1 is enabled on linux_i686
Test that manylinuxes are enabled on linux_i686
"""
assert is_manylinux_compatible()

@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_x86_64')
@patch('pip._internal.utils.glibc.have_compatible_glibc',
lambda major, minor: False)
def test_manylinux1_2(self, is_manylinux_compatible):
def test_manylinux_2(self, is_manylinux_compatible):
"""
Test that manylinux1 is disabled with incompatible glibc
Test that manylinuxes are disabled with incompatible glibc
"""
assert not is_manylinux_compatible()

@patch('pip._internal.pep425tags.get_platform', lambda: 'arm6vl')
@patch('pip._internal.utils.glibc.have_compatible_glibc',
lambda major, minor: True)
def test_manylinux1_3(self, is_manylinux_compatible):
def test_manylinux_3(self, is_manylinux_compatible):
"""
Test that manylinux1 is disabled on arm6vl
Test that manylinuxes are disabled on arm6vl
"""
assert not is_manylinux_compatible()

Expand All @@ -186,6 +187,8 @@ class TestManylinux1Tags(object):

@patch('pip._internal.pep425tags.is_manylinux2010_compatible',
lambda: False)
@patch('pip._internal.pep425tags.is_manylinux2014_compatible',
lambda: False)
@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_x86_64')
@patch('pip._internal.utils.glibc.have_compatible_glibc',
lambda major, minor: True)
Expand All @@ -210,6 +213,8 @@ def test_manylinux1_tag_is_first(self):

class TestManylinux2010Tags(object):

@patch('pip._internal.pep425tags.is_manylinux2014_compatible',
lambda: False)
@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_x86_64')
@patch('pip._internal.utils.glibc.have_compatible_glibc',
lambda major, minor: True)
Expand Down Expand Up @@ -253,3 +258,55 @@ def test_manylinux2010_implies_manylinux1(self, manylinux2010, manylinux1):
if arches == ['any']:
continue
assert arches[:2] == [manylinux2010, manylinux1]


class TestManylinux2014Tags(object):

@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_x86_64')
@patch('pip._internal.utils.glibc.have_compatible_glibc',
lambda major, minor: True)
@patch('sys.platform', 'linux2')
def test_manylinux2014_tag_is_first(self):
"""
Test that the more specific tag manylinux2014 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) == 5:
assert arches == ['manylinux2014_x86_64',
'manylinux2010_x86_64',
'manylinux1_x86_64',
'linux_x86_64',
'any']
else:
assert arches == ['manylinux2014_x86_64',
'manylinux2010_x86_64',
'manylinux1_x86_64',
'linux_x86_64']

@pytest.mark.parametrize("manylinuxA,manylinuxB", [
("manylinux2014_x86_64", ["manylinux2010_x86_64",
"manylinux1_x86_64"]),
("manylinux2014_i686", ["manylinux2010_i686", "manylinux1_i686"]),
])
def test_manylinuxA_implies_manylinuxB(self, manylinuxA, manylinuxB):
"""
Specifying manylinux2014 implies manylinux2010/manylinux1.
"""
groups = {}
supported = pep425tags.get_supported(platform=manylinuxA)
for pyimpl, abi, arch in supported:
groups.setdefault((pyimpl, abi), []).append(arch)

expected_arches = [manylinuxA]
expected_arches.extend(manylinuxB)
for arches in groups.values():
if arches == ['any']:
continue
assert arches[:3] == expected_arches

0 comments on commit 62d84a5

Please sign in to comment.