Skip to content

Commit

Permalink
Exclude a known incompatible installed candidate
Browse files Browse the repository at this point in the history
The resolver collects previously known incompatibilites and sends them
to the provider. But previously the provider does not correctly exclude
the currently-installed candidate if it is present in that
incompatibility list, causing the resolver to enter a loop trying that
same candidate. This patch correctly applies incompat_ids when producing
an AlreadyInstalledCandidate and exclude it if its id() is in the set.
  • Loading branch information
uranusjr authored and sbidoul committed May 23, 2021
1 parent 1c31d33 commit 729c626
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 13 deletions.
3 changes: 3 additions & 0 deletions news/9841.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
New resolver: Correctly exclude an already installed package if its version is
known to be incompatible to stop the dependency resolution process with a clear
error message.
37 changes: 24 additions & 13 deletions src/pip/_internal/resolution/resolvelib/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,18 +240,29 @@ def _iter_found_candidates(
hashes &= ireq.hashes(trust_internet=False)
extras |= frozenset(ireq.extras)

# Get the installed version, if it matches, unless the user
# specified `--force-reinstall`, when we want the version from
# the index instead.
installed_candidate = None
if not self._force_reinstall and name in self._installed_dists:
installed_dist = self._installed_dists[name]
if specifier.contains(installed_dist.version, prereleases=True):
installed_candidate = self._make_candidate_from_dist(
dist=installed_dist,
extras=extras,
template=template,
)
def _get_installed_candidate() -> Optional[Candidate]:
"""Get the candidate for the currently-installed version."""
# If --force-reinstall is set, we want the version from the index
# instead, so we "pretend" there is nothing installed.
if self._force_reinstall:
return None
try:
installed_dist = self._installed_dists[name]
except KeyError:
return None
# Don't use the installed distribution if its version does not fit
# the current dependency graph.
if not specifier.contains(installed_dist.version, prereleases=True):
return None
candidate = self._make_candidate_from_dist(
dist=installed_dist,
extras=extras,
template=template,
)
# The candidate is a known incompatiblity. Don't use it.
if id(candidate) in incompatible_ids:
return None
return candidate

def iter_index_candidate_infos():
# type: () -> Iterator[IndexCandidateInfo]
Expand Down Expand Up @@ -283,7 +294,7 @@ def iter_index_candidate_infos():

return FoundCandidates(
iter_index_candidate_infos,
installed_candidate,
_get_installed_candidate(),
prefers_installed,
incompatible_ids,
)
Expand Down

0 comments on commit 729c626

Please sign in to comment.