From 6c8b150a2b6c0a6c01ffc89f4fdbda5b03241a3c Mon Sep 17 00:00:00 2001 From: Brian Wickman Date: Tue, 11 Aug 2015 16:09:26 -0700 Subject: [PATCH] Normalize all names in ResolvableSet. Fixes #147. --- CHANGES.rst | 8 ++++++++ pex/resolver.py | 16 ++++++++++++---- pex/version.py | 2 +- tests/test_resolver.py | 10 +++++----- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index a7f31a25a..bc2eebb1e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,14 @@ CHANGES ======= +---------- +1.1.0.dev0 +---------- + +* Bug fix: We did not normalize package names in ``ResolvableSet``, so it was possible to depend on + ``sphinx`` and ``Sphinx-1.4a0.tar.gz`` and get two versions build and included into the pex. + `#147 `_. + ----- 1.0.3 ----- diff --git a/pex/resolver.py b/pex/resolver.py index c8db1cf5c..fe45fa6a2 100644 --- a/pex/resolver.py +++ b/pex/resolver.py @@ -8,6 +8,8 @@ import time from collections import namedtuple +from pkg_resources import safe_name + from .common import safe_mkdir from .fetcher import Fetcher from .interpreter import PythonInterpreter @@ -56,6 +58,10 @@ def merge(self, other): class _ResolvableSet(object): + @classmethod + def normalize(cls, name): + return safe_name(name).lower() + def __init__(self, tuples=None): # A list of _ResolvedPackages self.__tuples = tuples or [] @@ -71,7 +77,7 @@ def _collapse(self): # adversely but could be the source of subtle resolution quirks. resolvables = {} for resolved_packages in self.__tuples: - key = resolved_packages.resolvable.name + key = self.normalize(resolved_packages.resolvable.name) previous = resolvables.get(key, _ResolvedPackages.empty()) if previous.resolvable is None: resolvables[key] = resolved_packages @@ -86,7 +92,7 @@ def render_resolvable(resolved_packages): '(from: %s)' % resolved_packages.parent if resolved_packages.parent else '') return ', '.join( render_resolvable(resolved_packages) for resolved_packages in self.__tuples - if resolved_packages.resolvable.name == name) + if self.normalize(resolved_packages.resolvable.name) == self.normalize(name)) def _check(self): # Check whether or not the resolvables in this set are satisfiable, raise an exception if not. @@ -102,7 +108,8 @@ def merge(self, resolvable, packages, parent=None): def get(self, name): """Get the set of compatible packages given a resolvable name.""" - resolvable, packages, parent = self._collapse().get(name, _ResolvedPackages.empty()) + resolvable, packages, parent = self._collapse().get( + self.normalize(name), _ResolvedPackages.empty()) return packages def packages(self): @@ -111,7 +118,8 @@ def packages(self): def extras(self, name): return set.union( - *[set(tup.resolvable.extras()) for tup in self.__tuples if tup.resolvable.name == name]) + *[set(tup.resolvable.extras()) for tup in self.__tuples + if self.normalize(tup.resolvable.name) == self.normalize(name)]) def replace_built(self, built_packages): """Return a copy of this resolvable set but with built packages. diff --git a/pex/version.py b/pex/version.py index c7d1aeac0..ef3d5144f 100644 --- a/pex/version.py +++ b/pex/version.py @@ -1,7 +1,7 @@ # Copyright 2015 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -__version__ = '1.0.3' +__version__ = '1.1.0.dev0' SETUPTOOLS_REQUIREMENT = 'setuptools>=2.2,<16' WHEEL_REQUIREMENT = 'wheel>=0.24.0,<0.25.0' diff --git a/tests/test_resolver.py b/tests/test_resolver.py index 5b8897081..ce94d02fb 100644 --- a/tests/test_resolver.py +++ b/tests/test_resolver.py @@ -53,18 +53,21 @@ def test_resolvable_set(): rs = _ResolvableSet() rq = ResolvableRequirement.from_string('foo[ext]', builder) source_pkg = SourcePackage.from_href('foo-2.3.4.tar.gz') - binary_pkg = EggPackage.from_href('foo-2.3.4-py3.4.egg') + binary_pkg = EggPackage.from_href('Foo-2.3.4-py3.4.egg') rs.merge(rq, [source_pkg, binary_pkg]) - assert rs.get('foo') == set([source_pkg, binary_pkg]) + assert rs.get(source_pkg.name) == set([source_pkg, binary_pkg]) + assert rs.get(binary_pkg.name) == set([source_pkg, binary_pkg]) assert rs.packages() == [(rq, set([source_pkg, binary_pkg]), None)] # test methods assert rs.extras('foo') == set(['ext']) + assert rs.extras('Foo') == set(['ext']) # test filtering rs.merge(rq, [source_pkg]) assert rs.get('foo') == set([source_pkg]) + assert rs.get('Foo') == set([source_pkg]) with pytest.raises(Unsatisfiable): rs.merge(rq, [binary_pkg]) @@ -88,6 +91,3 @@ def test_resolvable_set_built(): updated_rs.merge(rq, [binary_pkg]) assert updated_rs.get('foo') == set([binary_pkg]) assert updated_rs.packages() == [(rq, set([binary_pkg]), None)] - - -# TODO(wickman) Write more than simple resolver test.