From 22c094eff724a27bcdbc5d4aa722f1c5baf32759 Mon Sep 17 00:00:00 2001 From: Shmulik Cohen <34924662+anuk909@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:56:07 +0200 Subject: [PATCH 1/7] Fix warning message for missing METADATA file Fixes #12446 Update the warning message for missing `METADATA` file in dist-info directories. * Update the warning message in `src/pip/_internal/metadata/importlib/_compat.py` to differentiate between a missing `METADATA` file and other metadata issues. * Add a check for the existence of the `METADATA` file in the `get_dist_canonical_name` function. * Add a test case in `tests/functional/test_list.py` to verify the new warning message for a missing `METADATA` file. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/pypa/pip/issues/12446?shareId=XXXX-XXXX-XXXX-XXXX). --- src/pip/_internal/metadata/importlib/_compat.py | 3 +++ tests/functional/test_list.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/pip/_internal/metadata/importlib/_compat.py b/src/pip/_internal/metadata/importlib/_compat.py index ec1e815cdbd..8ebf0f9b07b 100644 --- a/src/pip/_internal/metadata/importlib/_compat.py +++ b/src/pip/_internal/metadata/importlib/_compat.py @@ -81,5 +81,8 @@ def get_dist_canonical_name(dist: importlib.metadata.Distribution) -> Normalized name = cast(Any, dist).name if not isinstance(name, str): + info_location = get_info_location(dist) + if info_location and not info_location.joinpath("METADATA").exists(): + raise BadMetadata(dist, reason="missing `METADATA` file") raise BadMetadata(dist, reason="invalid metadata entry 'name'") return canonicalize_name(name) diff --git a/tests/functional/test_list.py b/tests/functional/test_list.py index e611fe7cb64..fb510e829fc 100644 --- a/tests/functional/test_list.py +++ b/tests/functional/test_list.py @@ -751,3 +751,19 @@ def test_list_pep610_editable(script: PipTestEnvironment) -> None: break else: pytest.fail("package 'testpkg' not found in pip list result") + + +def test_list_missing_metadata_warning(script: PipTestEnvironment) -> None: + """ + Test that a warning is shown when a dist-info directory is missing the METADATA file. + """ + # Create a test package and create .dist-info dir without METADATA file + pkg_path = create_test_package_with_setup(script, name="testpkg", version="1.0") + dist_info_path = pkg_path / "testpkg-1.0.dist-info" + dist_info_path.mkdir() + dist_info_path.joinpath("RECORD").write_text("") + + # List should show a warning about the missing METADATA file + result = script.pip("list", expect_stderr=True) + assert "WARNING: Skipping" in result.stderr + assert "due to invalid dist-info directory: missing `METADATA` file" in result.stderr From fcc0cd183531dcd58845281d99ce77381a580c89 Mon Sep 17 00:00:00 2001 From: Shmulik Cohen <34924662+anuk909@users.noreply.github.com> Date: Wed, 18 Dec 2024 23:27:30 +0200 Subject: [PATCH 2/7] Update `BadMetadata` warning message and add `METADATA` file check * **`src/pip/_internal/metadata/importlib/_compat.py`** - Add `joinpath` method to `BasePath` class. * **`news/12446.bugfix.rst`** - Document changes made to fix the issue. --- CHANGELOG.md | 6 ++++++ news/12446.bugfix.rst | 3 +++ src/pip/_internal/metadata/importlib/_compat.py | 3 +++ 3 files changed, 12 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 news/12446.bugfix.rst diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000000..b4ec4723a5e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + +## [Unreleased] + +### Changed +- Updated warning message for invalid dist-info directory due to missing `METADATA` file. diff --git a/news/12446.bugfix.rst b/news/12446.bugfix.rst new file mode 100644 index 00000000000..2335f5136e1 --- /dev/null +++ b/news/12446.bugfix.rst @@ -0,0 +1,3 @@ +* Updated warning message for invalid dist-info directory due to missing `METADATA` file. +* Added a check for the existence of the `METADATA` file in the `get_dist_canonical_name` function. +* Added a test case to verify the new warning message for a missing `METADATA` file. diff --git a/src/pip/_internal/metadata/importlib/_compat.py b/src/pip/_internal/metadata/importlib/_compat.py index 8ebf0f9b07b..e4251f58539 100644 --- a/src/pip/_internal/metadata/importlib/_compat.py +++ b/src/pip/_internal/metadata/importlib/_compat.py @@ -33,6 +33,9 @@ def name(self) -> str: def parent(self) -> "BasePath": raise NotImplementedError() + def joinpath(self, *other) -> "BasePath": + raise NotImplementedError() + def get_info_location(d: importlib.metadata.Distribution) -> Optional[BasePath]: """Find the path to the distribution's metadata directory. From 93c5f6431ad076fe0efbf08f93ed6df270117f64 Mon Sep 17 00:00:00 2001 From: Shmulik Cohen <34924662+anuk909@users.noreply.github.com> Date: Wed, 18 Dec 2024 23:27:57 +0200 Subject: [PATCH 3/7] Delete CHANGELOG.md --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b4ec4723a5e..00000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,6 +0,0 @@ -# Changelog - -## [Unreleased] - -### Changed -- Updated warning message for invalid dist-info directory due to missing `METADATA` file. From cae9fa07d2a2f2d3c239b0c352a6419742eb7595 Mon Sep 17 00:00:00 2001 From: Shmulik Cohen Date: Thu, 19 Dec 2024 00:20:58 +0200 Subject: [PATCH 4/7] mypy --- src/pip/_internal/metadata/importlib/_compat.py | 9 ++++++--- src/pip/_internal/metadata/importlib/_dists.py | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/pip/_internal/metadata/importlib/_compat.py b/src/pip/_internal/metadata/importlib/_compat.py index e4251f58539..94dd648cfba 100644 --- a/src/pip/_internal/metadata/importlib/_compat.py +++ b/src/pip/_internal/metadata/importlib/_compat.py @@ -1,6 +1,6 @@ import importlib.metadata import os -from typing import Any, Optional, Protocol, Tuple, cast +from typing import Any, Optional, Protocol, Tuple, Union, cast from pip._vendor.packaging.utils import NormalizedName, canonicalize_name @@ -33,7 +33,10 @@ def name(self) -> str: def parent(self) -> "BasePath": raise NotImplementedError() - def joinpath(self, *other) -> "BasePath": + def joinpath(self, *args: Union[str, os.PathLike[str]]) -> "BasePath": + raise NotImplementedError() + + def exists(self) -> bool: raise NotImplementedError() @@ -85,7 +88,7 @@ def get_dist_canonical_name(dist: importlib.metadata.Distribution) -> Normalized name = cast(Any, dist).name if not isinstance(name, str): info_location = get_info_location(dist) - if info_location and not info_location.joinpath("METADATA").exists(): + if info_location and not info_location.joinpath("METADATA"): raise BadMetadata(dist, reason="missing `METADATA` file") raise BadMetadata(dist, reason="invalid metadata entry 'name'") return canonicalize_name(name) diff --git a/src/pip/_internal/metadata/importlib/_dists.py b/src/pip/_internal/metadata/importlib/_dists.py index 5e92b12755e..b42b5c166a1 100644 --- a/src/pip/_internal/metadata/importlib/_dists.py +++ b/src/pip/_internal/metadata/importlib/_dists.py @@ -10,7 +10,7 @@ Mapping, Optional, Sequence, - cast, + Union, ) from pip._vendor.packaging.requirements import Requirement @@ -100,8 +100,8 @@ class Distribution(BaseDistribution): def __init__( self, dist: importlib.metadata.Distribution, - info_location: Optional[BasePath], - installed_location: Optional[BasePath], + info_location: Optional[Union[BasePath, pathlib.PurePosixPath]], + installed_location: Optional[Union[BasePath, pathlib.PurePosixPath]], ) -> None: self._dist = dist self._info_location = info_location @@ -199,7 +199,7 @@ def _metadata_impl(self) -> email.message.Message: # a ton of fields that we need, including get() and get_payload(). We # rely on the implementation that the object is actually a Message now, # until upstream can improve the protocol. (python/cpython#94952) - return cast(email.message.Message, self._dist.metadata) + return self._dist.metadata def iter_provided_extras(self) -> Iterable[NormalizedName]: return [ From cce5a5f7d87998cf06ae86d783d8f0c21e8dcbbb Mon Sep 17 00:00:00 2001 From: Shmulik Cohen Date: Thu, 19 Dec 2024 00:24:42 +0200 Subject: [PATCH 5/7] return cast --- src/pip/_internal/metadata/importlib/_dists.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pip/_internal/metadata/importlib/_dists.py b/src/pip/_internal/metadata/importlib/_dists.py index b42b5c166a1..863131d4561 100644 --- a/src/pip/_internal/metadata/importlib/_dists.py +++ b/src/pip/_internal/metadata/importlib/_dists.py @@ -11,6 +11,7 @@ Optional, Sequence, Union, + cast, ) from pip._vendor.packaging.requirements import Requirement @@ -199,7 +200,7 @@ def _metadata_impl(self) -> email.message.Message: # a ton of fields that we need, including get() and get_payload(). We # rely on the implementation that the object is actually a Message now, # until upstream can improve the protocol. (python/cpython#94952) - return self._dist.metadata + return cast(email.message.Message, self._dist.metadata) def iter_provided_extras(self) -> Iterable[NormalizedName]: return [ From d80044899e304790421b91213232f21ca68a8665 Mon Sep 17 00:00:00 2001 From: Shmulik Cohen Date: Thu, 19 Dec 2024 00:27:41 +0200 Subject: [PATCH 6/7] format --- tests/functional/test_list.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/functional/test_list.py b/tests/functional/test_list.py index fb510e829fc..dfcb45743c8 100644 --- a/tests/functional/test_list.py +++ b/tests/functional/test_list.py @@ -755,7 +755,8 @@ def test_list_pep610_editable(script: PipTestEnvironment) -> None: def test_list_missing_metadata_warning(script: PipTestEnvironment) -> None: """ - Test that a warning is shown when a dist-info directory is missing the METADATA file. + Test that a warning is shown when a dist-info directory is missing the + METADATA file. """ # Create a test package and create .dist-info dir without METADATA file pkg_path = create_test_package_with_setup(script, name="testpkg", version="1.0") @@ -766,4 +767,6 @@ def test_list_missing_metadata_warning(script: PipTestEnvironment) -> None: # List should show a warning about the missing METADATA file result = script.pip("list", expect_stderr=True) assert "WARNING: Skipping" in result.stderr - assert "due to invalid dist-info directory: missing `METADATA` file" in result.stderr + assert ( + "due to invalid dist-info directory: missing `METADATA` file" in result.stderr + ) From 03808ad7eba42de83dfe4b52ad2b73f482f5192e Mon Sep 17 00:00:00 2001 From: Shmulik Cohen Date: Thu, 19 Dec 2024 00:30:23 +0200 Subject: [PATCH 7/7] update news file --- news/12446.bugfix.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/news/12446.bugfix.rst b/news/12446.bugfix.rst index 2335f5136e1..a18672d33d8 100644 --- a/news/12446.bugfix.rst +++ b/news/12446.bugfix.rst @@ -1,3 +1 @@ -* Updated warning message for invalid dist-info directory due to missing `METADATA` file. -* Added a check for the existence of the `METADATA` file in the `get_dist_canonical_name` function. -* Added a test case to verify the new warning message for a missing `METADATA` file. +Updated warning message for invalid dist-info directory due to missing METADATA file.