From 79d6e46d4949a77238ca8884ed8137d5d6175d31 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 26 Feb 2025 16:14:11 +0000 Subject: [PATCH 1/7] Add regression test for issue 4853 --- pkg_resources/tests/test_pkg_resources.py | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 0f696e8502..73a9a652a0 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -2,6 +2,7 @@ import builtins import datetime +import inspect import os import plistlib import stat @@ -425,3 +426,56 @@ def test_normalize_path_backslash_sep(self, unnormalized, expected): """Ensure path seps are cleaned on backslash path sep systems.""" result = pkg_resources.normalize_path(unnormalized) assert result.endswith(expected) + + +class TestWorkdirRequire: + def fake_site_packages(self, tmp_path, monkeypatch, dist_files): + site_packages = tmp_path / "site-packages" + site_packages.mkdir() + for file, content in self.FILES.items(): + path = site_packages / file + path.parent.mkdir(exist_ok=True, parents=True) + path.write_text(inspect.cleandoc(content), encoding="utf-8") + + monkeypatch.setattr(sys, "path", [site_packages]) + return os.fspath(site_packages) + + FILES = { + "pkg1_mod-1.2.3.dist-info/METADATA": """ + Metadata-Version: 2.4 + Name: pkg1.mod + Version: 1.2.3 + """, + "pkg2.mod-0.42.dist-info/METADATA": """ + Metadata-Version: 2.1 + Name: pkg2.mod + Version: 0.42 + """, + "pkg3_mod.egg-info/PKG-INFO": """ + Name: pkg3.mod + Version: 1.2.3 + """, + "pkg4.mod.egg-info/PKG-INFO": """ + Name: pkg4.mod + Version: 0.42 + """, + } + + @pytest.mark.parametrize( + ("name", "version", "req"), + [ + ("pkg1.mod", "1.2.3", "pkg1.mod>=1"), + ("pkg2.mod", "0.42", "pkg2.mod>=0.4"), + ("pkg3.mod", "1.2.3", "pkg3.mod<=2"), + ("pkg4.mod", "0.42", "pkg4.mod>0.2,<1"), + ], + ) + def test_require_normalised_name(self, tmp_path, monkeypatch, name, version, req): + # https://github.com/pypa/setuptools/issues/4853 + site_packages = self.fake_site_packages(tmp_path, monkeypatch, self.FILES) + ws = pkg_resources.WorkingSet([site_packages]) + + [dist] = ws.require(req) + assert dist.version == version + assert dist.project_name == name + assert os.path.commonpath([dist.location, site_packages]) == site_packages From 2c242238f536c4b942812632ba9dd0b1c48b4b85 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 26 Feb 2025 16:46:33 +0000 Subject: [PATCH 2/7] Update WorkingSet.find to consider standardised dist-info names --- pkg_resources/__init__.py | 17 +++++++++-------- pkg_resources/tests/test_pkg_resources.py | 1 - 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 68feeb0593..6d90e7906d 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -708,14 +708,15 @@ def find(self, req: Requirement) -> Distribution | None: If there is no active distribution for the requested project, ``None`` 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) + for candidate in ( + req.key, + self.normalized_to_canonical_keys.get(req.key), + safe_name(req.key).replace(".", "-"), + ): + dist = self.by_key.get(candidate) + if dist: + req.key = candidate + break if dist is not None and dist not in req: # XXX add more info diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 73a9a652a0..c749128449 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -477,5 +477,4 @@ def test_require_normalised_name(self, tmp_path, monkeypatch, name, version, req [dist] = ws.require(req) assert dist.version == version - assert dist.project_name == name assert os.path.commonpath([dist.location, site_packages]) == site_packages From 23b73aaef2cb95650a997f80ea74c8d51bc5f01c Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 26 Feb 2025 17:00:44 +0000 Subject: [PATCH 3/7] Fix mypy errors --- pkg_resources/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 6d90e7906d..8a2fbfa412 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -708,11 +708,15 @@ def find(self, req: Requirement) -> Distribution | None: If there is no active distribution for the requested project, ``None`` is returned. """ - for candidate in ( + dist: Distribution | None = None + + candidates = ( req.key, self.normalized_to_canonical_keys.get(req.key), safe_name(req.key).replace(".", "-"), - ): + ) + + for candidate in filter(None, candidates): dist = self.by_key.get(candidate) if dist: req.key = candidate From a3718c8099235fb3b40d013f97530d5aeb5ba0ce Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 26 Feb 2025 17:07:20 +0000 Subject: [PATCH 4/7] Slightly change test, so that we are sure about the correct distribution being found --- pkg_resources/tests/test_pkg_resources.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index c749128449..2d54cfb5ce 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -453,11 +453,11 @@ def fake_site_packages(self, tmp_path, monkeypatch, dist_files): """, "pkg3_mod.egg-info/PKG-INFO": """ Name: pkg3.mod - Version: 1.2.3 + Version: 1.2.3.4 """, "pkg4.mod.egg-info/PKG-INFO": """ Name: pkg4.mod - Version: 0.42 + Version: 0.42.1 """, } @@ -466,8 +466,8 @@ def fake_site_packages(self, tmp_path, monkeypatch, dist_files): [ ("pkg1.mod", "1.2.3", "pkg1.mod>=1"), ("pkg2.mod", "0.42", "pkg2.mod>=0.4"), - ("pkg3.mod", "1.2.3", "pkg3.mod<=2"), - ("pkg4.mod", "0.42", "pkg4.mod>0.2,<1"), + ("pkg3.mod", "1.2.3.4", "pkg3.mod<=2"), + ("pkg4.mod", "0.42.1", "pkg4.mod>0.2,<1"), ], ) def test_require_normalised_name(self, tmp_path, monkeypatch, name, version, req): From 8280e2c4fc2f32a5da1ec3ba322c534e2f5369a3 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 26 Feb 2025 18:27:06 +0000 Subject: [PATCH 5/7] Attempt to solve path normalisation issue in windows tests --- pkg_resources/tests/test_pkg_resources.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 2d54cfb5ce..d378079f94 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -477,4 +477,6 @@ def test_require_normalised_name(self, tmp_path, monkeypatch, name, version, req [dist] = ws.require(req) assert dist.version == version - assert os.path.commonpath([dist.location, site_packages]) == site_packages + assert os.path.samefile( + os.path.commonpath([dist.location, site_packages]), site_packages + ) From 22355fcb3337317d4f6ca675aa60947692c9af3a Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 26 Feb 2025 19:56:25 +0000 Subject: [PATCH 6/7] Also consider '-' separator in tests --- pkg_resources/tests/test_pkg_resources.py | 25 +++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index d378079f94..cfc9b16c0f 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -462,21 +462,24 @@ def fake_site_packages(self, tmp_path, monkeypatch, dist_files): } @pytest.mark.parametrize( - ("name", "version", "req"), + ("version", "requirement"), [ - ("pkg1.mod", "1.2.3", "pkg1.mod>=1"), - ("pkg2.mod", "0.42", "pkg2.mod>=0.4"), - ("pkg3.mod", "1.2.3.4", "pkg3.mod<=2"), - ("pkg4.mod", "0.42.1", "pkg4.mod>0.2,<1"), + ("1.2.3", "pkg1.mod>=1"), + ("0.42", "pkg2.mod>=0.4"), + ("1.2.3.4", "pkg3.mod<=2"), + ("0.42.1", "pkg4.mod>0.2,<1"), ], ) - def test_require_normalised_name(self, tmp_path, monkeypatch, name, version, req): + def test_require_non_normalised_name( + self, tmp_path, monkeypatch, version, requirement + ): # https://github.com/pypa/setuptools/issues/4853 site_packages = self.fake_site_packages(tmp_path, monkeypatch, self.FILES) ws = pkg_resources.WorkingSet([site_packages]) - [dist] = ws.require(req) - assert dist.version == version - assert os.path.samefile( - os.path.commonpath([dist.location, site_packages]), site_packages - ) + for req in [requirement, requirement.replace(".", "-")]: + [dist] = ws.require(req) + assert dist.version == version + assert os.path.samefile( + os.path.commonpath([dist.location, site_packages]), site_packages + ) From edca1811df4daa15d18eb06d0dd5da11eda8b3af Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 26 Feb 2025 20:04:33 +0000 Subject: [PATCH 7/7] Add news fragment --- newsfragments/4856.bugfix.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 newsfragments/4856.bugfix.rst diff --git a/newsfragments/4856.bugfix.rst b/newsfragments/4856.bugfix.rst new file mode 100644 index 0000000000..ad0087ea00 --- /dev/null +++ b/newsfragments/4856.bugfix.rst @@ -0,0 +1,2 @@ +Fixed ``pkg_resources.require(...)`` to also consider standardised +``dist-info`` directories.