Skip to content

Commit

Permalink
Add manylinux2014 support
Browse files Browse the repository at this point in the history
  • Loading branch information
mayeut committed Sep 28, 2019
1 parent 1cbc28a commit 91c6dec
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 7 deletions.
3 changes: 3 additions & 0 deletions news/7102.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Implement manylinux2014 platform tag support. manylinux2014 is the successor
to manylinux2010. It allows carefully compiled binary wheels to be installed
on compatible Linux platforms.
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 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 91c6dec

Please sign in to comment.