Skip to content

Commit 0034cb1

Browse files
committed
Fix editable-or-not egg-info uninstallation
1 parent a66b02a commit 0034cb1

File tree

2 files changed

+26
-8
lines changed

2 files changed

+26
-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: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -455,13 +455,22 @@ 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.
463-
if info_location is not None:
464-
paths_to_remove.add(info_location)
472+
if setuptools_flat_installation:
473+
paths_to_remove.add(info_location)
465474
installed_files = dist.iter_declared_entries()
466475
if installed_files is not None:
467476
for installed_file in installed_files:
@@ -512,15 +521,16 @@ def from_dist(cls, dist: BaseDistribution) -> "UninstallPathSet":
512521
for path in uninstallation_paths(dist):
513522
paths_to_remove.add(path)
514523

515-
elif dist.editable and develop_egg_link:
524+
elif develop_egg_link:
516525
# PEP 660 modern editable is handled in the ``.dist-info`` case
517526
# above, so this only covers the setuptools-style editable.
518527
with open(develop_egg_link) as fh:
519528
link_pointer = os.path.normcase(fh.readline().strip())
520529
assert (
521530
link_pointer == dist_location
522-
), "Egg-link {} does not match installed location of {} (at {})".format(
523-
link_pointer, dist.raw_name, dist_location
531+
), (
532+
f"Egg-link {link_pointer} does not match installed location of "
533+
f"{dist.raw_name} (at {dist_location})"
524534
)
525535
paths_to_remove.add(develop_egg_link)
526536
easy_install_pth = os.path.join(

0 commit comments

Comments
 (0)