Skip to content

Commit

Permalink
Merge pull request pypa#8 from pfmoore/wheel_install_platcheck
Browse files Browse the repository at this point in the history
Add platform checks to wheel location code
  • Loading branch information
qwcode committed Oct 14, 2012
2 parents aaf18e3 + 50c2111 commit 6e481b1
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 12 deletions.
19 changes: 9 additions & 10 deletions pip/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
product, url2pathname)
from pip.backwardcompat import Empty as QueueEmpty
from pip.download import urlopen, path_to_url2, url_to_path, geturl, Urllib2HeadRequest
import pip.pep425tags

__all__ = ['PackageFinder']

Expand Down Expand Up @@ -329,17 +330,15 @@ def _link_package_versions(self, link, search_name):
wheel_info = self._wheel_info_re.match(link.filename)
if wheel_info.group('name').replace('_', '-').lower() == search_name.lower():
version = wheel_info.group('ver')
nodot = sys.version[:3].replace('.', '')
pyversions = wheel_info.group('pyver').split('.')
ok = False
for pv in pyversions:
# TODO: Doesn't check Python implementation
if nodot.startswith(pv[2:]):
ok = True
break
if not ok:
logger.debug('Skipping %s because Python version is incorrect' % link)
return []
abis = wheel_info.group('abi').split('.')
plats = wheel_info.group('plat').split('.')
wheel_supports = set((x, y, z) for x in pyversions for y
in abis for z in plats)
supported = set(pip.pep425tags.get_supported())
if not supported.intersection(wheel_supports):
logger.debug('Skipping %s because it is not compatible with this Python' % link)
return []
if not version:
version = self._egg_info_matches(egg_info, search_name, link)
if version is None:
Expand Down
97 changes: 97 additions & 0 deletions pip/pep425tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"""Generate and work with PEP 425 Compatibility Tags."""

import sys

try:
import sysconfig
except ImportError: # pragma nocover
# Python < 2.7
import distutils.sysconfig as sysconfig
import distutils.util


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 = sysconfig.get_config_var("py_version_nodot")
if not impl_ver:
impl_ver = ''.join(map(str, sys.version_info[:2]))
return impl_ver


def get_platform():
"""Return our platform name 'win32', 'linux_x86_64'"""
# XXX remove distutils dependency
return distutils.util.get_platform().replace('.', '_').replace('-', '_')


def get_supported(versions=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.
"""
supported = []

# Versions must be given with respect to the preference
if versions is None:
versions = []
major = sys.version_info[0]
# Support all previous minor Python versions.
for minor in range(sys.version_info[1], -1, -1):
versions.append(''.join(map(str, (major, minor))))

impl = get_abbr_impl()

abis = []

soabi = sysconfig.get_config_var('SOABI')
if soabi and soabi.startswith('cpython-'):
abis[0:0] = ['cp' + soabi.split('-', 1)[-1]]

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')

arch = get_platform()

# Current version, current API (built specifically for our Python):
for abi in abis:
supported.append(('%s%s' % (impl, versions[0]), abi, arch))

# No abi / arch, but requires our implementation:
for i, version in enumerate(versions):
supported.append(('%s%s' % (impl, version), 'none', 'any'))
if i == 0:
# 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


Binary file not shown.
24 changes: 22 additions & 2 deletions tests/test_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
from pip.backwardcompat import urllib
from pip.req import InstallRequirement
from pip.index import PackageFinder
from pip.exceptions import BestVersionAlreadyInstalled
from pip.exceptions import BestVersionAlreadyInstalled, DistributionNotFound
from tests.path import Path
from tests.test_pip import here
from nose.tools import assert_raises
from mock import Mock
from mock import Mock, patch
import os

find_links = 'file://' + urllib.quote(str(Path(here).abspath/'packages').replace('\\', '/'))
find_links2 = 'file://' + urllib.quote(str(Path(here).abspath/'packages2').replace('\\', '/'))
Expand Down Expand Up @@ -75,3 +76,22 @@ def test_finder_detects_latest_already_satisfied_pypi_links():
req.satisfied_by = satisfied_by
finder = PackageFinder([], ["http://pypi.python.org/simple"])
assert_raises(BestVersionAlreadyInstalled, finder.find_requirement, req, True)

@patch('pip.pep425tags.get_supported')
def test_find_wheel(mock_get_supported):
"""
Test finding wheels.
"""
find_links_url = 'file://' + os.path.join(here, 'packages')
find_links = [find_links_url]
req = InstallRequirement.from_line("simple.dist")
finder = PackageFinder(find_links, [], use_wheel=True)
mock_get_supported.return_value = [('py1', 'none', 'any')]
assert_raises(DistributionNotFound, finder.find_requirement, req, True)
mock_get_supported.return_value = [('py2', 'none', 'any')]
found = finder.find_requirement(req, True)
assert found.url.endswith("simple.dist-0.1-py2.py3-none-any.whl"), found
mock_get_supported.return_value = [('py3', 'none', 'any')]
found = finder.find_requirement(req, True)
assert found.url.endswith("simple.dist-0.1-py2.py3-none-any.whl"), found

0 comments on commit 6e481b1

Please sign in to comment.