Skip to content

Commit c0f39c0

Browse files
committed
Update WorkingSet.find to consider standardised .dist-info directory names (#4856)
2 parents 56c055b + edca181 commit c0f39c0

File tree

3 files changed

+71
-6
lines changed

3 files changed

+71
-6
lines changed

newsfragments/4856.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed ``pkg_resources.require(...)`` to also consider standardised
2+
``dist-info`` directories.

pkg_resources/__init__.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -708,14 +708,19 @@ def find(self, req: Requirement) -> Distribution | None:
708708
If there is no active distribution for the requested project, ``None``
709709
is returned.
710710
"""
711-
dist = self.by_key.get(req.key)
711+
dist: Distribution | None = None
712712

713-
if dist is None:
714-
canonical_key = self.normalized_to_canonical_keys.get(req.key)
713+
candidates = (
714+
req.key,
715+
self.normalized_to_canonical_keys.get(req.key),
716+
safe_name(req.key).replace(".", "-"),
717+
)
715718

716-
if canonical_key is not None:
717-
req.key = canonical_key
718-
dist = self.by_key.get(canonical_key)
719+
for candidate in filter(None, candidates):
720+
dist = self.by_key.get(candidate)
721+
if dist:
722+
req.key = candidate
723+
break
719724

720725
if dist is not None and dist not in req:
721726
# XXX add more info

pkg_resources/tests/test_pkg_resources.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import builtins
44
import datetime
5+
import inspect
56
import os
67
import plistlib
78
import stat
@@ -425,3 +426,60 @@ def test_normalize_path_backslash_sep(self, unnormalized, expected):
425426
"""Ensure path seps are cleaned on backslash path sep systems."""
426427
result = pkg_resources.normalize_path(unnormalized)
427428
assert result.endswith(expected)
429+
430+
431+
class TestWorkdirRequire:
432+
def fake_site_packages(self, tmp_path, monkeypatch, dist_files):
433+
site_packages = tmp_path / "site-packages"
434+
site_packages.mkdir()
435+
for file, content in self.FILES.items():
436+
path = site_packages / file
437+
path.parent.mkdir(exist_ok=True, parents=True)
438+
path.write_text(inspect.cleandoc(content), encoding="utf-8")
439+
440+
monkeypatch.setattr(sys, "path", [site_packages])
441+
return os.fspath(site_packages)
442+
443+
FILES = {
444+
"pkg1_mod-1.2.3.dist-info/METADATA": """
445+
Metadata-Version: 2.4
446+
Name: pkg1.mod
447+
Version: 1.2.3
448+
""",
449+
"pkg2.mod-0.42.dist-info/METADATA": """
450+
Metadata-Version: 2.1
451+
Name: pkg2.mod
452+
Version: 0.42
453+
""",
454+
"pkg3_mod.egg-info/PKG-INFO": """
455+
Name: pkg3.mod
456+
Version: 1.2.3.4
457+
""",
458+
"pkg4.mod.egg-info/PKG-INFO": """
459+
Name: pkg4.mod
460+
Version: 0.42.1
461+
""",
462+
}
463+
464+
@pytest.mark.parametrize(
465+
("version", "requirement"),
466+
[
467+
("1.2.3", "pkg1.mod>=1"),
468+
("0.42", "pkg2.mod>=0.4"),
469+
("1.2.3.4", "pkg3.mod<=2"),
470+
("0.42.1", "pkg4.mod>0.2,<1"),
471+
],
472+
)
473+
def test_require_non_normalised_name(
474+
self, tmp_path, monkeypatch, version, requirement
475+
):
476+
# https://github.com/pypa/setuptools/issues/4853
477+
site_packages = self.fake_site_packages(tmp_path, monkeypatch, self.FILES)
478+
ws = pkg_resources.WorkingSet([site_packages])
479+
480+
for req in [requirement, requirement.replace(".", "-")]:
481+
[dist] = ws.require(req)
482+
assert dist.version == version
483+
assert os.path.samefile(
484+
os.path.commonpath([dist.location, site_packages]), site_packages
485+
)

0 commit comments

Comments
 (0)