Skip to content

Commit

Permalink
Implement extra-ed requirement merging
Browse files Browse the repository at this point in the history
When a requirement is requested multiple times, some via a direct URL
("req @ URL") and some not but with extras ("req[extra] VERSION"), the
resolver previous could not correctly find "req[extra]" if "req" is
available in an index.

This additional logic makes the resolver, when encountering a
requirement with identifier "req[extra]", to also look for explicit
candidates listed under "req", and add them as found matches for
"req[extra]".
  • Loading branch information
uranusjr committed Apr 4, 2021
1 parent cbc9f53 commit f8b84c7
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 0 deletions.
4 changes: 4 additions & 0 deletions news/8785.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
New resolver: When a requirement is requested both via a direct URL
(``req @ URL``) and via version specifier with extras (``req[extra]``), the
resolver will now be able to use the URL to correctly resolve the requirement
with extras.
22 changes: 22 additions & 0 deletions src/pip/_internal/resolution/resolvelib/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
cast,
)

from pip._vendor.packaging.requirements import (
InvalidRequirement,
Requirement as PackagingRequirement,
)
from pip._vendor.packaging.specifiers import SpecifierSet
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
from pip._vendor.pkg_resources import Distribution
Expand Down Expand Up @@ -296,6 +300,24 @@ def find_candidates(
if ireq is not None:
ireqs.append(ireq)

# If the current identifier contains extras, also add explicit
# candidates from entries from extra-less identifier.
try:
identifier_req = PackagingRequirement(identifier)
except InvalidRequirement:
base_identifier = None
extras = frozenset()
else:
base_identifier = identifier_req.name
extras = frozenset(identifier_req.extras)
if base_identifier and base_identifier in requirements:
for req in requirements[base_identifier]:
base_cand, _ = req.get_candidate_lookup()
if base_cand is None:
continue
candidate = self._make_extras_candidate(base_cand, extras)
explicit_candidates.add(candidate)

# If none of the requirements want an explicit candidate, we can ask
# the finder for candidates.
if not explicit_candidates:
Expand Down

0 comments on commit f8b84c7

Please sign in to comment.