From 840fdf5910065fc12d20e76b5f4f8128d6e9e934 Mon Sep 17 00:00:00 2001 From: Andrei Neagu <5694077+GitHK@users.noreply.github.com> Date: Thu, 3 Oct 2024 16:15:50 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20archiving=5Futils=20creates=20de?= =?UTF-8?q?terministic=20zip=20archives=20(#6472)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrei Neagu --- packages/aws-library/requirements/_base.txt | 2 + .../service-library/requirements/_base.in | 1 + .../service-library/requirements/_base.txt | 2 + .../service-library/requirements/_test.in | 2 + .../service-library/requirements/_test.txt | 4 + .../src/servicelib/archiving_utils.py | 67 ++++++++------ .../tests/test_archiving_utils.py | 92 ++++++++++++++++++- packages/simcore-sdk/requirements/_base.txt | 2 + services/api-server/requirements/_base.txt | 4 + services/autoscaling/requirements/_base.txt | 4 + services/catalog/requirements/_base.txt | 2 + .../clusters-keeper/requirements/_base.txt | 4 + services/dask-sidecar/requirements/_base.txt | 2 + .../datcore-adapter/requirements/_base.txt | 2 + services/director-v2/requirements/_base.txt | 4 + .../dynamic-scheduler/requirements/_base.txt | 5 + .../dynamic-sidecar/requirements/_base.txt | 4 + services/efs-guardian/requirements/_base.txt | 4 + services/invitations/requirements/_base.txt | 2 + services/payments/requirements/_base.txt | 2 + .../requirements/_base.txt | 4 + services/storage/requirements/_base.txt | 4 + services/web/server/requirements/_base.txt | 4 + tests/swarm-deploy/requirements/_test.txt | 4 + 24 files changed, 196 insertions(+), 31 deletions(-) diff --git a/packages/aws-library/requirements/_base.txt b/packages/aws-library/requirements/_base.txt index 79052f3c4d9..e3ba613b1af 100644 --- a/packages/aws-library/requirements/_base.txt +++ b/packages/aws-library/requirements/_base.txt @@ -224,6 +224,8 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.8.1 diff --git a/packages/service-library/requirements/_base.in b/packages/service-library/requirements/_base.in index f31af0b3a40..aa776fedb15 100644 --- a/packages/service-library/requirements/_base.in +++ b/packages/service-library/requirements/_base.in @@ -24,6 +24,7 @@ pydantic pyinstrument pyyaml redis +repro-zipfile tenacity toolz tqdm diff --git a/packages/service-library/requirements/_base.txt b/packages/service-library/requirements/_base.txt index 64b33447725..1ca02bd5938 100644 --- a/packages/service-library/requirements/_base.txt +++ b/packages/service-library/requirements/_base.txt @@ -172,6 +172,8 @@ referencing==0.29.3 # -c requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.8.1 diff --git a/packages/service-library/requirements/_test.in b/packages/service-library/requirements/_test.in index 3ce22356810..d3936487c75 100644 --- a/packages/service-library/requirements/_test.in +++ b/packages/service-library/requirements/_test.in @@ -17,7 +17,9 @@ coverage docker faker flaky +numpy openapi-spec-validator +pillow pytest pytest-aiohttp pytest-asyncio diff --git a/packages/service-library/requirements/_test.txt b/packages/service-library/requirements/_test.txt index a6a72dcd500..98e99158b10 100644 --- a/packages/service-library/requirements/_test.txt +++ b/packages/service-library/requirements/_test.txt @@ -121,6 +121,8 @@ mypy==1.11.2 # via sqlalchemy mypy-extensions==1.0.0 # via mypy +numpy==2.1.1 + # via -r requirements/_test.in openapi-schema-validator==0.6.2 # via # -c requirements/_aiohttp.txt @@ -137,6 +139,8 @@ pathable==0.4.3 # via # -c requirements/_aiohttp.txt # jsonschema-path +pillow==10.4.0 + # via -r requirements/_test.in pluggy==1.5.0 # via pytest pprintpp==0.4.0 diff --git a/packages/service-library/src/servicelib/archiving_utils.py b/packages/service-library/src/servicelib/archiving_utils.py index d5c318f8b09..a46665b2c23 100644 --- a/packages/service-library/src/servicelib/archiving_utils.py +++ b/packages/service-library/src/servicelib/archiving_utils.py @@ -4,13 +4,16 @@ import logging import types import zipfile -from contextlib import AsyncExitStack, contextmanager +from collections.abc import Awaitable, Callable, Iterator +from contextlib import AsyncExitStack, contextmanager, suppress from functools import partial from pathlib import Path -from typing import Any, Awaitable, Callable, Final, Iterator +from typing import Any, Final import tqdm from models_library.basic_types import IDStr +from pydantic import NonNegativeFloat +from repro_zipfile import ReproducibleZipFile # type: ignore[import-untyped] from tqdm.contrib.logging import logging_redirect_tqdm, tqdm_logging_redirect from .file_utils import remove_directory @@ -21,8 +24,9 @@ _MIN: Final[int] = 60 # secs _MAX_UNARCHIVING_WORKER_COUNT: Final[int] = 2 _CHUNK_SIZE: Final[int] = 1024 * 8 +_UNIT_MULTIPLIER: Final[NonNegativeFloat] = 1024.0 -log = logging.getLogger(__name__) +_logger = logging.getLogger(__name__) class ArchiveError(Exception): @@ -35,10 +39,10 @@ def _human_readable_size(size, decimal_places=3): human_readable_file_size = float(size) unit = "B" for t_unit in ["B", "KiB", "MiB", "GiB", "TiB"]: - if human_readable_file_size < 1024.0: + if human_readable_file_size < _UNIT_MULTIPLIER: unit = t_unit break - human_readable_file_size /= 1024.0 + human_readable_file_size /= _UNIT_MULTIPLIER return f"{human_readable_file_size:.{decimal_places}f}{unit}" @@ -56,7 +60,9 @@ def _iter_files_to_compress( dir_path: Path, exclude_patterns: set[str] | None ) -> Iterator[Path]: exclude_patterns = exclude_patterns if exclude_patterns else set() - for path in dir_path.rglob("*"): + # NOTE: make sure to sort paths othrwise between different runs + # the zip will have a different structure and hash + for path in sorted(dir_path.rglob("*")): if path.is_file() and not any( fnmatch.fnmatch(f"{path}", x) for x in exclude_patterns ): @@ -64,11 +70,11 @@ def _iter_files_to_compress( def _strip_directory_from_path(input_path: Path, to_strip: Path) -> Path: - _to_strip = f"{str(to_strip)}/" + _to_strip = f"{to_strip}/" return Path(str(input_path).replace(_to_strip, "")) -class _FastZipFileReader(zipfile.ZipFile): +class _FastZipFileReader(ReproducibleZipFile): """ Used to gain a speed boost of several orders of magnitude. @@ -86,7 +92,7 @@ class _FastZipFileReader(zipfile.ZipFile): files contained in the archive. """ - def _RealGetContents(self): + def _RealGetContents(self): # noqa: N802 """method disabled""" @@ -107,7 +113,7 @@ def _zipfile_single_file_extract_worker( zip_file_path: Path, file_in_archive: zipfile.ZipInfo, destination_folder: Path, - is_dir: bool, + is_dir: bool, # noqa: FBT001 ) -> Path: """Extracts file_in_archive from the archive zip_file_path -> destination_folder/file_in_archive @@ -129,7 +135,7 @@ def _zipfile_single_file_extract_worker( desc=desc, **( _TQDM_FILE_OPTIONS - | dict(miniters=_compute_tqdm_miniters(file_in_archive.file_size)) + | {"miniters": _compute_tqdm_miniters(file_in_archive.file_size)} ), ) as pbar: while chunk := zip_fp.read(_CHUNK_SIZE): @@ -139,7 +145,7 @@ def _zipfile_single_file_extract_worker( def _ensure_destination_subdirectories_exist( - zip_file_handler: zipfile.ZipFile, destination_folder: Path + zip_file_handler: ReproducibleZipFile, destination_folder: Path ) -> None: # assemble full destination paths full_destination_paths = { @@ -177,7 +183,7 @@ async def unarchive_dir( ) async with AsyncExitStack() as zip_stack: zip_file_handler = zip_stack.enter_context( - zipfile.ZipFile( # pylint: disable=consider-using-with + ReproducibleZipFile( # pylint: disable=consider-using-with archive_to_extract, mode="r", ) @@ -232,7 +238,7 @@ async def unarchive_dir( extracted_path = await future extracted_file_size = extracted_path.stat().st_size if tqdm_progress.update(extracted_file_size) and log_cb: - with log_catch(log, reraise=False): + with log_catch(_logger, reraise=False): await log_cb(f"{tqdm_progress}") await sub_prog.update(extracted_file_size) extracted_paths.append(extracted_path) @@ -266,12 +272,15 @@ async def unarchive_dir( @contextmanager def _progress_enabled_zip_write_handler( - zip_file_handler: zipfile.ZipFile, progress_bar: tqdm.tqdm -) -> Iterator[zipfile.ZipFile]: + zip_file_handler: ReproducibleZipFile, progress_bar: tqdm.tqdm +) -> Iterator[ReproducibleZipFile]: """This function overrides the default zip write fct to allow to get progress using tqdm library""" def _write_with_progress( - original_write_fct, self, data, pbar # pylint: disable=unused-argument + original_write_fct, + self, # pylint: disable=unused-argument # noqa: ARG001 + data, + pbar, ): pbar.update(len(data)) return original_write_fct(data) @@ -279,21 +288,21 @@ def _write_with_progress( # Replace original write() with a wrapper to track progress assert zip_file_handler.fp # nosec old_write_method = zip_file_handler.fp.write - zip_file_handler.fp.write = types.MethodType( # type: ignore[assignment] + zip_file_handler.fp.write = types.MethodType( partial(_write_with_progress, old_write_method, pbar=progress_bar), zip_file_handler.fp, ) try: yield zip_file_handler finally: - zip_file_handler.fp.write = old_write_method # type: ignore[method-assign] + zip_file_handler.fp.write = old_write_method def _add_to_archive( dir_to_compress: Path, destination: Path, - compress: bool, - store_relative_path: bool, + compress: bool, # noqa: FBT001 + store_relative_path: bool, # noqa: FBT001 update_progress, loop, exclude_patterns: set[str] | None = None, @@ -308,11 +317,10 @@ def _add_to_archive( desc=f"{desc}\n", total=folder_size_bytes, **( - _TQDM_FILE_OPTIONS - | dict(miniters=_compute_tqdm_miniters(folder_size_bytes)) + _TQDM_FILE_OPTIONS | {"miniters": _compute_tqdm_miniters(folder_size_bytes)} ), ) as progress_bar, _progress_enabled_zip_write_handler( - zipfile.ZipFile(destination, "w", compression=compression), progress_bar + ReproducibleZipFile(destination, "w", compression=compression), progress_bar ) as zip_file_handler: for file_to_add in _iter_files_to_compress(dir_to_compress, exclude_patterns): progress_bar.set_description(f"{desc}/{file_to_add.name}\n") @@ -393,10 +401,11 @@ async def archive_dir( if destination.is_file(): destination.unlink(missing_ok=True) - raise ArchiveError( + msg = ( f"Failed archiving {dir_to_compress} -> {destination} due to {type(err)}." f"Details: {err}" - ) from err + ) + raise ArchiveError(msg) from err except BaseException: if destination.is_file(): @@ -453,11 +462,9 @@ def prune(self, exclude: set[Path]) -> None: if path.is_file(): path.unlink() elif path.is_dir(): - try: + # prevents deleting non-empty folders + with suppress(OSError): path.rmdir() - except OSError: - # prevents deleting non-empty folders - pass # second pass to delete empty folders # after deleting files, some folders might have been left empty diff --git a/packages/service-library/tests/test_archiving_utils.py b/packages/service-library/tests/test_archiving_utils.py index f6886ea509a..3996be43ca5 100644 --- a/packages/service-library/tests/test_archiving_utils.py +++ b/packages/service-library/tests/test_archiving_utils.py @@ -11,17 +11,20 @@ import secrets import string import tempfile +from collections.abc import AsyncIterable, Callable, Iterable, Iterator from concurrent.futures import ProcessPoolExecutor from dataclasses import dataclass from pathlib import Path -from typing import Callable, Iterable, Iterator +import numpy import pytest from faker import Faker +from PIL import Image from pydantic import ByteSize, parse_obj_as from pytest_benchmark.plugin import BenchmarkFixture from servicelib import archiving_utils from servicelib.archiving_utils import ArchiveError, archive_dir, unarchive_dir +from servicelib.file_utils import remove_directory def _print_tree(path: Path, level=0): @@ -596,3 +599,90 @@ def run_async_test(*args, **kwargs): ) benchmark(run_async_test) + + +def _touch_all_files_in_path(path_to_archive: Path) -> None: + for path in path_to_archive.rglob("*"): + print("touching", path) + path.touch() + + +@pytest.fixture +async def mixed_file_types(tmp_path: Path, faker: Faker) -> AsyncIterable[Path]: + base_dir = tmp_path / "mixed_types_dir" + base_dir.mkdir() + + # mixed small text files and binary files + (base_dir / "empty").mkdir() + (base_dir / "d1").mkdir() + (base_dir / "d1" / "f1.txt").write_text(faker.text()) + (base_dir / "d1" / "b2.bin").write_bytes(faker.json_bytes()) + (base_dir / "d1" / "sd1").mkdir() + (base_dir / "d1" / "sd1" / "f1.txt").write_text(faker.text()) + (base_dir / "d1" / "sd1" / "b2.bin").write_bytes(faker.json_bytes()) + (base_dir / "images").mkdir() + + # images cause issues with zipping, below content produced different + # hashes for zip files + for i in range(2): + image_dir = base_dir / f"images{i}" + image_dir.mkdir() + for n in range(50): + a = numpy.random.rand(900, 900, 3) * 255 # noqa: NPY002 + im_out = Image.fromarray(a.astype("uint8")).convert("RGB") + image_path = image_dir / f"out{n}.jpg" + im_out.save(image_path) + + print("mixed_types_dir ---") + _print_tree(base_dir) + + yield base_dir + + await remove_directory(base_dir) + assert not base_dir.exists() + + +@pytest.mark.parametrize( + "store_relative_path, compress", + [ + # test that all possible combinations still work + pytest.param(False, False, id="no_relative_path_no_compress"), + pytest.param(False, True, id="no_relative_path_with_compression"), + pytest.param(True, False, id="nodeports_options"), + pytest.param(True, True, id="with_relative_path_with_compression"), + ], +) +async def test_regression_archive_hash_does_not_change( + mixed_file_types: Path, + tmp_path: Path, + store_relative_path: bool, + compress: bool, +): + destination_path = tmp_path / "archives_to_compare" + destination_path.mkdir(parents=True, exist_ok=True) + + first_archive = destination_path / "first" + second_archive = destination_path / "second" + assert not first_archive.exists() + assert not second_archive.exists() + assert first_archive != second_archive + + await archive_dir( + mixed_file_types, + first_archive, + compress=compress, + store_relative_path=store_relative_path, + ) + + _touch_all_files_in_path(mixed_file_types) + + await archive_dir( + mixed_file_types, + second_archive, + compress=compress, + store_relative_path=store_relative_path, + ) + + _, first_hash = _compute_hash(first_archive) + _, second_hash = _compute_hash(second_archive) + assert first_hash == second_hash diff --git a/packages/simcore-sdk/requirements/_base.txt b/packages/simcore-sdk/requirements/_base.txt index a2d040670d0..b57f881bbc4 100644 --- a/packages/simcore-sdk/requirements/_base.txt +++ b/packages/simcore-sdk/requirements/_base.txt @@ -247,6 +247,8 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.8.1 diff --git a/services/api-server/requirements/_base.txt b/services/api-server/requirements/_base.txt index ea43eef9e4a..76bdd46ba36 100644 --- a/services/api-server/requirements/_base.txt +++ b/services/api-server/requirements/_base.txt @@ -467,6 +467,10 @@ redis==5.0.4 # -c requirements/../../../requirements/constraints.txt # -r requirements/../../../packages/service-library/requirements/_base.in # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/autoscaling/requirements/_base.txt b/services/autoscaling/requirements/_base.txt index 4895d0ce00a..ee6878dd43b 100644 --- a/services/autoscaling/requirements/_base.txt +++ b/services/autoscaling/requirements/_base.txt @@ -432,6 +432,10 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/catalog/requirements/_base.txt b/services/catalog/requirements/_base.txt index f69139967eb..5ed5819a125 100644 --- a/services/catalog/requirements/_base.txt +++ b/services/catalog/requirements/_base.txt @@ -323,6 +323,8 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/clusters-keeper/requirements/_base.txt b/services/clusters-keeper/requirements/_base.txt index 9adaa406642..f6226e21629 100644 --- a/services/clusters-keeper/requirements/_base.txt +++ b/services/clusters-keeper/requirements/_base.txt @@ -430,6 +430,10 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/dask-sidecar/requirements/_base.txt b/services/dask-sidecar/requirements/_base.txt index a04b02047b3..a8a80bd3301 100644 --- a/services/dask-sidecar/requirements/_base.txt +++ b/services/dask-sidecar/requirements/_base.txt @@ -324,6 +324,8 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/datcore-adapter/requirements/_base.txt b/services/datcore-adapter/requirements/_base.txt index d1ed690f390..ed00053e60d 100644 --- a/services/datcore-adapter/requirements/_base.txt +++ b/services/datcore-adapter/requirements/_base.txt @@ -287,6 +287,8 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/director-v2/requirements/_base.txt b/services/director-v2/requirements/_base.txt index 500eb0159de..a151f9fb0ab 100644 --- a/services/director-v2/requirements/_base.txt +++ b/services/director-v2/requirements/_base.txt @@ -555,6 +555,10 @@ referencing==0.29.3 # -c requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/dynamic-scheduler/requirements/_base.txt b/services/dynamic-scheduler/requirements/_base.txt index f60e814f088..714f37a8b3e 100644 --- a/services/dynamic-scheduler/requirements/_base.txt +++ b/services/dynamic-scheduler/requirements/_base.txt @@ -36,6 +36,7 @@ arrow==1.3.0 # -r requirements/../../../packages/models-library/requirements/_base.in # -r requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/_base.in # -r requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/_base.in asgiref==3.8.1 # via opentelemetry-instrumentation-asgi async-timeout==4.0.3 @@ -298,6 +299,8 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 @@ -390,6 +393,8 @@ wrapt==1.16.0 # via # deprecated # opentelemetry-instrumentation +wsproto==1.2.0 + # via simple-websocket yarl==1.9.4 # via # -r requirements/../../../packages/postgres-database/requirements/_base.in diff --git a/services/dynamic-sidecar/requirements/_base.txt b/services/dynamic-sidecar/requirements/_base.txt index 9cdc66a8256..35cd6843f2b 100644 --- a/services/dynamic-sidecar/requirements/_base.txt +++ b/services/dynamic-sidecar/requirements/_base.txt @@ -418,6 +418,10 @@ referencing==0.29.3 # -c requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/efs-guardian/requirements/_base.txt b/services/efs-guardian/requirements/_base.txt index 6d67dee0772..9f98cc7a99d 100644 --- a/services/efs-guardian/requirements/_base.txt +++ b/services/efs-guardian/requirements/_base.txt @@ -364,6 +364,10 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/invitations/requirements/_base.txt b/services/invitations/requirements/_base.txt index 590de2833e0..5930af799f3 100644 --- a/services/invitations/requirements/_base.txt +++ b/services/invitations/requirements/_base.txt @@ -272,6 +272,8 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/payments/requirements/_base.txt b/services/payments/requirements/_base.txt index e8c6dd841e1..d4c08c97591 100644 --- a/services/payments/requirements/_base.txt +++ b/services/payments/requirements/_base.txt @@ -338,6 +338,8 @@ referencing==0.29.3 # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/resource-usage-tracker/requirements/_base.txt b/services/resource-usage-tracker/requirements/_base.txt index 75e0ca71ed2..d31e353e4c3 100644 --- a/services/resource-usage-tracker/requirements/_base.txt +++ b/services/resource-usage-tracker/requirements/_base.txt @@ -447,6 +447,10 @@ referencing==0.29.3 # jsonschema-specifications regex==2023.12.25 # via dateparser +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.2 # via # httmock diff --git a/services/storage/requirements/_base.txt b/services/storage/requirements/_base.txt index f65c39f7b71..69d470d7fa3 100644 --- a/services/storage/requirements/_base.txt +++ b/services/storage/requirements/_base.txt @@ -423,6 +423,10 @@ referencing==0.29.3 # jsonschema # jsonschema-path # jsonschema-specifications +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.2 # via # jsonschema-path diff --git a/services/web/server/requirements/_base.txt b/services/web/server/requirements/_base.txt index 770ea9b9d9e..b7d14fef70a 100644 --- a/services/web/server/requirements/_base.txt +++ b/services/web/server/requirements/_base.txt @@ -481,6 +481,10 @@ redis==5.0.4 # -r requirements/../../../../packages/service-library/requirements/_base.in # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in # -r requirements/_base.in +repro-zipfile==0.3.1 + # via + # -r requirements/../../../../packages/service-library/requirements/_base.in + # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.2 # via # opentelemetry-exporter-otlp-proto-http diff --git a/tests/swarm-deploy/requirements/_test.txt b/tests/swarm-deploy/requirements/_test.txt index 432abdef719..16c8a272e9b 100644 --- a/tests/swarm-deploy/requirements/_test.txt +++ b/tests/swarm-deploy/requirements/_test.txt @@ -387,6 +387,10 @@ referencing==0.29.3 # -c requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema # jsonschema-specifications +repro-zipfile==0.3.1 + # via + # -r requirements/../../../packages/service-library/requirements/_base.in + # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via # -r requirements/../../../packages/postgres-database/requirements/_migration.txt