Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/7490.trivial
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix unrelease bug from #7319.
26 changes: 14 additions & 12 deletions src/pip/_internal/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,13 @@ def _get_candidates(self, link, canonical_package_name):
candidates = []
path = self.get_path_for_link(link)
if os.path.isdir(path):
candidates.extend(os.listdir(path))
for candidate in os.listdir(path):
candidates.append((candidate, path))
# TODO remove legacy path lookup in pip>=21
legacy_path = self.get_path_for_link_legacy(link)
if os.path.isdir(legacy_path):
candidates.extend(os.listdir(legacy_path))
for candidate in os.listdir(legacy_path):
candidates.append((candidate, legacy_path))
return candidates

def get_path_for_link_legacy(self, link):
Expand All @@ -167,13 +169,6 @@ def get(
"""
raise NotImplementedError()

def _link_for_candidate(self, link, candidate):
# type: (Link, str) -> Link
root = self.get_path_for_link(link)
path = os.path.join(root, candidate)

return Link(path_to_url(path))

def cleanup(self):
# type: () -> None
pass
Expand Down Expand Up @@ -228,7 +223,9 @@ def get(
return link

canonical_package_name = canonicalize_name(package_name)
for wheel_name in self._get_candidates(link, canonical_package_name):
for wheel_name, wheel_dir in self._get_candidates(
link, canonical_package_name
):
try:
wheel = Wheel(wheel_name)
except InvalidWheelFilename:
Expand All @@ -245,13 +242,18 @@ def get(
# Built for a different python/arch/etc
continue
candidates.append(
(wheel.support_index_min(supported_tags), wheel_name)
(
wheel.support_index_min(supported_tags),
wheel_name,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: it's unlikely that the min() call would depend on the wheel_name.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least this is equivalent to the previous behavior. Alternatively, we may want to separately consider whether an sdist may produce a wheel with "build tag" that should be taken into account even in the cache.

wheel_dir,
)
)

if not candidates:
return link

return self._link_for_candidate(link, min(candidates)[1])
_, wheel_name, wheel_dir = min(candidates)
return Link(path_to_url(os.path.join(wheel_dir, wheel_name)))


class EphemWheelCache(SimpleWheelCache):
Expand Down
35 changes: 29 additions & 6 deletions tests/unit/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ def test_wheel_name_filter(tmpdir):
with open(os.path.join(cache_path, "package-1.0-py3-none-any.whl"), "w"):
pass
# package matches wheel name
assert wc.get(link, "package", [("py3", "none", "any")]) is not link
cached_link = wc.get(link, "package", [("py3", "none", "any")])
assert cached_link is not link
assert os.path.exists(cached_link.file_path)
# package2 does not match wheel name
assert wc.get(link, "package2", [("py3", "none", "any")]) is link

Expand All @@ -56,18 +58,39 @@ def test_cache_hash():
def test_get_path_for_link_legacy(tmpdir):
"""
Test that an existing cache entry that was created with the legacy hashing
mechanism is used.
mechanism is returned by WheelCache._get_candidates().
"""
wc = WheelCache(tmpdir, FormatControl())
link = Link("https://g.c/o/r")
path = wc.get_path_for_link(link)
legacy_path = wc.get_path_for_link_legacy(link)
assert path != legacy_path
ensure_dir(path)
with open(os.path.join(path, "test-pyz-none-any.whl"), "w"):
with open(os.path.join(path, "test-1.0.0-pyz-none-any.whl"), "w"):
pass
ensure_dir(legacy_path)
with open(os.path.join(legacy_path, "test-pyx-none-any.whl"), "w"):
with open(os.path.join(legacy_path, "test-1.0.0-pyx-none-any.whl"), "w"):
pass
expected_candidates = {"test-pyx-none-any.whl", "test-pyz-none-any.whl"}
assert set(wc._get_candidates(link, "test")) == expected_candidates
expected_candidates = {
"test-1.0.0-pyx-none-any.whl", "test-1.0.0-pyz-none-any.whl"
}
candidates = {c[0] for c in wc._get_candidates(link, "test")}
assert candidates == expected_candidates


def test_get_with_legacy_entry_only(tmpdir):
"""
Test that an existing cache entry that was created with the legacy hashing
mechanism is actually returned in WheelCache.get().
"""
wc = WheelCache(tmpdir, FormatControl())
link = Link("https://g.c/o/r")
legacy_path = wc.get_path_for_link_legacy(link)
ensure_dir(legacy_path)
with open(os.path.join(legacy_path, "test-1.0.0-py3-none-any.whl"), "w"):
pass
cached_link = wc.get(link, "test", [("py3", "none", "any")])
assert (
os.path.normcase(os.path.dirname(cached_link.file_path)) ==
os.path.normcase(legacy_path)
)