diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py index 6290d2fe31f214f1e275fbb2e782256db5b5b2b0..f29b9692bd210c4d80270812827ce21d6eef5c65 100644 --- a/src/pip/_internal/resolution/resolvelib/resolver.py +++ b/src/pip/_internal/resolution/resolvelib/resolver.py @@ -134,23 +134,31 @@ class Resolver(BaseResolver): # and set a flag for later stages to uninstall it, if needed. # # * There is no existing installation. Nothing to uninstall. - # * The candidate is a local path/file. Always reinstall. # * The --force-reinstall flag is set. Always reinstall. # * The installation is different in version or editable-ness, so # we need to uninstall it to install the new distribution. - # * The installed version is the same as the pending distribution. - # Skip this distribution altogether to save work. + # * The installed version is different from the pending distribution. + # * The candidate is a local wheel. Do nothing. + # * The candidate is a local path. Always reinstall. installed_dist = self.factory.get_dist_to_uninstall(candidate) if installed_dist is None: ireq.should_reinstall = False - elif candidate.source_link.is_file: - ireq.should_reinstall = True elif self.factory.force_reinstall: ireq.should_reinstall = True elif installed_dist.parsed_version != candidate.version: ireq.should_reinstall = True elif dist_is_editable(installed_dist) != candidate.is_editable: ireq.should_reinstall = True + elif candidate.source_link.is_file: + if candidate.source_link.is_wheel: + logger.info( + "%s is already installed with the same version as the " + "provided wheel. Use --force-reinstall to force an " + "installation of the wheel.", + ireq.name, + ) + continue + ireq.should_reinstall = True else: continue diff --git a/tests/functional/test_new_resolver.py b/tests/functional/test_new_resolver.py index 211f0c58b70bc87e48f7370cd0604ea746558162..a26786c89aa6ab99ff605d657b9b896bbc945a5d 100644 --- a/tests/functional/test_new_resolver.py +++ b/tests/functional/test_new_resolver.py @@ -1152,51 +1152,28 @@ def test_new_resolver_check_wheel_version_normalized( assert_installed(script, simple="0.1.0+local.1") -def test_new_resolver_contraint_on_dep_with_extra(script): - create_basic_wheel_for_package( - script, - name="simple", - version="1", - depends=["dep[x]"], - ) - create_basic_wheel_for_package( - script, - name="dep", - version="1", - extras={"x": ["depx==1"]}, - ) - create_basic_wheel_for_package( - script, - name="dep", - version="2", - extras={"x": ["depx==2"]}, - ) - create_basic_wheel_for_package( +def test_new_resolver_does_not_reinstall_local_wheels(script): + archive_path = create_basic_wheel_for_package( script, - name="depx", - version="1", + "pkg", + "1.0", ) - create_basic_wheel_for_package( - script, - name="depx", - version="2", + script.pip( + "install", "--no-cache-dir", "--no-index", + archive_path, ) + assert_installed(script, pkg="1.0") - constraints_txt = script.scratch_path / "constraints.txt" - constraints_txt.write_text("dep==1") - - script.pip( - "install", - "--no-cache-dir", "--no-index", - "--find-links", script.scratch_path, - "--constraint", constraints_txt, - "simple", + result = script.pip( + "install", "--no-cache-dir", "--no-index", + archive_path, ) - assert_installed(script, simple="1", dep="1", depx="1") + assert "Installing collected packages: pkg" not in result.stdout, str(result) + assert_installed(script, pkg="1.0") -def test_new_resolver_does_reinstall_local_wheels(script): - archive_path = create_basic_wheel_for_package( +def test_new_resolver_does_reinstall_local_sdists(script): + archive_path = create_basic_sdist_for_package( script, "pkg", "1.0", @@ -1236,7 +1213,7 @@ def test_new_resolver_does_reinstall_local_paths(script): def test_new_resolver_does_not_reinstall_when_from_a_local_index(script): - create_basic_wheel_for_package( + create_basic_sdist_for_package( script, "simple", "0.1.0",