Skip to content

Commit 864e2ee

Browse files
committed
Merge pull request #8659 from uranusjr/fix-get-distribution-dot-in-name
Canonicalize name in check_if_exists
1 parent ed205bd commit 864e2ee

File tree

3 files changed

+44
-19
lines changed

3 files changed

+44
-19
lines changed

news/8645.bugfix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Correctly find already-installed distributions with dot (``.``) in the name
2+
and uninstall them when needed.

src/pip/_internal/req/req_install.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -429,25 +429,13 @@ def check_if_exists(self, use_user_site):
429429
"""
430430
if self.req is None:
431431
return
432-
# get_distribution() will resolve the entire list of requirements
433-
# anyway, and we've already determined that we need the requirement
434-
# in question, so strip the marker so that we don't try to
435-
# evaluate it.
436-
no_marker = Requirement(str(self.req))
437-
no_marker.marker = None
438-
439-
# pkg_resources uses the canonical name to look up packages, but
440-
# the name passed passed to get_distribution is not canonicalized
441-
# so we have to explicitly convert it to a canonical name
442-
no_marker.name = canonicalize_name(no_marker.name)
443-
try:
444-
self.satisfied_by = pkg_resources.get_distribution(str(no_marker))
445-
except pkg_resources.DistributionNotFound:
432+
existing_dist = get_distribution(self.req.name)
433+
if not existing_dist:
446434
return
447-
except pkg_resources.VersionConflict:
448-
existing_dist = get_distribution(
449-
self.req.name
450-
)
435+
436+
existing_version = existing_dist.parsed_version
437+
if not self.req.specifier.contains(existing_version, prereleases=True):
438+
self.satisfied_by = None
451439
if use_user_site:
452440
if dist_in_usersite(existing_dist):
453441
self.should_reinstall = True
@@ -461,11 +449,13 @@ def check_if_exists(self, use_user_site):
461449
else:
462450
self.should_reinstall = True
463451
else:
464-
if self.editable and self.satisfied_by:
452+
if self.editable:
465453
self.should_reinstall = True
466454
# when installing editables, nothing pre-existing should ever
467455
# satisfy
468456
self.satisfied_by = None
457+
else:
458+
self.satisfied_by = existing_dist
469459

470460
# Things valid for wheels
471461
@property

tests/functional/test_install_upgrade.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import itertools
12
import os
23
import sys
34
import textwrap
@@ -7,6 +8,7 @@
78
from tests.lib import pyversion # noqa: F401
89
from tests.lib import assert_all_changes
910
from tests.lib.local_repos import local_checkout
11+
from tests.lib.wheel import make_wheel
1012

1113

1214
@pytest.mark.network
@@ -439,3 +441,34 @@ def prep_ve(self, script, version, pip_src, distribute=False):
439441
cwd=pip_src,
440442
expect_stderr=True,
441443
)
444+
445+
446+
@pytest.mark.parametrize("req1, req2", list(itertools.product(
447+
["foo.bar", "foo_bar", "foo-bar"], ["foo.bar", "foo_bar", "foo-bar"],
448+
)))
449+
def test_install_find_existing_package_canonicalize(script, req1, req2):
450+
"""Ensure an already-installed dist is found no matter how the dist name
451+
was normalized on installation. (pypa/pip#8645)
452+
"""
453+
# Create and install a package that's not available in the later stage.
454+
req_container = script.scratch_path.joinpath("foo-bar")
455+
req_container.mkdir()
456+
req_path = make_wheel("foo_bar", "1.0").save_to_dir(req_container)
457+
script.pip("install", "--no-index", req_path)
458+
459+
# Depend on the previously installed, but now unavailable package.
460+
pkg_container = script.scratch_path.joinpath("pkg")
461+
pkg_container.mkdir()
462+
make_wheel(
463+
"pkg",
464+
"1.0",
465+
metadata_updates={"Requires-Dist": req2},
466+
).save_to_dir(pkg_container)
467+
468+
# Ensure the previously installed package can be correctly used to match
469+
# the dependency.
470+
result = script.pip(
471+
"install", "--no-index", "--find-links", pkg_container, "pkg",
472+
)
473+
satisfied_message = "Requirement already satisfied: {}".format(req2)
474+
assert satisfied_message in result.stdout, str(result)

0 commit comments

Comments
 (0)