diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 5d49489e09..eb15930d9a 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v4 - name: Crowdin Action - uses: crowdin/github-action@v1.13.0 + uses: crowdin/github-action@v1.13.1 with: # Tokens project_id: ${{ secrets.CROWDIN_PROJECT_ID }} diff --git a/docs/changes/5.3.3.md b/docs/changes/5.3.3.md index aec94a2997..20896bb2b1 100644 --- a/docs/changes/5.3.3.md +++ b/docs/changes/5.3.3.md @@ -13,7 +13,7 @@ Release date: `2023-xx-xx` ### Direct Transfer -- [NXDRIVE-2](https://jira.nuxeo.com/browse/NXDRIVE-2): +- [NXDRIVE-2711](https://jira.nuxeo.com/browse/NXDRIVE-2711): Show that upload is still alive for very large files ## GUI @@ -43,11 +43,12 @@ Release date: `2023-xx-xx` - Upgraded `black` from 23.3.0 to 23.9.1 - Upgraded `boto3` from 1.26.115 to 1.28.50 - Upgraded `botocore` from 1.29.115 to 1.31.50 +- Upgraded `certifi` from 2022.12.7 to 2023.7.22 - Upgraded `cfgv` from 3.3.0 to 3.4.0 - Upgraded `codecov/codecov-action@v3.1.4` from 3.1.2 to 3.1.4 - Upgraded `comtypes` from 1.1.10 to 1.2.0 - Upgraded `coverage[toml]` from 7.2.7 to 7.3.1 -- Upgraded `crowdin/github-action` from 1.12.0 to 1.13.0 +- Upgraded `crowdin/github-action` from 1.13.0 to 1.13.1 - Upgraded `distlib` from 0.3.2 to 0.3.7 - Upgraded `docker/build-push-action` from 4.1.1 to 5.0.0 - Upgraded `docker/login-action` from 2.2.0 to 3.0.0 @@ -62,6 +63,7 @@ Release date: `2023-xx-xx` - Upgraded `flake8` from 3.9.2 to 6.1.0 - Upgraded `iniconfig` from 1.1.1 to 2.0.0 - Upgraded `mccabe` from 0.6.1 to 0.7.0 +- Upgraded `mypy` from 1.2.0 to 1.5.1 - Upgraded `pycodestyle` from 2.7.0 to 2.11.0 - Upgraded `junitparser` from 2.1.1 to 3.1.0 - Upgraded `more-itertools` from 8.12.0 to 10.1.0 @@ -82,6 +84,7 @@ Release date: `2023-xx-xx` - Upgraded `typing-extensions` from 4.0.1 to 4.7.1 - Upgraded `vulture` from 2.3 to 2.9.1 - Upgraded `wcwidth` from 0.2.5 to 0.2.6 + ## Technical Changes -- +- Added `finalizing_status` attribute in LinkingAction class diff --git a/nxdrive/client/uploader/__init__.py b/nxdrive/client/uploader/__init__.py index 812fa719e7..601d90db8c 100644 --- a/nxdrive/client/uploader/__init__.py +++ b/nxdrive/client/uploader/__init__.py @@ -416,7 +416,7 @@ def _link_blob_to_doc( self._set_transfer_status(transfer, TransferStatus.ONGOING) raise exc - def link_blob_to_doc( # type: ignore[return] + def link_blob_to_doc( self, command: str, transfer: Upload, @@ -451,15 +451,19 @@ def link_blob_to_doc( # type: ignore[return] kwargs["headers"] = headers try: doc_type = kwargs.get("doc_type", "") - if transfer.is_direct_transfer and doc_type and doc_type != "": - res = self._transfer_docType_file(transfer, headers, doc_type) - else: - res = self._transfer_autoType_file(command, blob, kwargs) - - return res + return ( + self._transfer_docType_file(transfer, headers, doc_type) + if transfer.is_direct_transfer and doc_type and doc_type != "" + else self._transfer_autoType_file(command, blob, kwargs) + ) except Exception as exc: err = f"Error while linking blob to doc: {exc!r}" log.warning(err) + action.finalizing_status = "Error" + if "TCPKeepAliveHTTPSConnectionPool" not in str(exc): + transfer.request_uid = str(uuid4()) + self.dao.update_upload_requestid(transfer) + raise exc finally: action.finish_action() diff --git a/nxdrive/dao/engine.py b/nxdrive/dao/engine.py index 38705b6795..9f52a18d90 100644 --- a/nxdrive/dao/engine.py +++ b/nxdrive/dao/engine.py @@ -2381,6 +2381,13 @@ def update_upload(self, upload: Upload, /) -> None: sql = "UPDATE Uploads SET batch = ? WHERE uid = ?" c.execute(sql, (json.dumps(batch), upload.uid)) + def update_upload_requestid(self, upload: Upload, /) -> None: + """In case of error during linking, update request_uid for upload""" + with self.lock: + c = self._get_write_connection().cursor() + sql = "UPDATE Uploads SET request_uid = ? WHERE uid = ?" + c.execute(sql, (upload.request_uid, upload.uid)) + def pause_transfer( self, nature: str, diff --git a/nxdrive/data/i18n/i18n.json b/nxdrive/data/i18n/i18n.json index 2962170574..69a6120b0e 100644 --- a/nxdrive/data/i18n/i18n.json +++ b/nxdrive/data/i18n/i18n.json @@ -106,6 +106,7 @@ "DIRECT_TRANSFER_DETAILS": "[%1%] %2 of %3", "DIRECT_TRANSFER_END": "Transfer done: \"%1\"", "DIRECT_TRANSFER_ERROR": "Transfer error: \"%1\"", + "DIRECT_TRANSFER_FINALIZING_ERROR": "An error occurred during the transfer, it will resume shortly.", "DIRECT_TRANSFER_NO_ACCOUNT": "Cannot use the Direct Transfer feature with no account, aborting.", "DIRECT_TRANSFER_NOT_ALLOWED": "Direct Transfer of \"%1\" is not allowed for synced files.", "DIRECT_TRANSFER_NOT_ENABLED": "The Direct Transfer feature is not enabled.", diff --git a/nxdrive/data/qml/TransferItem.qml b/nxdrive/data/qml/TransferItem.qml index eb030950c1..cd1d79fafe 100644 --- a/nxdrive/data/qml/TransferItem.qml +++ b/nxdrive/data/qml/TransferItem.qml @@ -77,5 +77,13 @@ Rectangle { } } } + + ScaledText { + text: qsTr("DIRECT_TRANSFER_FINALIZING_ERROR") + tl.tr + color: secondaryText + visible: finalizing && finalizing_status + Layout.leftMargin: icon.width + 5 + font.pointSize: point_size * 0.8 + } } } diff --git a/nxdrive/engine/activity.py b/nxdrive/engine/activity.py index d43e459869..b8713cefc3 100644 --- a/nxdrive/engine/activity.py +++ b/nxdrive/engine/activity.py @@ -54,8 +54,7 @@ def get_current_action(*, thread_id: int = None) -> Optional["Action"]: @staticmethod def finish_action() -> None: - action = Action.actions.pop(current_thread_id(), None) - if action: + if action := Action.actions.pop(current_thread_id(), None): action.finish() def finish(self) -> None: @@ -149,6 +148,15 @@ def progress(self, value: float, /) -> None: self.progressing.emit(self) + @property + def finalizing_status(self) -> str: + return self._finalizing_status + + @finalizing_status.setter + def finalizing_status(self, value: str, /) -> None: + self._finalizing_status = value + self.progressing.emit(self) + def get_percent(self) -> float: if self.size < 0 or (self.empty and not self.uploaded): return 0.0 @@ -257,6 +265,13 @@ def __init__( doc_pair=doc_pair, ) self.progress = size + self.finalizing_status = "" + + def export(self) -> Dict[str, Any]: + return { + **super().export(), + "finalizing_status": self.finalizing_status, + } def tooltip(doing: str): # type: ignore diff --git a/nxdrive/gui/view.py b/nxdrive/gui/view.py index 98882c34c8..b0fdbceec9 100755 --- a/nxdrive/gui/view.py +++ b/nxdrive/gui/view.py @@ -273,6 +273,7 @@ class DirectTransferModel(QAbstractListModel): REMOTE_PARENT_REF = qt.UserRole + 10 SHADOW = qt.UserRole + 11 # Tell the interface if the row should be visible or not DOC_PAIR = qt.UserRole + 12 + FINALIZING_STATUS = qt.UserRole + 13 def __init__(self, translate: Callable, /, *, parent: QObject = None) -> None: super().__init__(parent) @@ -291,6 +292,7 @@ def __init__(self, translate: Callable, /, *, parent: QObject = None) -> None: self.REMOTE_PARENT_REF: b"remote_parent_ref", self.SHADOW: b"shadow", self.DOC_PAIR: b"doc_pair", + self.FINALIZING_STATUS: b"finalizing_status", } # Pretty print self.psize = partial(sizeof_fmt, suffix=self.tr("BYTE_ABBREV")) @@ -353,6 +355,8 @@ def data(self, index: QModelIndex, role: int, /) -> Any: return self.psize(row["filesize"]) if role == self.TRANSFERRED: return self.psize(row["filesize"] * row["progress"] / 100) + if role == self.FINALIZING_STATUS: + return row.get("finalizing_status") return row[self.names[role].decode()] def setData(self, index: QModelIndex, value: Any, /, *, role: int = None) -> None: @@ -375,6 +379,9 @@ def set_progress(self, action: Dict[str, Any], /) -> None: self.setData(idx, action["progress"], role=self.TRANSFERRED) if action["action_type"] == "Linking": self.setData(idx, True, role=self.FINALIZING) + self.setData( + idx, action["finalizing_status"], role=self.FINALIZING_STATUS + ) def add_item(self, parent: QModelIndex, n_item: Dict[str, Any], /) -> None: """Add an item to existing list.""" diff --git a/tests/functional/test_view.py b/tests/functional/test_view.py deleted file mode 100644 index 8ac1897b1f..0000000000 --- a/tests/functional/test_view.py +++ /dev/null @@ -1,10 +0,0 @@ -from nxdrive.gui.view import FileModel - - -def test_foldersDialog(): - def func(): - return True - - file_model = FileModel(func) - returned_val = file_model.add_files([{"key": "val"}]) - assert not returned_val diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 44a037bf51..5ee49abf9f 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -1,19 +1,23 @@ import os import shutil import time -from typing import Optional +from typing import Any, Callable, Optional from uuid import uuid4 import pytest from nxdrive.client.remote_client import Remote +from nxdrive.constants import TransferStatus from nxdrive.dao.engine import EngineDAO from nxdrive.dao.manager import ManagerDAO from nxdrive.engine.engine import Engine from nxdrive.engine.processor import Processor +from nxdrive.gui.view import DirectTransferModel from nxdrive.manager import Manager -from nxdrive.objects import DocPair +from nxdrive.objects import DocPair, Upload from nxdrive.osi import AbstractOSIntegration +from nxdrive.qt import constants as qt +from nxdrive.qt.imports import QObject from nxdrive.updater.darwin import Updater from nxdrive.utils import normalized_path @@ -141,6 +145,13 @@ def __init__(self, tmp_path): super().__init__(self, final_app) +class MockDirectTransferModel(DirectTransferModel): + def __init__( + self, translate: Callable[..., Any], /, *, parent: QObject = None + ) -> None: + super().__init__(translate, parent=parent) + + @pytest.fixture() def engine_dao(tmp_path): dao = MockEngineDAO @@ -188,3 +199,43 @@ def processor(engine, engine_dao): processor.remote = Remote processor.dao = engine_dao return processor + + +@pytest.fixture() +def upload(): + upload = Upload + upload.path = "/tmp" + upload.status = TransferStatus.ONGOING + upload.engine = f"{engine}" + upload.is_direct_edit = False + upload.is_direct_transfer = True + upload.filesize = "23.0" + upload.batch = {"batchID": f"{str(uuid4())}"} + upload.chunk_size = "345" + upload.remote_parent_path = "/tmp/remote_path" + upload.remote_parent_ref = "/tmp/remote_path_ref" + upload.doc_pair = "test_file" + upload.request_uid = str(uuid4()) + return upload + + +@pytest.fixture() +def direct_transfer_model(): + direct_transfer_model = MockDirectTransferModel + direct_transfer_model.FINALIZING_STATUS = qt.UserRole + 13 + direct_transfer_model.items = [ + { + "uid": 1, + "name": "a.txt", + "filesize": 142936511610, + "status": "", + "engine": "51a2c2dc641311ee87fb...bfc0ec09fa", + "progress": 100.0, + "doc_pair": 1, + "remote_parent_path": "/default-domain/User...TestFolder", + "remote_parent_ref": "7b7886ea-5ad9-460d-8...1607ea0081", + "shadow": True, + "finalizing": True, + } + ] + return direct_transfer_model diff --git a/tests/unit/test_action.py b/tests/unit/test_action.py index fbc7d1ecdd..1bff8b34bc 100644 --- a/tests/unit/test_action.py +++ b/tests/unit/test_action.py @@ -244,6 +244,9 @@ def test_finalization_action(tmp): action = LinkingAction(filepath, filepath.stat().st_size) assert action.type == "Linking" + action.finalizing_status = "Error occurred while linking" + details = action.export() + assert details["finalizing_status"] == "Error occurred while linking" Action.finish_action() assert action.finished diff --git a/tests/unit/test_client_uploader.py b/tests/unit/test_client_uploader.py new file mode 100644 index 0000000000..f1a2dff404 --- /dev/null +++ b/tests/unit/test_client_uploader.py @@ -0,0 +1,50 @@ +from unittest.mock import Mock +from uuid import uuid4 + +import pytest +import requests +from nuxeo.models import FileBlob + +from nxdrive.client.remote_client import Remote +from nxdrive.client.uploader import BaseUploader + + +@pytest.fixture +def baseuploader(): + remote = Remote + remote.dao = Mock() + return BaseUploader(remote) + + +def test_link_blob_to_doc(baseuploader, upload, tmp_path, monkeypatch): + """Test system network and server side exception handling while linking blob to document""" + file = tmp_path / f"{uuid4()}.txt" + file.write_bytes(b"content") + + def mock_transfer_autoType_file(*args, **kwargs): + raise requests.exceptions.RequestException("Connection Error") + + monkeypatch.setattr( + baseuploader, "_transfer_autoType_file", mock_transfer_autoType_file + ) + + # server side exceptions + with pytest.raises(requests.exceptions.RequestException): + baseuploader.link_blob_to_doc( + "Filemanager.Import", upload, FileBlob(str(file)), False + ) + + def mock_transfer_autoType_file(*args, **kwargs): + raise requests.exceptions.RequestException( + "TCPKeepAliveHTTPSConnectionPool: Connection Error" + ) + + monkeypatch.setattr( + baseuploader, "_transfer_autoType_file", mock_transfer_autoType_file + ) + + # system network disconnect + with pytest.raises(requests.exceptions.RequestException): + baseuploader.link_blob_to_doc( + "Filemanager.Import", upload, FileBlob(str(file)), False + ) diff --git a/tests/unit/test_engine_dao.py b/tests/unit/test_engine_dao.py index 9cba64f50a..1b2a07c2eb 100644 --- a/tests/unit/test_engine_dao.py +++ b/tests/unit/test_engine_dao.py @@ -1,8 +1,9 @@ import os import sqlite3 from datetime import datetime +from multiprocessing import RLock from pathlib import Path -from unittest.mock import patch +from unittest.mock import Mock, patch from uuid import uuid4 from nxdrive.constants import TransferStatus @@ -408,7 +409,7 @@ def test_migration_db_v10(engine_dao): """Verify Downloads after migration from v9 to v10.""" with engine_dao("engine_migration_10.db") as dao: downloads = list(dao.get_downloads()) - assert len(downloads) == 0 + assert not downloads states = list(dao.get_states_from_partial_local(Path())) assert len(states) == 4 @@ -608,3 +609,21 @@ def test_migration_interface(): assert not interface.downgrade(cursor) assert not interface.previous_version assert not interface.version + + +def test_update_upload_requestid(engine_dao, upload): + """Test to save upload and update reuqest_uid of existing row""" + engine_dao.lock = RLock() + with engine_dao("engine_migration_18.db") as dao: + engine_dao.directTransferUpdated = Mock() + # Save New upload + engine_dao.save_upload(dao, upload) + + assert upload.uid + + previous_request_id = upload.request_uid + upload.request_uid = str(uuid4()) + # Update request_uid of existing record + engine_dao.update_upload_requestid(dao, upload) + + assert previous_request_id != upload.request_uid diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 2e9133e5ca..5c0d96cc95 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -413,7 +413,7 @@ def test_request_verify_ca_bundle_file(caplog, tmp_path): # Save the certificate for the first time caplog.clear() cert = nxdrive.utils.requests_verify(ca_bundle, False) - path = "" if type(cert) == bool else cert + path = "" if isinstance(bool, type(cert)) else cert final_certificate = Path(path) records = [line.message for line in caplog.records] assert len(records) == 3 @@ -451,7 +451,7 @@ def test_request_verify_ca_bundle_file_is_str(caplog, tmp_path): # Save the certificate for the first time caplog.clear() cert = nxdrive.utils.requests_verify(ca_bundle, False) - path = "" if type(cert) == bool else cert + path = "" if isinstance(bool, type(cert)) else cert final_certificate = Path(path) records = [line.message for line in caplog.records] assert len(records) == 3 @@ -494,7 +494,7 @@ def test_request_verify_ca_bundle_file_mimic_updates(caplog, tmp_path): # Save the certificate for the first time caplog.clear() cert = nxdrive.utils.requests_verify(ca_bundle, False) - path = "" if type(cert) == bool else cert + path = "" if isinstance(bool, type(cert)) else cert final_certificate_1 = Path(path) records = [line.message for line in caplog.records] assert len(records) == 3 diff --git a/tests/unit/test_view.py b/tests/unit/test_view.py new file mode 100644 index 0000000000..f5d78674fe --- /dev/null +++ b/tests/unit/test_view.py @@ -0,0 +1,37 @@ +from unittest.mock import Mock + +from nxdrive.gui.view import FileModel +from nxdrive.qt.imports import QModelIndex + + +def test_foldersDialog(): + def func(): + return True + + file_model = FileModel(func) + returned_val = file_model.add_files([{"key": "val"}]) + assert not returned_val + + +def test_set_progress(direct_transfer_model): + """Test the finalize state after 100% progress""" + action = { + "engine": "51a2c2dc641311ee87fb...bfc0ec09fa", + "doc_pair": 1, + "progress": "100", + "action_type": "Linking", + "finalizing_status": "Finalize the status", + } + + direct_transfer_model.createIndex = Mock(return_value=1) + direct_transfer_model.setData = Mock() + direct_transfer_model.set_progress(direct_transfer_model, action) + + +def test_data(direct_transfer_model): + """Test get row data as per role""" + index = QModelIndex + index.row = Mock(return_value=0) + direct_transfer_model.data( + direct_transfer_model, index, direct_transfer_model.FINALIZING_STATUS + ) diff --git a/tools/deps/requirements-tests.txt b/tools/deps/requirements-tests.txt index 88b719f73c..cd652d0672 100644 --- a/tools/deps/requirements-tests.txt +++ b/tools/deps/requirements-tests.txt @@ -150,33 +150,34 @@ more-itertools==10.1.0 \ --hash=sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a \ --hash=sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6 # via pytest -mypy==1.2.0 \ - --hash=sha256:023fe9e618182ca6317ae89833ba422c411469156b690fde6a315ad10695a521 \ - --hash=sha256:031fc69c9a7e12bcc5660b74122ed84b3f1c505e762cc4296884096c6d8ee140 \ - --hash=sha256:2de7babe398cb7a85ac7f1fd5c42f396c215ab3eff731b4d761d68d0f6a80f48 \ - --hash=sha256:2e93a8a553e0394b26c4ca683923b85a69f7ccdc0139e6acd1354cc884fe0128 \ - --hash=sha256:390bc685ec209ada4e9d35068ac6988c60160b2b703072d2850457b62499e336 \ - --hash=sha256:3a2d219775a120581a0ae8ca392b31f238d452729adbcb6892fa89688cb8306a \ - --hash=sha256:3efde4af6f2d3ccf58ae825495dbb8d74abd6d176ee686ce2ab19bd025273f41 \ - --hash=sha256:4a99fe1768925e4a139aace8f3fb66db3576ee1c30b9c0f70f744ead7e329c9f \ - --hash=sha256:4b41412df69ec06ab141808d12e0bf2823717b1c363bd77b4c0820feaa37249e \ - --hash=sha256:4c8d8c6b80aa4a1689f2a179d31d86ae1367ea4a12855cc13aa3ba24bb36b2d8 \ - --hash=sha256:4d19f1a239d59f10fdc31263d48b7937c585810288376671eaf75380b074f238 \ - --hash=sha256:4e4a682b3f2489d218751981639cffc4e281d548f9d517addfd5a2917ac78119 \ - --hash=sha256:695c45cea7e8abb6f088a34a6034b1d273122e5530aeebb9c09626cea6dca4cb \ - --hash=sha256:701189408b460a2ff42b984e6bd45c3f41f0ac9f5f58b8873bbedc511900086d \ - --hash=sha256:70894c5345bea98321a2fe84df35f43ee7bb0feec117a71420c60459fc3e1eed \ - --hash=sha256:8293a216e902ac12779eb7a08f2bc39ec6c878d7c6025aa59464e0c4c16f7eb9 \ - --hash=sha256:8d26b513225ffd3eacece727f4387bdce6469192ef029ca9dd469940158bc89e \ - --hash=sha256:a197ad3a774f8e74f21e428f0de7f60ad26a8d23437b69638aac2764d1e06a6a \ - --hash=sha256:bea55fc25b96c53affab852ad94bf111a3083bc1d8b0c76a61dd101d8a388cf5 \ - --hash=sha256:c9a084bce1061e55cdc0493a2ad890375af359c766b8ac311ac8120d3a472950 \ - --hash=sha256:d0e9464a0af6715852267bf29c9553e4555b61f5904a4fc538547a4d67617937 \ - --hash=sha256:d8e9187bfcd5ffedbe87403195e1fc340189a68463903c39e2b63307c9fa0394 \ - --hash=sha256:eaeaa0888b7f3ccb7bcd40b50497ca30923dba14f385bde4af78fac713d6d6f6 \ - --hash=sha256:f46af8d162f3d470d8ffc997aaf7a269996d205f9d746124a179d3abe05ac602 \ - --hash=sha256:f70a40410d774ae23fcb4afbbeca652905a04de7948eaf0b1789c8d1426b72d1 \ - --hash=sha256:fe91be1c51c90e2afe6827601ca14353bbf3953f343c2129fa1e247d55fd95ba +mypy==1.5.1 \ + --hash=sha256:159aa9acb16086b79bbb0016145034a1a05360626046a929f84579ce1666b315 \ + --hash=sha256:258b22210a4a258ccd077426c7a181d789d1121aca6db73a83f79372f5569ae0 \ + --hash=sha256:26f71b535dfc158a71264e6dc805a9f8d2e60b67215ca0bfa26e2e1aa4d4d373 \ + --hash=sha256:26fb32e4d4afa205b24bf645eddfbb36a1e17e995c5c99d6d00edb24b693406a \ + --hash=sha256:2fc3a600f749b1008cc75e02b6fb3d4db8dbcca2d733030fe7a3b3502902f161 \ + --hash=sha256:32cb59609b0534f0bd67faebb6e022fe534bdb0e2ecab4290d683d248be1b275 \ + --hash=sha256:330857f9507c24de5c5724235e66858f8364a0693894342485e543f5b07c8693 \ + --hash=sha256:361da43c4f5a96173220eb53340ace68cda81845cd88218f8862dfb0adc8cddb \ + --hash=sha256:4a465ea2ca12804d5b34bb056be3a29dc47aea5973b892d0417c6a10a40b2d65 \ + --hash=sha256:51cb1323064b1099e177098cb939eab2da42fea5d818d40113957ec954fc85f4 \ + --hash=sha256:57b10c56016adce71fba6bc6e9fd45d8083f74361f629390c556738565af8eeb \ + --hash=sha256:596fae69f2bfcb7305808c75c00f81fe2829b6236eadda536f00610ac5ec2243 \ + --hash=sha256:5d627124700b92b6bbaa99f27cbe615c8ea7b3402960f6372ea7d65faf376c14 \ + --hash=sha256:6ac9c21bfe7bc9f7f1b6fae441746e6a106e48fc9de530dea29e8cd37a2c0cc4 \ + --hash=sha256:82cb6193de9bbb3844bab4c7cf80e6227d5225cc7625b068a06d005d861ad5f1 \ + --hash=sha256:8f772942d372c8cbac575be99f9cc9d9fb3bd95c8bc2de6c01411e2c84ebca8a \ + --hash=sha256:9fece120dbb041771a63eb95e4896791386fe287fefb2837258925b8326d6160 \ + --hash=sha256:a156e6390944c265eb56afa67c74c0636f10283429171018446b732f1a05af25 \ + --hash=sha256:a9ec1f695f0c25986e6f7f8778e5ce61659063268836a38c951200c57479cc12 \ + --hash=sha256:abed92d9c8f08643c7d831300b739562b0a6c9fcb028d211134fc9ab20ccad5d \ + --hash=sha256:b031b9601f1060bf1281feab89697324726ba0c0bae9d7cd7ab4b690940f0b92 \ + --hash=sha256:c543214ffdd422623e9fedd0869166c2f16affe4ba37463975043ef7d2ea8770 \ + --hash=sha256:d28ddc3e3dfeab553e743e532fb95b4e6afad51d4706dd22f28e1e5e664828d2 \ + --hash=sha256:f33592ddf9655a4894aef22d134de7393e95fcbdc2d15c1ab65828eee5c66c70 \ + --hash=sha256:f6b0e77db9ff4fda74de7df13f30016a0a663928d669c9f2c057048ba44f09bb \ + --hash=sha256:f757063a83970d67c444f6e01d9550a7402322af3557ce7630d3c957386fa8f5 \ + --hash=sha256:ff0cedc84184115202475bbb46dd99f8dcb87fe24d5d0ddfc0fe6b8575c88d2f mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 diff --git a/tools/deps/requirements.txt b/tools/deps/requirements.txt index f54fd3d218..c0affdd21c 100644 --- a/tools/deps/requirements.txt +++ b/tools/deps/requirements.txt @@ -14,9 +14,9 @@ botocore==1.31.50 \ --hash=sha256:5038a407783ea394aaf0671d1086cf55cc1e7c303e1fac244b76adc78cc7ef07 \ --hash=sha256:a1343f2e38ea86e11247d61bd37a9d5656c16186f4a21b482c713589a054c605 # via boto3, s3transfer -certifi==2022.12.7 \ - --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ - --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 +certifi==2023.7.22 \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \