mirror of https://github.com/pypa/pip
Merge pull request #9993
from uranusjr/exclude-installed-candidate-if-incompatible
This commit is contained in:
commit
cb301333b7
|
@ -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.
|
|
@ -240,18 +240,29 @@ class Factory:
|
|||
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]
|
||||
|
@ -283,7 +294,7 @@ class Factory:
|
|||
|
||||
return FoundCandidates(
|
||||
iter_index_candidate_infos,
|
||||
installed_candidate,
|
||||
_get_installed_candidate(),
|
||||
prefers_installed,
|
||||
incompatible_ids,
|
||||
)
|
||||
|
|
|
@ -1827,3 +1827,33 @@ def test_new_resolver_direct_url_with_extras(tmp_path, script):
|
|||
assert not get_created_direct_url(result, "pkg1")
|
||||
assert get_created_direct_url(result, "pkg2")
|
||||
assert not get_created_direct_url(result, "pkg3")
|
||||
|
||||
|
||||
def test_new_resolver_modifies_installed_incompatible(script):
|
||||
create_basic_wheel_for_package(script, name="a", version="1")
|
||||
create_basic_wheel_for_package(script, name="a", version="2")
|
||||
create_basic_wheel_for_package(script, name="a", version="3")
|
||||
create_basic_wheel_for_package(script, name="b", version="1", depends=["a==1"])
|
||||
create_basic_wheel_for_package(script, name="b", version="2", depends=["a==2"])
|
||||
create_basic_wheel_for_package(script, name="c", version="1", depends=["a!=1"])
|
||||
create_basic_wheel_for_package(script, name="c", version="2", depends=["a!=1"])
|
||||
create_basic_wheel_for_package(script, name="d", version="1", depends=["b", "c"])
|
||||
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-cache-dir", "--no-index",
|
||||
"--find-links", script.scratch_path,
|
||||
"b==1",
|
||||
)
|
||||
|
||||
# d-1 depends on b and c. b-1 is already installed and therefore first
|
||||
# pinned, but later found to be incompatible since the "a==1" dependency
|
||||
# makes all c versions impossible to satisfy. The resolver should be able to
|
||||
# discard b-1 and backtrack, so b-2 is selected instead.
|
||||
script.pip(
|
||||
"install",
|
||||
"--no-cache-dir", "--no-index",
|
||||
"--find-links", script.scratch_path,
|
||||
"d==1",
|
||||
)
|
||||
assert_installed(script, d="1", c="2", b="2", a="2")
|
||||
|
|
Loading…
Reference in New Issue