Skip to content

Commit 35ec437

Browse files
committed
Fix editable-or-not egg-info uninstallation
1 parent e0f41ae commit 35ec437

File tree

2 files changed

+25
-8
lines changed

2 files changed

+25
-8
lines changed

src/pip/_internal/metadata/base.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,14 @@ def canonical_name(self) -> NormalizedName:
214214
def version(self) -> DistributionVersion:
215215
raise NotImplementedError()
216216

217+
@property
218+
def setuptools_filename(self) -> str:
219+
"""Convert a project name to its setuptools-compatible filename.
220+
221+
This is a copy of ``pkg_resources.to_filename()`` for compatibility.
222+
"""
223+
return self.raw_name.replace("-", "_")
224+
217225
@property
218226
def direct_url(self) -> Optional[DirectUrl]:
219227
"""Obtain a DirectUrl from this distribution.

src/pip/_internal/req/req_uninstall.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -455,11 +455,21 @@ def from_dist(cls, dist: BaseDistribution) -> "UninstallPathSet":
455455
paths_to_remove = cls(dist)
456456
develop_egg_link = egg_link_path_from_location(dist.raw_name)
457457

458+
# Distribution is installed with metadata in a "flat" .egg-info
459+
# directory. This means it is not a modern .dist-info installation, an
460+
# egg, or legacy editable.
461+
setuptools_flat_installation = (
462+
dist.installed_with_setuptools_egg_info
463+
and info_location is not None
464+
and os.path.exists(info_location)
465+
# If dist is editable and the location points to a ``.egg-info``,
466+
# we are in fact in the legacy editable case.
467+
and not info_location.endswith(f"{dist.setuptools_filename}.egg-info")
468+
)
469+
458470
# Uninstall cases order do matter as in the case of 2 installs of the
459471
# same package, pip needs to uninstall the currently detected version
460-
if dist.installed_with_setuptools_egg_info and not dist.editable:
461-
# if dist is editable and the location points to a ``.egg-info``,
462-
# we are in fact in the ``.egg_link`` case.
472+
if setuptools_flat_installation:
463473
if info_location is not None:
464474
paths_to_remove.add(info_location)
465475
installed_files = dist.iter_declared_entries()
@@ -512,15 +522,14 @@ def from_dist(cls, dist: BaseDistribution) -> "UninstallPathSet":
512522
for path in uninstallation_paths(dist):
513523
paths_to_remove.add(path)
514524

515-
elif dist.editable and develop_egg_link:
525+
elif develop_egg_link:
516526
# PEP 660 modern editable is handled in the ``.dist-info`` case
517527
# above, so this only covers the setuptools-style editable.
518528
with open(develop_egg_link) as fh:
519529
link_pointer = os.path.normcase(fh.readline().strip())
520-
assert (
521-
link_pointer == dist_location
522-
), "Egg-link {} does not match installed location of {} (at {})".format(
523-
link_pointer, dist.raw_name, dist_location
530+
assert link_pointer == dist_location, (
531+
f"Egg-link {link_pointer} does not match installed location of "
532+
f"{dist.raw_name} (at {dist_location})"
524533
)
525534
paths_to_remove.add(develop_egg_link)
526535
easy_install_pth = os.path.join(

0 commit comments

Comments
 (0)