diff --git a/piptools/repositories/local.py b/piptools/repositories/local.py index b2356d811..6c91d1b4f 100644 --- a/piptools/repositories/local.py +++ b/piptools/repositories/local.py @@ -33,7 +33,8 @@ class LocalRequirementsRepository(BaseRepository): PyPI. This keeps updates to the requirements.txt down to a minimum. """ - def __init__(self, existing_pins, proxied_repository): + def __init__(self, existing_pins, proxied_repository, reuse_hashes=True): + self._reuse_hashes = reuse_hashes self.repository = proxied_repository self.existing_pins = existing_pins @@ -74,8 +75,9 @@ def get_dependencies(self, ireq): return self.repository.get_dependencies(ireq) def get_hashes(self, ireq): - key = key_from_ireq(ireq) - existing_pin = self.existing_pins.get(key) + existing_pin = self._reuse_hashes and self.existing_pins.get( + key_from_ireq(ireq) + ) if existing_pin and ireq_satisfied_by_existing_pin(ireq, existing_pin): if PIP_VERSION[:2] <= (20, 0): hashes = existing_pin.options.get("hashes", {}) diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index d96ce9df0..785afb9bb 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -183,6 +183,15 @@ def has_arg(self, arg_name): default=False, help="Generate pip 8 style hashes in the resulting requirements file.", ) +@click.option( + "--reuse-hashes/--no-reuse-hashes", + is_flag=True, + default=True, + help=( + "Improve the speed of --generate-hashes by reusing the hashes from an " + "existing output file." + ), +) @click.option( "--max-rounds", default=10, @@ -241,6 +250,7 @@ def cli( output_file, allow_unsafe, generate_hashes, + reuse_hashes, src_files, max_rounds, build_isolation, @@ -360,7 +370,9 @@ def cli( existing_pins_to_upgrade.add(key) else: existing_pins[key] = ireq - repository = LocalRequirementsRepository(existing_pins, repository) + repository = LocalRequirementsRepository( + existing_pins, repository, reuse_hashes=reuse_hashes + ) ### # Parsing/collecting initial requirements diff --git a/tests/test_repository_local.py b/tests/test_repository_local.py index c0d4607c5..5b250119e 100644 --- a/tests/test_repository_local.py +++ b/tests/test_repository_local.py @@ -1,5 +1,7 @@ import copy +import pytest + from tests.conftest import FakeRepository from piptools.repositories.local import LocalRequirementsRepository @@ -29,6 +31,27 @@ def test_get_hashes_local_repository_cache_hit(from_line, repository): assert hashes == EXPECTED +NONSENSE = {"sha256:NONSENSE"} + + +@pytest.mark.parametrize( + ("reuse_hashes", "expected"), ((True, NONSENSE), (False, EXPECTED)) +) +def test_toggle_reuse_hashes_local_repository( + pip_conf, from_line, pypi_repository, reuse_hashes, expected +): + # Create an install requirement with the hashes included in its options + options = {"hashes": {"sha256": [entry.split(":")[1] for entry in NONSENSE]}} + req = from_line("small-fake-a==0.1", options=options) + existing_pins = {name_from_req(req): req} + + local_repository = LocalRequirementsRepository( + existing_pins, pypi_repository, reuse_hashes=reuse_hashes + ) + with local_repository.allow_all_wheels(): + assert local_repository.get_hashes(from_line("small-fake-a==0.1")) == expected + + class FakeRepositoryChecksForCopy(FakeRepository): def __init__(self): super(FakeRepositoryChecksForCopy, self).__init__()