Skip to content

Commit 5d9dde1

Browse files
authored
Merge pull request #12060 from sbidoul/fix-11985-sbi
2 parents ab1b312 + 1ca4529 commit 5d9dde1

File tree

3 files changed

+51
-11
lines changed

3 files changed

+51
-11
lines changed

news/11985.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ignore invalid or unreadable ``origin.json`` files in the cache of locally built wheels.

src/pip/_internal/cache.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,17 @@ def __init__(
194194
self.origin: Optional[DirectUrl] = None
195195
origin_direct_url_path = Path(self.link.file_path).parent / ORIGIN_JSON_NAME
196196
if origin_direct_url_path.exists():
197-
self.origin = DirectUrl.from_json(origin_direct_url_path.read_text())
197+
try:
198+
self.origin = DirectUrl.from_json(
199+
origin_direct_url_path.read_text(encoding="utf-8")
200+
)
201+
except Exception as e:
202+
logger.warning(
203+
"Ignoring invalid cache entry origin file %s for %s (%s)",
204+
origin_direct_url_path,
205+
link.filename,
206+
e,
207+
)
198208

199209

200210
class WheelCache(Cache):
@@ -257,16 +267,26 @@ def get_cache_entry(
257267
@staticmethod
258268
def record_download_origin(cache_dir: str, download_info: DirectUrl) -> None:
259269
origin_path = Path(cache_dir) / ORIGIN_JSON_NAME
260-
if origin_path.is_file():
261-
origin = DirectUrl.from_json(origin_path.read_text())
262-
# TODO: use DirectUrl.equivalent when https://github.com/pypa/pip/pull/10564
263-
# is merged.
264-
if origin.url != download_info.url:
270+
if origin_path.exists():
271+
try:
272+
origin = DirectUrl.from_json(origin_path.read_text(encoding="utf-8"))
273+
except Exception as e:
265274
logger.warning(
266-
"Origin URL %s in cache entry %s does not match download URL %s. "
267-
"This is likely a pip bug or a cache corruption issue.",
268-
origin.url,
269-
cache_dir,
270-
download_info.url,
275+
"Could not read origin file %s in cache entry (%s). "
276+
"Will attempt to overwrite it.",
277+
origin_path,
278+
e,
271279
)
280+
else:
281+
# TODO: use DirectUrl.equivalent when
282+
# https://github.com/pypa/pip/pull/10564 is merged.
283+
if origin.url != download_info.url:
284+
logger.warning(
285+
"Origin URL %s in cache entry %s does not match download URL "
286+
"%s. This is likely a pip bug or a cache corruption issue. "
287+
"Will overwrite it with the new value.",
288+
origin.url,
289+
cache_dir,
290+
download_info.url,
291+
)
272292
origin_path.write_text(download_info.to_json(), encoding="utf-8")

tests/unit/test_req.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,25 @@ def test_download_info_archive_cache_with_origin(
445445
assert isinstance(req.download_info.info, ArchiveInfo)
446446
assert req.download_info.info.hash == hash
447447

448+
def test_download_info_archive_cache_with_invalid_origin(
449+
self, tmp_path: Path, shared_data: TestData, caplog: pytest.LogCaptureFixture
450+
) -> None:
451+
"""Test an invalid origin.json is ignored."""
452+
url = shared_data.packages.joinpath("simple-1.0.tar.gz").as_uri()
453+
finder = make_test_finder()
454+
wheel_cache = WheelCache(str(tmp_path / "cache"))
455+
cache_entry_dir = wheel_cache.get_path_for_link(Link(url))
456+
Path(cache_entry_dir).mkdir(parents=True)
457+
Path(cache_entry_dir).joinpath("origin.json").write_text("{") # invalid json
458+
wheel.make_wheel(name="simple", version="1.0").save_to_dir(cache_entry_dir)
459+
with self._basic_resolver(finder, wheel_cache=wheel_cache) as resolver:
460+
ireq = get_processed_req_from_line(f"simple @ {url}")
461+
reqset = resolver.resolve([ireq], True)
462+
assert len(reqset.all_requirements) == 1
463+
req = reqset.all_requirements[0]
464+
assert req.is_wheel_from_cache
465+
assert "Ignoring invalid cache entry origin file" in caplog.messages[0]
466+
448467
def test_download_info_local_wheel(self, data: TestData) -> None:
449468
"""Test that download_info is set for requirements from a local wheel."""
450469
finder = make_test_finder()

0 commit comments

Comments
 (0)