Skip to content

Commit 21422d4

Browse files
committed
Correctly normalize paths relative to install path
Since the legacy installed-files.txt writes paths relatively to the egg-info directory, we need to introduce a new property on BaseDistribution to return that directory's path (analoguous to pkg_resources's Distribution.egg_info). Entries in RECORD are normalized with pathlib.Path so they have the correct path component separator depending on the platform (e.g. '/' on Windows), to match the previous behavior.
1 parent 776a1da commit 21422d4

File tree

3 files changed

+28
-7
lines changed

3 files changed

+28
-7
lines changed

src/pip/_internal/commands/show.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import csv
22
import logging
3-
import os
3+
import pathlib
44
from optparse import Values
55
from typing import Iterator, List, NamedTuple, Optional
66

@@ -95,19 +95,24 @@ def _get_requiring_packages(current_dist: BaseDistribution) -> List[str]:
9595
}
9696
]
9797

98-
def _files_from_record(dist: BaseDistribution) -> Optional[Iterator[str]]:
98+
def _files_from_record(dist: BaseDistribution) -> Optional[Iterator[pathlib.Path]]:
9999
try:
100100
text = dist.read_text('RECORD')
101101
except FileNotFoundError:
102102
return None
103-
return (row[0] for row in csv.reader(text.splitlines()))
103+
return (pathlib.Path(row[0]) for row in csv.reader(text.splitlines()))
104104

105-
def _files_from_installed_files(dist: BaseDistribution) -> Optional[Iterator[str]]:
105+
def _files_from_legacy(dist: BaseDistribution) -> Optional[Iterator[pathlib.Path]]:
106106
try:
107107
text = dist.read_text('installed-files.txt')
108108
except FileNotFoundError:
109109
return None
110-
return (p for p in text.splitlines(keepends=False) if p)
110+
paths = (p for p in text.splitlines(keepends=False) if p)
111+
root = dist.location
112+
if root is not None:
113+
info = pathlib.Path(dist.metadata_directory)
114+
paths = (info.joinpath(p).resolve().relative_to(root) for p in paths)
115+
return paths
111116

112117
for query_name in query_names:
113118
try:
@@ -121,11 +126,11 @@ def _files_from_installed_files(dist: BaseDistribution) -> Optional[Iterator[str
121126
except FileNotFoundError:
122127
entry_points = []
123128

124-
files_iter = _files_from_record(dist) or _files_from_installed_files(dist)
129+
files_iter = _files_from_record(dist) or _files_from_legacy(dist)
125130
if files_iter is None:
126131
files: Optional[List[str]] = None
127132
else:
128-
files = sorted(os.path.relpath(p, dist.location) for p in files_iter)
133+
files = sorted(str(p) for p in files_iter)
129134

130135
metadata = dist.metadata
131136

src/pip/_internal/metadata/base.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ def location(self) -> Optional[str]:
6060
"""
6161
raise NotImplementedError()
6262

63+
@property
64+
def metadata_directory(self) -> Optional[str]:
65+
"""Location of the metadata directory.
66+
67+
Similarly to ``location``, a string value is not necessarily a
68+
filesystem path. ``None`` means the distribution is created in-memory.
69+
70+
For a modern .dist-info installation on disk, this should be something
71+
like ``{location}/{raw_name}-{version}.dist-info``.
72+
"""
73+
raise NotImplementedError()
74+
6375
@property
6476
def canonical_name(self) -> "NormalizedName":
6577
raise NotImplementedError()

src/pip/_internal/metadata/pkg_resources.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ def from_wheel(cls, path: str, name: str) -> "Distribution":
4848
def location(self) -> Optional[str]:
4949
return self._dist.location
5050

51+
@property
52+
def metadata_directory(self) -> Optional[str]:
53+
return self._dist.egg_info
54+
5155
@property
5256
def canonical_name(self) -> "NormalizedName":
5357
return canonicalize_name(self._dist.project_name)

0 commit comments

Comments
 (0)