diff --git a/pip/pep425tags.py b/pip/pep425tags.py index b760c922c5d..997626cf07d 100644 --- a/pip/pep425tags.py +++ b/pip/pep425tags.py @@ -1,5 +1,6 @@ """Generate and work with PEP 425 Compatibility Tags.""" +import re import sys import warnings @@ -10,6 +11,8 @@ import distutils.sysconfig as sysconfig import distutils.util +_osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)') + def get_abbr_impl(): """Return abbreviated implementation name.""" @@ -77,10 +80,37 @@ def get_supported(versions=None, noarch=False): if not noarch: arch = get_platform() + if sys.platform == 'darwin': + # 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() + actual_arches = [actual_arch] + if actual_arch in ('i386', 'ppc'): + actual_arches.append('fat') + if actual_arch in ('i386', 'x86_64'): + actual_arches.append('intel') + if actual_arch in ('i386', 'ppc', 'x86_64'): + actual_arches.append('fat3') + if actual_arch in ('ppc64', 'x86_64'): + actual_arches.append('fat64') + if actual_arch in ('i386', 'x86_64', 'intel', 'ppc', 'ppc64'): + actual_arches.append('universal') + tpl = '{0}_{1}_%i_%s'.format(name, major) + arches = [] + for m in range(int(minor) + 1): + for a in actual_arches: + arches.append(tpl % (m, a)) + else: + # arch pattern didn't match (?!) + arches = [arch] + else: + arches = [arch] # Current version, current API (built specifically for our Python): for abi in abis: - supported.append(('%s%s' % (impl, versions[0]), abi, arch)) + for arch in arches: + supported.append(('%s%s' % (impl, versions[0]), abi, arch)) # No abi / arch, but requires our implementation: for i, version in enumerate(versions): diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py index 5b813a91597..3f9acb905f2 100644 --- a/tests/unit/test_wheel.py +++ b/tests/unit/test_wheel.py @@ -5,7 +5,7 @@ from mock import patch, Mock from pip._vendor import pkg_resources -from pip import wheel +from pip import pep425tags, wheel from pip.exceptions import InvalidWheelFilename, UnsupportedWheel from pip.util import unpack_file @@ -149,6 +149,90 @@ def test_not_supported_version(self): w = wheel.Wheel('simple-0.1-py2-none-any.whl') assert not w.supported(tags=[('py1', 'none', 'any')]) + @patch('sys.platform', 'darwin') + @patch('pip.pep425tags.get_abbr_impl', lambda: 'cp') + @patch('pip.pep425tags.get_platform', lambda: 'macosx_10_9_intel') + def test_supported_osx_version(self): + """ + Wheels built for OS X 10.6 are supported on 10.9 + """ + tags = pep425tags.get_supported(['27'], False) + w = wheel.Wheel('simple-0.1-cp27-none-macosx_10_6_intel.whl') + assert w.supported(tags=tags) + w = wheel.Wheel('simple-0.1-cp27-none-macosx_10_9_intel.whl') + assert w.supported(tags=tags) + + @patch('sys.platform', 'darwin') + @patch('pip.pep425tags.get_abbr_impl', lambda: 'cp') + @patch('pip.pep425tags.get_platform', lambda: 'macosx_10_6_intel') + def test_not_supported_osx_version(self): + """ + Wheels built for OS X 10.9 are not supported on 10.6 + """ + tags = pep425tags.get_supported(['27'], False) + w = wheel.Wheel('simple-0.1-cp27-none-macosx_10_9_intel.whl') + assert not w.supported(tags=tags) + + @patch('sys.platform', 'darwin') + @patch('pip.pep425tags.get_abbr_impl', lambda: 'cp') + def test_supported_multiarch_darwin(self): + """ + Multi-arch wheels (intel) are supported on components (i386, x86_64) + """ + with patch('pip.pep425tags.get_platform', + lambda: 'macosx_10_5_universal'): + universal = pep425tags.get_supported(['27'], False) + with patch('pip.pep425tags.get_platform', + lambda: 'macosx_10_5_intel'): + intel = pep425tags.get_supported(['27'], False) + with patch('pip.pep425tags.get_platform', + lambda: 'macosx_10_5_x86_64'): + x64 = pep425tags.get_supported(['27'], False) + with patch('pip.pep425tags.get_platform', + lambda: 'macosx_10_5_i386'): + i386 = pep425tags.get_supported(['27'], False) + with patch('pip.pep425tags.get_platform', + lambda: 'macosx_10_5_ppc'): + ppc = pep425tags.get_supported(['27'], False) + with patch('pip.pep425tags.get_platform', + lambda: 'macosx_10_5_ppc64'): + ppc64 = pep425tags.get_supported(['27'], False) + + w = wheel.Wheel('simple-0.1-cp27-none-macosx_10_5_intel.whl') + assert w.supported(tags=intel) + assert w.supported(tags=x64) + assert w.supported(tags=i386) + assert not w.supported(tags=universal) + assert not w.supported(tags=ppc) + assert not w.supported(tags=ppc64) + w = wheel.Wheel('simple-0.1-cp27-none-macosx_10_5_universal.whl') + assert w.supported(tags=universal) + assert w.supported(tags=intel) + assert w.supported(tags=x64) + assert w.supported(tags=i386) + assert w.supported(tags=ppc) + assert w.supported(tags=ppc64) + + @patch('sys.platform', 'darwin') + @patch('pip.pep425tags.get_abbr_impl', lambda: 'cp') + def test_not_supported_multiarch_darwin(self): + """ + Single-arch wheels (x86_64) are not supported on multi-arch (intel) + """ + with patch('pip.pep425tags.get_platform', + lambda: 'macosx_10_5_universal'): + universal = pep425tags.get_supported(['27'], False) + with patch('pip.pep425tags.get_platform', + lambda: 'macosx_10_5_intel'): + intel = pep425tags.get_supported(['27'], False) + + w = wheel.Wheel('simple-0.1-cp27-none-macosx_10_5_i386.whl') + assert not w.supported(tags=intel) + assert not w.supported(tags=universal) + w = wheel.Wheel('simple-0.1-cp27-none-macosx_10_5_x86_64.whl') + assert not w.supported(tags=intel) + assert not w.supported(tags=universal) + def test_support_index_min(self): """ Test results from `support_index_min`