Skip to content

Commit

Permalink
Match normalized requirement names (#3153)
Browse files Browse the repository at this point in the history
  • Loading branch information
abravalheri committed Apr 4, 2022
2 parents dad9161 + 3669910 commit 1b4d0c2
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 4 deletions.
1 change: 1 addition & 0 deletions changelog.d/3153.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
When resolving requirements use both canonical and normalized names -- by :user:`ldaniluk`
19 changes: 16 additions & 3 deletions pkg_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
__import__('pkg_resources.extern.packaging.specifiers')
__import__('pkg_resources.extern.packaging.requirements')
__import__('pkg_resources.extern.packaging.markers')
__import__('pkg_resources.extern.packaging.utils')

if sys.version_info < (3, 5):
raise RuntimeError("Python 3.5 or later is required")
Expand Down Expand Up @@ -554,6 +555,7 @@ def __init__(self, entries=None):
self.entries = []
self.entry_keys = {}
self.by_key = {}
self.normalized_to_canonical_keys = {}
self.callbacks = []

if entries is None:
Expand Down Expand Up @@ -634,6 +636,14 @@ def find(self, req):
is returned.
"""
dist = self.by_key.get(req.key)

if dist is None:
canonical_key = self.normalized_to_canonical_keys.get(req.key)

if canonical_key is not None:
req.key = canonical_key
dist = self.by_key.get(canonical_key)

if dist is not None and dist not in req:
# XXX add more info
raise VersionConflict(dist, req)
Expand Down Expand Up @@ -702,6 +712,8 @@ def add(self, dist, entry=None, insert=True, replace=False):
return

self.by_key[dist.key] = dist
normalized_name = packaging.utils.canonicalize_name(dist.key)
self.normalized_to_canonical_keys[normalized_name] = dist.key
if dist.key not in keys:
keys.append(dist.key)
if dist.key not in keys2:
Expand Down Expand Up @@ -922,14 +934,15 @@ def _added_new(self, dist):
def __getstate__(self):
return (
self.entries[:], self.entry_keys.copy(), self.by_key.copy(),
self.callbacks[:]
self.normalized_to_canonical_keys.copy(), self.callbacks[:]
)

def __setstate__(self, e_k_b_c):
entries, keys, by_key, callbacks = e_k_b_c
def __setstate__(self, e_k_b_n_c):
entries, keys, by_key, normalized_to_canonical_keys, callbacks = e_k_b_n_c
self.entries = entries[:]
self.entry_keys = keys.copy()
self.by_key = by_key.copy()
self.normalized_to_canonical_keys = normalized_to_canonical_keys.copy()
self.callbacks = callbacks[:]


Expand Down
21 changes: 20 additions & 1 deletion pkg_resources/tests/test_working_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def parse_distributions(s):
continue
fields = spec.split('\n', 1)
assert 1 <= len(fields) <= 2
name, version = fields.pop(0).split('-')
name, version = fields.pop(0).rsplit('-', 1)
if fields:
requires = textwrap.dedent(fields.pop(0))
metadata = Metadata(('requires.txt', requires))
Expand Down Expand Up @@ -465,6 +465,25 @@ def parametrize_test_working_set_resolve(*test_list):
# resolved [replace conflicting]
VersionConflict
''',
'''
# id
wanted_normalized_name_installed_canonical
# installed
foo.bar-3.6
# installable
# wanted
foo-bar==3.6
# resolved
foo.bar-3.6
# resolved [replace conflicting]
foo.bar-3.6
''',
)
def test_working_set_resolve(installed_dists, installable_dists, requirements,
replace_conflicting, resolved_dists_or_exception):
Expand Down

0 comments on commit 1b4d0c2

Please sign in to comment.