Skip to content

Commit dc8f3a8

Browse files
authored
Merge pull request #11353 from uranusjr/importlib-metadata-ignore-bad-name
2 parents 1880f4a + 6817fbf commit dc8f3a8

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

news/11352.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Ignore distributions with invalid ``Name`` in metadata instead of crashing, when
2+
using the ``importlib.metadata`` backend.

src/pip/_internal/metadata/importlib/_compat.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
from typing import Any, Optional, Protocol, cast
33

44

5+
class BadMetadata(ValueError):
6+
def __init__(self, dist: importlib.metadata.Distribution, *, reason: str) -> None:
7+
self.dist = dist
8+
self.reason = reason
9+
10+
def __str__(self) -> str:
11+
return f"Bad metadata in {self.dist} ({self.reason})"
12+
13+
514
class BasePath(Protocol):
615
"""A protocol that various path objects conform.
716
@@ -40,4 +49,7 @@ def get_dist_name(dist: importlib.metadata.Distribution) -> str:
4049
The ``name`` attribute is only available in Python 3.10 or later. We are
4150
targeting exactly that, but Mypy does not know this.
4251
"""
43-
return cast(Any, dist).name
52+
name = cast(Any, dist).name
53+
if not isinstance(name, str):
54+
raise BadMetadata(dist, reason="invalid metadata entry 'name'")
55+
return name

src/pip/_internal/metadata/importlib/_envs.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import functools
22
import importlib.metadata
3+
import logging
34
import os
45
import pathlib
56
import sys
@@ -14,9 +15,11 @@
1415
from pip._internal.utils.deprecation import deprecated
1516
from pip._internal.utils.filetypes import WHEEL_EXTENSION
1617

17-
from ._compat import BasePath, get_dist_name, get_info_location
18+
from ._compat import BadMetadata, BasePath, get_dist_name, get_info_location
1819
from ._dists import Distribution
1920

21+
logger = logging.getLogger(__name__)
22+
2023

2124
def _looks_like_wheel(location: str) -> bool:
2225
if not location.endswith(WHEEL_EXTENSION):
@@ -56,11 +59,16 @@ def _find_impl(self, location: str) -> Iterator[FoundResult]:
5659
# To know exactly where we find a distribution, we have to feed in the
5760
# paths one by one, instead of dumping the list to importlib.metadata.
5861
for dist in importlib.metadata.distributions(path=[location]):
59-
normalized_name = canonicalize_name(get_dist_name(dist))
62+
info_location = get_info_location(dist)
63+
try:
64+
raw_name = get_dist_name(dist)
65+
except BadMetadata as e:
66+
logger.warning("Skipping %s due to %s", info_location, e.reason)
67+
continue
68+
normalized_name = canonicalize_name(raw_name)
6069
if normalized_name in self._found_names:
6170
continue
6271
self._found_names.add(normalized_name)
63-
info_location = get_info_location(dist)
6472
yield dist, info_location
6573

6674
def find(self, location: str) -> Iterator[BaseDistribution]:

0 commit comments

Comments
 (0)