From 05d2b85d4aeae5473c692a5cc138ee22960d9653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Mon, 30 May 2022 18:36:48 +0200 Subject: [PATCH] Add unit tests for cache origin.json... and fix a bug --- src/pip/_internal/operations/prepare.py | 11 +++-- tests/unit/test_req.py | 64 ++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/pip/_internal/operations/prepare.py b/src/pip/_internal/operations/prepare.py index 053e0020c90..80723fffe47 100644 --- a/src/pip/_internal/operations/prepare.py +++ b/src/pip/_internal/operations/prepare.py @@ -505,21 +505,22 @@ def _prepare_linked_requirement( # prepare_editable_requirement). assert not req.editable req.download_info = direct_url_from_link(link, req.source_dir) - - # For use in later processing, - # preserve the file path on the requirement. - if local_file: - req.local_file_path = local_file.path # Make sure we have a hash in download_info. If we got it as part of the # URL, it will have been verified and we can rely on it. Otherwise we # compute it from the downloaded file. if ( isinstance(req.download_info.info, ArchiveInfo) and not req.download_info.info.hash + and local_file ): hash = hash_file(local_file.path)[0].hexdigest() req.download_info.info.hash = f"sha256={hash}" + # For use in later processing, + # preserve the file path on the requirement. + if local_file: + req.local_file_path = local_file.path + dist = _get_prepared_distribution( req, self.build_tracker, diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 3c4ded6f26d..18932bb344d 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -5,13 +5,14 @@ import sys import tempfile from functools import partial -from typing import Iterator, Tuple, cast +from typing import Iterator, Optional, Tuple, cast from unittest import mock import pytest from pip._vendor.packaging.markers import Marker from pip._vendor.packaging.requirements import Requirement +from pip._internal.cache import WheelCache from pip._internal.commands import create_command from pip._internal.commands.install import InstallCommand from pip._internal.exceptions import ( @@ -22,7 +23,9 @@ ) from pip._internal.index.package_finder import PackageFinder from pip._internal.metadata import select_backend -from pip._internal.models.direct_url import ArchiveInfo, DirInfo, VcsInfo +from pip._internal.models.direct_url import ArchiveInfo, DirectUrl, DirInfo, VcsInfo +from pip._internal.models.format_control import FormatControl +from pip._internal.models.link import Link from pip._internal.network.session import PipSession from pip._internal.operations.build.build_tracker import get_build_tracker from pip._internal.operations.prepare import RequirementPreparer @@ -43,7 +46,7 @@ ) from pip._internal.resolution.legacy.resolver import Resolver from pip._internal.utils.urls import path_to_url -from tests.lib import TestData, make_test_finder, requirements_file +from tests.lib import TestData, make_test_finder, requirements_file, wheel from tests.lib.path import Path @@ -77,7 +80,10 @@ def teardown(self) -> None: @contextlib.contextmanager def _basic_resolver( - self, finder: PackageFinder, require_hashes: bool = False + self, + finder: PackageFinder, + require_hashes: bool = False, + wheel_cache: Optional[WheelCache] = None, ) -> Iterator[Resolver]: make_install_req = partial( install_req_from_req_string, @@ -106,7 +112,7 @@ def _basic_resolver( preparer=preparer, make_install_req=make_install_req, finder=finder, - wheel_cache=None, + wheel_cache=wheel_cache, use_user_site=False, upgrade_strategy="to-satisfy-only", ignore_dependencies=False, @@ -366,7 +372,6 @@ def test_download_info_index_url(self) -> None: req = reqset.all_requirements[0] assert req.download_info assert isinstance(req.download_info.info, ArchiveInfo) - assert req.download_info.info.hash @pytest.mark.network def test_download_info_web_archive(self) -> None: @@ -391,6 +396,53 @@ def test_download_info_web_archive(self) -> None: "ad977496000576e1b6c41f6449a9897087ce9da6db4f15b603fe8372af4bf3c6" ) + def test_download_info_archive_legacy_cache( + self, tmp_path: Path, shared_data: TestData + ) -> None: + """Test download_info hash is not set for an archive with legacy cache entry.""" + url = path_to_url(shared_data.packages / "simple-1.0.tar.gz") + finder = make_test_finder() + wheel_cache = WheelCache(str(tmp_path / "cache"), FormatControl()) + cache_entry_dir = wheel_cache.get_path_for_link(Link(url)) + Path(cache_entry_dir).mkdir(parents=True) + wheel.make_wheel(name="simple", version="1.0").save_to_dir(cache_entry_dir) + with self._basic_resolver(finder, wheel_cache=wheel_cache) as resolver: + ireq = get_processed_req_from_line(f"simple @ {url}") + reqset = resolver.resolve([ireq], True) + assert len(reqset.all_requirements) == 1 + req = reqset.all_requirements[0] + assert req.original_link_is_in_wheel_cache + assert req.download_info + assert req.download_info.url == url + assert isinstance(req.download_info.info, ArchiveInfo) + assert not req.download_info.info.hash + + def test_download_info_archive_cache_with_origin( + self, tmp_path: Path, shared_data: TestData + ) -> None: + """Test download_info hash is set for a web archive with cache entry + that has origin.json.""" + url = path_to_url(shared_data.packages / "simple-1.0.tar.gz") + hash = "sha256=ad977496000576e1b6c41f6449a9897087ce9da6db4f15b603fe8372af4bf3c6" + finder = make_test_finder() + wheel_cache = WheelCache(str(tmp_path / "cache"), FormatControl()) + cache_entry_dir = wheel_cache.get_path_for_link(Link(url)) + Path(cache_entry_dir).mkdir(parents=True) + Path(cache_entry_dir).joinpath("origin.json").write_text( + DirectUrl(url, ArchiveInfo(hash=hash)).to_json() + ) + wheel.make_wheel(name="simple", version="1.0").save_to_dir(cache_entry_dir) + with self._basic_resolver(finder, wheel_cache=wheel_cache) as resolver: + ireq = get_processed_req_from_line(f"simple @ {url}") + reqset = resolver.resolve([ireq], True) + assert len(reqset.all_requirements) == 1 + req = reqset.all_requirements[0] + assert req.original_link_is_in_wheel_cache + assert req.download_info + assert req.download_info.url == url + assert isinstance(req.download_info.info, ArchiveInfo) + assert req.download_info.info.hash == hash + def test_download_info_local_wheel(self, data: TestData) -> None: """Test that download_info is set for requirements from a local wheel.""" finder = make_test_finder()