Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve tag generation for EggPackage. #493

Merged
merged 1 commit into from
May 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 54 additions & 25 deletions pex/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ def satisfies(self, requirement, allow_prereleases=None):
return requirement.specifier.contains(self.raw_version, prereleases=allow_prereleases)

def compatible(self, supported_tags):
"""Is this link compatible with the given tag set?
"""Is this package compatible with the given tag set?

:param supported_tags: A list of tags that is supported by the target
interpeter, as generated by
:func:`pex.pep425tags.get_supported`.
:type supported_tags: list of 3-tuples
"""
return not set(supported_tags).isdisjoint(self._supported_tags)
raise NotImplementedError()


class SourcePackage(Package):
Expand Down Expand Up @@ -142,7 +142,34 @@ def compatible(self, supported_tags):
return True


class EggPackage(Package):
class BinaryPackage(Package):
"""A Package representing a binary distribution which can be e.g. platform specific."""

def __init__(self, *args, **kwargs):
super(BinaryPackage, self).__init__(*args, **kwargs)
self._supported_tags = None

@property
def supported_tags(self):
if not self._supported_tags:
self._supported_tags = frozenset(self._iter_tags())
return self._supported_tags

def _iter_tags(self):
raise NotImplementedError()

def compatible(self, supported_tags):
"""Is this package compatible with the given tag set?

:param supported_tags: A list of tags that is supported by the target
interpeter, as generated by
:func:`pex.pep425tags.get_supported`.
:type supported_tags: list of 3-tuples
"""
return not set(supported_tags).isdisjoint(self.supported_tags)


class EggPackage(BinaryPackage):
"""A Package representing a built egg."""

def __init__(self, url, **kw):
Expand All @@ -161,26 +188,6 @@ def __init__(self, url, **kw):
if self._raw_version is None or self._py_version is None:
raise self.InvalidPackage('url with .egg extension but bad name: %s' % url)

impl = 'py' + self._py_version.replace('.', '')
abi_tag = 'none'
tag_platform = (self._platform or 'any').replace('-', '_')

self._supported_tags = set([(impl, abi_tag, tag_platform)])
if tag_platform != 'any':
self._supported_tags.add((impl, abi_tag, 'any'))

# Work around PyPy versions being weird in pep425tags.get_supported
if self.py_version == '2.7':
self._supported_tags.add(('pp2', abi_tag, tag_platform))
elif self.py_version == '3.2':
self._supported_tags.add(('pp321', abi_tag, tag_platform))
elif self.py_version == '3.3':
# N.B. PyPy 3.3 maps to `pp352` because of PyPy versioning.
# see e.g. http://doc.pypy.org/en/latest/release-pypy3.3-v5.2-alpha1.html
self._supported_tags.add(('pp352', abi_tag, tag_platform))
elif self.py_version == '3.5':
self._supported_tags.add(('pp357', abi_tag, tag_platform))

def __hash__(self):
return hash((self.name, self.version, self.py_version, self.platform))

Expand All @@ -200,8 +207,31 @@ def py_version(self):
def platform(self):
return self._platform

def _iter_tags(self):
abi_tag = 'none'
tag_platform = (self._platform or 'any').replace('-', '_').replace('.', '_')
suffix_maj = self._py_version.split('.', 1)[0]
suffix_min = self._py_version.replace('.', '')

for prefix in ('py', 'cp'):
for suffix in (suffix_maj, suffix_min):
impl = ''.join((prefix, suffix))
yield (impl, abi_tag, tag_platform)

# Work around PyPy versions being weird in pep425tags.get_supported
if self.py_version == '2.7':
yield ('pp2', abi_tag, tag_platform)
elif self.py_version == '3.2':
yield ('pp321', abi_tag, tag_platform)
elif self.py_version == '3.3':
# N.B. PyPy 3.3 maps to `pp352` because of PyPy versioning.
# see e.g. http://doc.pypy.org/en/latest/release-pypy3.3-v5.2-alpha1.html
yield ('pp352', abi_tag, tag_platform)
elif self.py_version == '3.5':
yield ('pp357', abi_tag, tag_platform)


class WheelPackage(Package):
class WheelPackage(BinaryPackage):
"""A Package representing a built wheel."""

def __init__(self, url, **kw):
Expand All @@ -217,7 +247,6 @@ def __init__(self, url, **kw):
# See https://github.com/pypa/pip/issues/1150 for why this is unavoidable.
self._name = self._name.replace('_', '-')
self._raw_version = self._raw_version.replace('_', '-')
self._supported_tags = frozenset(self._iter_tags())

@property
def name(self):
Expand Down
Binary file not shown.
29 changes: 28 additions & 1 deletion tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -834,11 +834,38 @@ def test_pex_manylinux_runtime():


@pytest.mark.skipif(NOT_CPYTHON27)
def test_platform_specific_egg_resolution():
def test_platform_specific_inline_egg_resolution():
with temporary_dir() as td:
pex_out_path = os.path.join(td, 'pex.pex')
res = run_pex_command(['--disable-cache',
'--no-wheel',
'MarkupSafe==1.0',
'-o', pex_out_path])
res.assert_success()


@pytest.mark.skipif(NOT_CPYTHON27)
def test_platform_specific_egg_resolution():
with temporary_dir() as td:
pex_out_path = os.path.join(td, 'pex.pex')
res = run_pex_command(['--disable-cache',
'--no-wheel',
'--no-build',
'--no-pypi',
'--platform=linux-x86_64',
'--find-links=tests/example_packages/',
'M2Crypto==0.22.3',
'-o', pex_out_path])
res.assert_success()


@pytest.mark.skipif(NOT_CPYTHON27)
def test_platform_specific_egg_resolution_matching():
with temporary_dir() as td:
pex_out_path = os.path.join(td, 'pex.pex')
res = run_pex_command(['--disable-cache',
'--no-wheel',
'--no-build',
'netifaces==0.10.6', # Only provides win32 eggs.
'-o', pex_out_path])
res.assert_failure()