Skip to content

Commit 62f0b12

Browse files
committed
Add manylinux2014 support
Per PEP 599: https://www.python.org/dev/peps/pep-0599/
1 parent 1cbc28a commit 62f0b12

File tree

4 files changed

+102
-7
lines changed

4 files changed

+102
-7
lines changed

news/7102.feature

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Implement manylinux2014 platform tag support. manylinux2014 is the successor
2+
to manylinux2010. It allows carefully compiled binary wheels to be installed
3+
on compatible Linux platforms.

src/pip/_internal/pep425tags.py

+31
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,25 @@ def is_manylinux2010_compatible():
200200
return pip._internal.utils.glibc.have_compatible_glibc(2, 12)
201201

202202

203+
def is_manylinux2014_compatible():
204+
# type: () -> bool
205+
# Only Linux, and only x86-64, i686, aarch64, ppc64, ppc64le, s390x
206+
if get_platform() not in {"linux_x86_64", "linux_i686", "linux-aarch64",
207+
"linux-ppc64", "linux-ppc64le", "linux-s390x"}:
208+
return False
209+
210+
# Check for presence of _manylinux module
211+
try:
212+
import _manylinux
213+
return bool(_manylinux.manylinux2014_compatible)
214+
except (ImportError, AttributeError):
215+
# Fall through to heuristic check below
216+
pass
217+
218+
# Check glibc version. CentOS 7 uses glibc 2.17.
219+
return pip._internal.utils.glibc.have_compatible_glibc(2, 17)
220+
221+
203222
def get_darwin_arches(major, minor, machine):
204223
# type: (int, int, str) -> List[str]
205224
"""Return a list of supported arches (including group arches) for
@@ -333,6 +352,16 @@ def get_supported(
333352
else:
334353
# arch pattern didn't match (?!)
335354
arches = [arch]
355+
elif arch_prefix == 'manylinux2014':
356+
arches = [arch]
357+
# manylinux1/manylinux2010 wheels run on most manylinux2014 systems
358+
# with the exception of wheels depending on ncurses. PEP 599 states
359+
# manylinux1/manylinux2010 wheels should be considered
360+
# manylinux2014 wheels:
361+
# https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels
362+
if arch_suffix in {'i686', 'x86_64'}:
363+
arches.append('manylinux2010' + arch_sep + arch_suffix)
364+
arches.append('manylinux1' + arch_sep + arch_suffix)
336365
elif arch_prefix == 'manylinux2010':
337366
# manylinux1 wheels run on most manylinux2010 systems with the
338367
# exception of wheels depending on ncurses. PEP 571 states
@@ -341,6 +370,8 @@ def get_supported(
341370
arches = [arch, 'manylinux1' + arch_sep + arch_suffix]
342371
elif platform is None:
343372
arches = []
373+
if is_manylinux2014_compatible():
374+
arches.append('manylinux2014' + arch_sep + arch_suffix)
344375
if is_manylinux2010_compatible():
345376
arches.append('manylinux2010' + arch_sep + arch_suffix)
346377
if is_manylinux1_compatible():

tests/functional/test_download.py

+4
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ class TestDownloadPlatformManylinuxes(object):
331331
"linux_x86_64",
332332
"manylinux1_x86_64",
333333
"manylinux2010_x86_64",
334+
"manylinux2014_x86_64",
334335
])
335336
def test_download_universal(self, platform, script, data):
336337
"""
@@ -353,6 +354,9 @@ def test_download_universal(self, platform, script, data):
353354
("manylinux1_x86_64", "manylinux1_x86_64"),
354355
("manylinux1_x86_64", "manylinux2010_x86_64"),
355356
("manylinux2010_x86_64", "manylinux2010_x86_64"),
357+
("manylinux1_x86_64", "manylinux2014_x86_64"),
358+
("manylinux2010_x86_64", "manylinux2014_x86_64"),
359+
("manylinux2014_x86_64", "manylinux2014_x86_64"),
356360
])
357361
def test_download_compatible_manylinuxes(
358362
self, wheel_abi, platform, script, data,

tests/unit/test_pep425tags.py

+64-7
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ def test_manual_abi_dm_flags(self):
137137
@pytest.mark.parametrize('is_manylinux_compatible', [
138138
pep425tags.is_manylinux1_compatible,
139139
pep425tags.is_manylinux2010_compatible,
140+
pep425tags.is_manylinux2014_compatible,
140141
])
141142
class TestManylinuxTags(object):
142143
"""
@@ -156,28 +157,28 @@ def test_manylinux_compatible_on_linux_x86_64(self,
156157
@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_i686')
157158
@patch('pip._internal.utils.glibc.have_compatible_glibc',
158159
lambda major, minor: True)
159-
def test_manylinux1_compatible_on_linux_i686(self,
160-
is_manylinux_compatible):
160+
def test_manylinux_compatible_on_linux_i686(self,
161+
is_manylinux_compatible):
161162
"""
162-
Test that manylinux1 is enabled on linux_i686
163+
Test that manylinuxes are enabled on linux_i686
163164
"""
164165
assert is_manylinux_compatible()
165166

166167
@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_x86_64')
167168
@patch('pip._internal.utils.glibc.have_compatible_glibc',
168169
lambda major, minor: False)
169-
def test_manylinux1_2(self, is_manylinux_compatible):
170+
def test_manylinux_2(self, is_manylinux_compatible):
170171
"""
171-
Test that manylinux1 is disabled with incompatible glibc
172+
Test that manylinuxes are disabled with incompatible glibc
172173
"""
173174
assert not is_manylinux_compatible()
174175

175176
@patch('pip._internal.pep425tags.get_platform', lambda: 'arm6vl')
176177
@patch('pip._internal.utils.glibc.have_compatible_glibc',
177178
lambda major, minor: True)
178-
def test_manylinux1_3(self, is_manylinux_compatible):
179+
def test_manylinux_3(self, is_manylinux_compatible):
179180
"""
180-
Test that manylinux1 is disabled on arm6vl
181+
Test that manylinuxes are disabled disabled on arm6vl
181182
"""
182183
assert not is_manylinux_compatible()
183184

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

187188
@patch('pip._internal.pep425tags.is_manylinux2010_compatible',
188189
lambda: False)
190+
@patch('pip._internal.pep425tags.is_manylinux2014_compatible',
191+
lambda: False)
189192
@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_x86_64')
190193
@patch('pip._internal.utils.glibc.have_compatible_glibc',
191194
lambda major, minor: True)
@@ -210,6 +213,8 @@ def test_manylinux1_tag_is_first(self):
210213

211214
class TestManylinux2010Tags(object):
212215

216+
@patch('pip._internal.pep425tags.is_manylinux2014_compatible',
217+
lambda: False)
213218
@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_x86_64')
214219
@patch('pip._internal.utils.glibc.have_compatible_glibc',
215220
lambda major, minor: True)
@@ -253,3 +258,55 @@ def test_manylinux2010_implies_manylinux1(self, manylinux2010, manylinux1):
253258
if arches == ['any']:
254259
continue
255260
assert arches[:2] == [manylinux2010, manylinux1]
261+
262+
263+
class TestManylinux2014Tags(object):
264+
265+
@patch('pip._internal.pep425tags.get_platform', lambda: 'linux_x86_64')
266+
@patch('pip._internal.utils.glibc.have_compatible_glibc',
267+
lambda major, minor: True)
268+
@patch('sys.platform', 'linux2')
269+
def test_manylinux2014_tag_is_first(self):
270+
"""
271+
Test that the more specific tag manylinux2014 comes first.
272+
"""
273+
groups = {}
274+
for pyimpl, abi, arch in pep425tags.get_supported():
275+
groups.setdefault((pyimpl, abi), []).append(arch)
276+
277+
for arches in groups.values():
278+
if arches == ['any']:
279+
continue
280+
# Expect the most specific arch first:
281+
if len(arches) == 5:
282+
assert arches == ['manylinux2014_x86_64',
283+
'manylinux2010_x86_64',
284+
'manylinux1_x86_64',
285+
'linux_x86_64',
286+
'any']
287+
else:
288+
assert arches == ['manylinux2014_x86_64',
289+
'manylinux2010_x86_64',
290+
'manylinux1_x86_64',
291+
'linux_x86_64']
292+
293+
@pytest.mark.parametrize("manylinuxA,manylinuxB", [
294+
("manylinux2014_x86_64", ["manylinux2010_x86_64",
295+
"manylinux1_x86_64"]),
296+
("manylinux2014_i686", ["manylinux2010_i686", "manylinux1_i686"]),
297+
])
298+
def test_manylinuxA_implies_manylinuxB(self, manylinuxA, manylinuxB):
299+
"""
300+
Specifying manylinux2014 implies manylinux2010/manylinux1.
301+
"""
302+
groups = {}
303+
supported = pep425tags.get_supported(platform=manylinuxA)
304+
for pyimpl, abi, arch in supported:
305+
groups.setdefault((pyimpl, abi), []).append(arch)
306+
307+
expected_arches = [manylinuxA]
308+
expected_arches.extend(manylinuxB)
309+
for arches in groups.values():
310+
if arches == ['any']:
311+
continue
312+
assert arches[:3] == expected_arches

0 commit comments

Comments
 (0)