Skip to content

Commit 1b4d0c2

Browse files
committed
Match normalized requirement names (#3153)
2 parents dad9161 + 3669910 commit 1b4d0c2

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

changelog.d/3153.change.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
When resolving requirements use both canonical and normalized names -- by :user:`ldaniluk`

pkg_resources/__init__.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
__import__('pkg_resources.extern.packaging.specifiers')
8484
__import__('pkg_resources.extern.packaging.requirements')
8585
__import__('pkg_resources.extern.packaging.markers')
86+
__import__('pkg_resources.extern.packaging.utils')
8687

8788
if sys.version_info < (3, 5):
8889
raise RuntimeError("Python 3.5 or later is required")
@@ -554,6 +555,7 @@ def __init__(self, entries=None):
554555
self.entries = []
555556
self.entry_keys = {}
556557
self.by_key = {}
558+
self.normalized_to_canonical_keys = {}
557559
self.callbacks = []
558560

559561
if entries is None:
@@ -634,6 +636,14 @@ def find(self, req):
634636
is returned.
635637
"""
636638
dist = self.by_key.get(req.key)
639+
640+
if dist is None:
641+
canonical_key = self.normalized_to_canonical_keys.get(req.key)
642+
643+
if canonical_key is not None:
644+
req.key = canonical_key
645+
dist = self.by_key.get(canonical_key)
646+
637647
if dist is not None and dist not in req:
638648
# XXX add more info
639649
raise VersionConflict(dist, req)
@@ -702,6 +712,8 @@ def add(self, dist, entry=None, insert=True, replace=False):
702712
return
703713

704714
self.by_key[dist.key] = dist
715+
normalized_name = packaging.utils.canonicalize_name(dist.key)
716+
self.normalized_to_canonical_keys[normalized_name] = dist.key
705717
if dist.key not in keys:
706718
keys.append(dist.key)
707719
if dist.key not in keys2:
@@ -922,14 +934,15 @@ def _added_new(self, dist):
922934
def __getstate__(self):
923935
return (
924936
self.entries[:], self.entry_keys.copy(), self.by_key.copy(),
925-
self.callbacks[:]
937+
self.normalized_to_canonical_keys.copy(), self.callbacks[:]
926938
)
927939

928-
def __setstate__(self, e_k_b_c):
929-
entries, keys, by_key, callbacks = e_k_b_c
940+
def __setstate__(self, e_k_b_n_c):
941+
entries, keys, by_key, normalized_to_canonical_keys, callbacks = e_k_b_n_c
930942
self.entries = entries[:]
931943
self.entry_keys = keys.copy()
932944
self.by_key = by_key.copy()
945+
self.normalized_to_canonical_keys = normalized_to_canonical_keys.copy()
933946
self.callbacks = callbacks[:]
934947

935948

pkg_resources/tests/test_working_set.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def parse_distributions(s):
4242
continue
4343
fields = spec.split('\n', 1)
4444
assert 1 <= len(fields) <= 2
45-
name, version = fields.pop(0).split('-')
45+
name, version = fields.pop(0).rsplit('-', 1)
4646
if fields:
4747
requires = textwrap.dedent(fields.pop(0))
4848
metadata = Metadata(('requires.txt', requires))
@@ -465,6 +465,25 @@ def parametrize_test_working_set_resolve(*test_list):
465465
# resolved [replace conflicting]
466466
VersionConflict
467467
''',
468+
469+
'''
470+
# id
471+
wanted_normalized_name_installed_canonical
472+
473+
# installed
474+
foo.bar-3.6
475+
476+
# installable
477+
478+
# wanted
479+
foo-bar==3.6
480+
481+
# resolved
482+
foo.bar-3.6
483+
484+
# resolved [replace conflicting]
485+
foo.bar-3.6
486+
''',
468487
)
469488
def test_working_set_resolve(installed_dists, installable_dists, requirements,
470489
replace_conflicting, resolved_dists_or_exception):

0 commit comments

Comments
 (0)