Skip to content

Commit 89b68c6

Browse files
committed
Merge branch 'main' into issue/11924-requirements-on-extras
2 parents 46707a4 + 0827d76 commit 89b68c6

File tree

15 files changed

+182
-56
lines changed

15 files changed

+182
-56
lines changed

.git-blame-ignore-revs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ c7ee560e00b85f7486b452c14ff49e4737996eda # Blacken tools/
3333
1897784d59e0d5fcda2dd75fea54ddd8be3d502a # Blacken src/pip/_internal/index
3434
94999255d5ede440c37137d210666fdf64302e75 # Reformat the codebase, with black
3535
585037a80a1177f1fa92e159a7079855782e543e # Cleanup implicit string concatenation
36+
8a6f6ac19b80a6dc35900a47016c851d9fcd2ee2 # Blacken src/pip/_internal/resolution directory

docs/html/cli/pip_search.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ Usage
2121
Description
2222
===========
2323

24+
.. attention::
25+
PyPI no longer supports ``pip search`` (or XML-RPC search). Please use https://pypi.org/search (via a browser)
26+
instead. See https://warehouse.pypa.io/api-reference/xml-rpc.html#deprecated-methods for more information.
27+
28+
However, XML-RPC search (and this command) may still be supported by indexes other than PyPI.
29+
2430
.. pip-command-description:: search
2531

2632

news/11649.bugfix.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Normalize extras according to :pep:`685` from package metadata in the resolver
2+
for comparison. This ensures extras are correctly compared and merged as long
3+
as the package providing the extra(s) is built with values normalized according
4+
to the standard. Note, however, that this *does not* solve cases where the
5+
package itself contains unnormalized extra values in the metadata.

news/12059.doc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Document that ``pip search`` support has been removed from PyPI

src/pip/_internal/metadata/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .base import BaseDistribution, BaseEnvironment, FilesystemWheel, MemoryWheel, Wheel
1010

1111
if TYPE_CHECKING:
12-
from typing import Protocol
12+
from typing import Literal, Protocol
1313
else:
1414
Protocol = object
1515

@@ -50,6 +50,7 @@ def _should_use_importlib_metadata() -> bool:
5050

5151

5252
class Backend(Protocol):
53+
NAME: 'Literal["importlib", "pkg_resources"]'
5354
Distribution: Type[BaseDistribution]
5455
Environment: Type[BaseEnvironment]
5556

src/pip/_internal/metadata/base.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from pip._vendor.packaging.requirements import Requirement
2626
from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet
27-
from pip._vendor.packaging.utils import NormalizedName
27+
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
2828
from pip._vendor.packaging.version import LegacyVersion, Version
2929

3030
from pip._internal.exceptions import NoneMetadataError
@@ -37,7 +37,6 @@
3737
from pip._internal.utils.compat import stdlib_pkgs # TODO: Move definition here.
3838
from pip._internal.utils.egg_link import egg_link_path_from_sys_path
3939
from pip._internal.utils.misc import is_local, normalize_path
40-
from pip._internal.utils.packaging import safe_extra
4140
from pip._internal.utils.urls import url_to_path
4241

4342
from ._json import msg_to_json
@@ -460,6 +459,19 @@ def iter_provided_extras(self) -> Iterable[str]:
460459
461460
For modern .dist-info distributions, this is the collection of
462461
"Provides-Extra:" entries in distribution metadata.
462+
463+
The return value of this function is not particularly useful other than
464+
display purposes due to backward compatibility issues and the extra
465+
names being poorly normalized prior to PEP 685. If you want to perform
466+
logic operations on extras, use :func:`is_extra_provided` instead.
467+
"""
468+
raise NotImplementedError()
469+
470+
def is_extra_provided(self, extra: str) -> bool:
471+
"""Check whether an extra is provided by this distribution.
472+
473+
This is needed mostly for compatibility issues with pkg_resources not
474+
following the extra normalization rules defined in PEP 685.
463475
"""
464476
raise NotImplementedError()
465477

@@ -537,10 +549,11 @@ def _iter_egg_info_extras(self) -> Iterable[str]:
537549
"""Get extras from the egg-info directory."""
538550
known_extras = {""}
539551
for entry in self._iter_requires_txt_entries():
540-
if entry.extra in known_extras:
552+
extra = canonicalize_name(entry.extra)
553+
if extra in known_extras:
541554
continue
542-
known_extras.add(entry.extra)
543-
yield entry.extra
555+
known_extras.add(extra)
556+
yield extra
544557

545558
def _iter_egg_info_dependencies(self) -> Iterable[str]:
546559
"""Get distribution dependencies from the egg-info directory.
@@ -556,10 +569,11 @@ def _iter_egg_info_dependencies(self) -> Iterable[str]:
556569
all currently available PEP 517 backends, although not standardized.
557570
"""
558571
for entry in self._iter_requires_txt_entries():
559-
if entry.extra and entry.marker:
560-
marker = f'({entry.marker}) and extra == "{safe_extra(entry.extra)}"'
561-
elif entry.extra:
562-
marker = f'extra == "{safe_extra(entry.extra)}"'
572+
extra = canonicalize_name(entry.extra)
573+
if extra and entry.marker:
574+
marker = f'({entry.marker}) and extra == "{extra}"'
575+
elif extra:
576+
marker = f'extra == "{extra}"'
563577
elif entry.marker:
564578
marker = entry.marker
565579
else:
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from ._dists import Distribution
22
from ._envs import Environment
33

4-
__all__ = ["Distribution", "Environment"]
4+
__all__ = ["NAME", "Distribution", "Environment"]
5+
6+
NAME = "importlib"

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
Wheel,
2828
)
2929
from pip._internal.utils.misc import normalize_path
30-
from pip._internal.utils.packaging import safe_extra
3130
from pip._internal.utils.temp_dir import TempDirectory
3231
from pip._internal.utils.wheel import parse_wheel, read_wheel_metadata_file
3332

@@ -208,12 +207,16 @@ def _metadata_impl(self) -> email.message.Message:
208207
return cast(email.message.Message, self._dist.metadata)
209208

210209
def iter_provided_extras(self) -> Iterable[str]:
211-
return (
212-
safe_extra(extra) for extra in self.metadata.get_all("Provides-Extra", [])
210+
return self.metadata.get_all("Provides-Extra", [])
211+
212+
def is_extra_provided(self, extra: str) -> bool:
213+
return any(
214+
canonicalize_name(provided_extra) == canonicalize_name(extra)
215+
for provided_extra in self.metadata.get_all("Provides-Extra", [])
213216
)
214217

215218
def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]:
216-
contexts: Sequence[Dict[str, str]] = [{"extra": safe_extra(e)} for e in extras]
219+
contexts: Sequence[Dict[str, str]] = [{"extra": e} for e in extras]
217220
for req_string in self.metadata.get_all("Requires-Dist", []):
218221
req = Requirement(req_string)
219222
if not req.marker:

src/pip/_internal/metadata/pkg_resources.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@
2424
Wheel,
2525
)
2626

27+
__all__ = ["NAME", "Distribution", "Environment"]
28+
2729
logger = logging.getLogger(__name__)
2830

31+
NAME = "pkg_resources"
32+
2933

3034
class EntryPoint(NamedTuple):
3135
name: str
@@ -212,12 +216,16 @@ def _metadata_impl(self) -> email.message.Message:
212216

213217
def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]:
214218
if extras: # pkg_resources raises on invalid extras, so we sanitize.
215-
extras = frozenset(extras).intersection(self._dist.extras)
219+
extras = frozenset(pkg_resources.safe_extra(e) for e in extras)
220+
extras = extras.intersection(self._dist.extras)
216221
return self._dist.requires(extras)
217222

218223
def iter_provided_extras(self) -> Iterable[str]:
219224
return self._dist.extras
220225

226+
def is_extra_provided(self, extra: str) -> bool:
227+
return pkg_resources.safe_extra(extra) in self._dist.extras
228+
221229

222230
class Environment(BaseEnvironment):
223231
def __init__(self, ws: pkg_resources.WorkingSet) -> None:

src/pip/_internal/req/req_install.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def __init__(
128128
if extras:
129129
self.extras = extras
130130
elif req:
131-
self.extras = {safe_extra(extra) for extra in req.extras}
131+
self.extras = req.extras
132132
else:
133133
self.extras = set()
134134
if markers is None and req:
@@ -272,7 +272,12 @@ def match_markers(self, extras_requested: Optional[Iterable[str]] = None) -> boo
272272
extras_requested = ("",)
273273
if self.markers is not None:
274274
return any(
275-
self.markers.evaluate({"extra": extra}) for extra in extras_requested
275+
self.markers.evaluate({"extra": extra})
276+
# TODO: Remove these two variants when packaging is upgraded to
277+
# support the marker comparison logic specified in PEP 685.
278+
or self.markers.evaluate({"extra": safe_extra(extra)})
279+
or self.markers.evaluate({"extra": canonicalize_name(extra)})
280+
for extra in extras_requested
276281
)
277282
else:
278283
return True

0 commit comments

Comments
 (0)