From 02019c3964405209c1c7bf15458f72bfed8199ea Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 14 Nov 2024 11:10:57 +0200 Subject: [PATCH 01/72] :arrow_up: Upgrade python-dateutil Resolves calling deprecated `datetime.utcfromtimestamp` method Signed-off-by: ff137 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d1395fcea8..3d47940686 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ pydid = "^0.5.1" pyjwt = "~2.9.0" pyld = "^2.0.4" pynacl = "~1.5.0" -python-dateutil = "~2.8.1" +python-dateutil = "^2.9.0" python-json-logger = "~2.0.7" pyyaml = "~6.0.2" qrcode = { version = ">=6.1,<7.0", extras = ["pil"] } From d8632ee2ce2a4ca2f0f5e21209ea277ebc3fd39d Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 14 Nov 2024 11:14:27 +0200 Subject: [PATCH 02/72] :art: Rename class to resolve PytestCollectionWarning Signed-off-by: ff137 --- acapy_agent/didcomm_v2/tests/test_adapters.py | 6 +++--- acapy_agent/transport/tests/test_pack_format.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/acapy_agent/didcomm_v2/tests/test_adapters.py b/acapy_agent/didcomm_v2/tests/test_adapters.py index 61ba698a14..56d861bfcb 100644 --- a/acapy_agent/didcomm_v2/tests/test_adapters.py +++ b/acapy_agent/didcomm_v2/tests/test_adapters.py @@ -15,7 +15,7 @@ from ..adapters import ResolverAdapter, SecretsAdapter, SecretsAdapterError -class TestDIDResolver(BaseDIDResolver): +class MockDIDResolver(BaseDIDResolver): async def setup(self, context: InjectionContext): return await super().setup(context) @@ -26,7 +26,7 @@ async def resolve( self, profile, did, - sercive_accept=None, + service_accept=None, ): return {"did": did, "test": "didDoc"} @@ -46,7 +46,7 @@ async def asyncSetUp(self): self.test_did = "did:test:0" self.invalid_did = "this shouldn't work" resolver = DIDResolver() - resolver.register_resolver(TestDIDResolver()) + resolver.register_resolver(MockDIDResolver()) self.res_adapter = ResolverAdapter(profile=self.profile, resolver=resolver) async def test_resolver_adapter_resolve_did(self): diff --git a/acapy_agent/transport/tests/test_pack_format.py b/acapy_agent/transport/tests/test_pack_format.py index 06e6e9dfe3..058d054bf6 100644 --- a/acapy_agent/transport/tests/test_pack_format.py +++ b/acapy_agent/transport/tests/test_pack_format.py @@ -221,7 +221,7 @@ async def test_get_recipient_keys_fails(self): serializer.get_recipient_keys(json.dumps(enc_message)) -class TestDIDCommMessaging(DIDCommMessaging): +class MockDIDCommMessaging(DIDCommMessaging): def __init__( self, ): @@ -255,7 +255,7 @@ async def test_errors(self): message_json = json.dumps(message) async with self.profile.session() as session: session.context.injector.bind_instance( - DIDCommMessaging, TestDIDCommMessaging() + DIDCommMessaging, MockDIDCommMessaging() ) with self.assertRaises(WireFormatParseError) as context: await wire_format.parse_message(session, message_json) @@ -273,7 +273,7 @@ async def test_errors(self): async def test_fallback(self): serializer = V2PackWireFormat() - test_dm = TestDIDCommMessaging() + test_dm = MockDIDCommMessaging() test_dm.packaging.unpack = mock.AsyncMock(side_effect=CryptoServiceError()) async with self.profile.session() as session: session.context.injector.bind_instance(DIDCommMessaging, test_dm) @@ -289,7 +289,7 @@ async def test_fallback(self): async def test_encode(self): serializer = V2PackWireFormat() - test_dm = TestDIDCommMessaging() + test_dm = MockDIDCommMessaging() test_dm.pack = mock.AsyncMock( return_value=PackResult( message=self.test_message, target_services=mock.MagicMock() From 36e47ce152ece618a78adf6c72ecfc9804c0c8ae Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 14 Nov 2024 11:25:23 +0200 Subject: [PATCH 03/72] :art: Replace deprecated `open_binary` method with `files` Signed-off-by: ff137 --- acapy_agent/config/logging/configurator.py | 2 +- acapy_agent/config/tests/test_logging.py | 59 +++++++++++++++++----- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/acapy_agent/config/logging/configurator.py b/acapy_agent/config/logging/configurator.py index 548508c0af..11763dca08 100644 --- a/acapy_agent/config/logging/configurator.py +++ b/acapy_agent/config/logging/configurator.py @@ -52,7 +52,7 @@ def load_resource(path: str, encoding: Optional[str] = None): else: # Package resource package, resource = components - bstream = resources.open_binary(package, resource) + bstream = resources.files(package).joinpath(resource).open("rb") if encoding: return io.TextIOWrapper(bstream, encoding=encoding) return bstream diff --git a/acapy_agent/config/tests/test_logging.py b/acapy_agent/config/tests/test_logging.py index 2e65770508..cf23074568 100644 --- a/acapy_agent/config/tests/test_logging.py +++ b/acapy_agent/config/tests/test_logging.py @@ -1,5 +1,5 @@ import contextlib -from io import StringIO +from io import BufferedReader, StringIO, TextIOWrapper from tempfile import NamedTemporaryFile from unittest import IsolatedAsyncioTestCase, mock @@ -110,24 +110,55 @@ def test_banner_did(self): def test_load_resource(self): # Testing local file access with mock.patch("builtins.open", mock.MagicMock()) as mock_open: - test_module.load_resource("abc", encoding="utf-8") + # First call succeeds + file_handle = mock.MagicMock(spec=TextIOWrapper) + mock_open.return_value = file_handle + result = test_module.load_resource("abc", encoding="utf-8") + mock_open.assert_called_once_with("abc", encoding="utf-8") + assert result == file_handle # Verify the returned file handle + + mock_open.reset_mock() + # Simulate IOError on second call mock_open.side_effect = IOError("insufficient privilege") # load_resource should absorb IOError - test_module.load_resource("abc", encoding="utf-8") + result = test_module.load_resource("abc", encoding="utf-8") + mock_open.assert_called_once_with("abc", encoding="utf-8") + assert result is None # Testing package resource access with encoding (text mode) - with mock.patch( - "importlib.resources.open_binary", mock.MagicMock() - ) as mock_open_binary, mock.patch( + with mock.patch("importlib.resources.files") as mock_files, mock.patch( "io.TextIOWrapper", mock.MagicMock() ) as mock_text_io_wrapper: - test_module.load_resource("abc:def", encoding="utf-8") - mock_open_binary.assert_called_once_with("abc", "def") - mock_text_io_wrapper.assert_called_once() + # Setup the mocks + mock_resource_path = mock.MagicMock() + mock_files.return_value.joinpath.return_value = mock_resource_path + mock_resource_handle = mock.MagicMock(spec=BufferedReader) + mock_resource_path.open.return_value = mock_resource_handle + mock_text_io_wrapper.return_value = mock.MagicMock(spec=TextIOWrapper) + + result = test_module.load_resource("abc:def", encoding="utf-8") + + # Assertions + mock_files.assert_called_once_with("abc") + mock_files.return_value.joinpath.assert_called_once_with("def") + mock_resource_path.open.assert_called_once_with("rb") + mock_text_io_wrapper.assert_called_once_with( + mock_resource_handle, encoding="utf-8" + ) + assert result is mock_text_io_wrapper.return_value # Testing package resource access without encoding (binary mode) - with mock.patch( - "importlib.resources.open_binary", mock.MagicMock() - ) as mock_open_binary: - test_module.load_resource("abc:def", encoding=None) - mock_open_binary.assert_called_once_with("abc", "def") + with mock.patch("importlib.resources.files") as mock_files: + # Setup the mocks + mock_resource_path = mock.MagicMock() + mock_files.return_value.joinpath.return_value = mock_resource_path + mock_resource_handle = mock.MagicMock(spec=BufferedReader) + mock_resource_path.open.return_value = mock_resource_handle + + result = test_module.load_resource("abc:def", encoding=None) + + # Assertions + mock_files.assert_called_once_with("abc") + mock_files.return_value.joinpath.assert_called_once_with("def") + mock_resource_path.open.assert_called_once_with("rb") + assert result == mock_resource_handle # Verify the returned binary stream From 573c2088d22e4e846bbb57840ae65d9cd7a72043 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 14 Nov 2024 12:51:51 +0200 Subject: [PATCH 04/72] :art: Replace deprecated `scope` keyword with `loop_scope` Signed-off-by: ff137 --- acapy_agent/multitenant/admin/tests/test_routes.py | 4 ++-- .../v1_0/handlers/tests/test_response_handler.py | 10 +++++----- .../examples/tests/test_mediator_ping_agents.py | 14 +++++++------- demo/playground/examples/tests/test_ping_agents.py | 14 +++++++------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/acapy_agent/multitenant/admin/tests/test_routes.py b/acapy_agent/multitenant/admin/tests/test_routes.py index 87dcdde88d..2431e6f6d5 100644 --- a/acapy_agent/multitenant/admin/tests/test_routes.py +++ b/acapy_agent/multitenant/admin/tests/test_routes.py @@ -143,7 +143,7 @@ async def test_wallets_list_query(self): } ) - @pytest.mark.asyncio(scope="function") + @pytest.mark.asyncio(loop_scope="function") async def test_wallet_create_tenant_settings(self): body = { "wallet_name": "test", @@ -796,7 +796,7 @@ async def test_wallet_create_token_x(self): ) await test_module.wallet_create_token(self.request) - @pytest.mark.asyncio(scope="function") + @pytest.mark.asyncio(loop_scope="function") async def test_wallet_remove_managed(self): self.request.has_body = False self.request.match_info = {"wallet_id": "dummy"} diff --git a/acapy_agent/protocols/didexchange/v1_0/handlers/tests/test_response_handler.py b/acapy_agent/protocols/didexchange/v1_0/handlers/tests/test_response_handler.py index d177e2109f..87abd74791 100644 --- a/acapy_agent/protocols/didexchange/v1_0/handlers/tests/test_response_handler.py +++ b/acapy_agent/protocols/didexchange/v1_0/handlers/tests/test_response_handler.py @@ -75,7 +75,7 @@ async def asyncSetUp(self): did_doc_attach=self.did_doc_attach, ) - @pytest.mark.asyncio(scope="function") + @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") async def test_called(self, mock_didx_mgr): mock_didx_mgr.return_value.accept_response = mock.CoroutineMock() @@ -89,7 +89,7 @@ async def test_called(self, mock_didx_mgr): ) assert not responder.messages - @pytest.mark.asyncio(scope="function") + @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") async def test_called_auto_ping(self, mock_didx_mgr): self.ctx.update_settings({"auto_ping_connection": True}) @@ -107,7 +107,7 @@ async def test_called_auto_ping(self, mock_didx_mgr): result, _ = messages[0] assert isinstance(result, Ping) - @pytest.mark.asyncio(scope="function") + @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") @mock.patch.object(connection_target, "ConnectionTarget") async def test_problem_report(self, mock_conn_target, mock_didx_mgr): @@ -144,7 +144,7 @@ async def test_problem_report(self, mock_conn_target, mock_didx_mgr): ) assert target == {"target_list": [mock_conn_target]} - @pytest.mark.asyncio(scope="function") + @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") @mock.patch.object(connection_target, "ConnectionTarget") async def test_problem_report_did_doc( @@ -191,7 +191,7 @@ async def test_problem_report_did_doc( ) assert target == {"target_list": [mock_conn_target]} - @pytest.mark.asyncio(scope="function") + @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") @mock.patch.object(connection_target, "ConnectionTarget") async def test_problem_report_did_doc_no_conn_target( diff --git a/demo/playground/examples/tests/test_mediator_ping_agents.py b/demo/playground/examples/tests/test_mediator_ping_agents.py index d734dc14d7..7b1a1c4af5 100644 --- a/demo/playground/examples/tests/test_mediator_ping_agents.py +++ b/demo/playground/examples/tests/test_mediator_ping_agents.py @@ -16,21 +16,21 @@ logger.info("start testing mediated connections...") -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def faber(): """faber agent fixture.""" logger.info(f"faber = {FABER}") yield Agent(FABER) -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def alice(): """resolver agent fixture.""" logger.info(f"alice = {ALICE}") yield Agent(ALICE) -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def multi_one(): """resolver agent fixture.""" agent = Agent(MULTI) @@ -42,7 +42,7 @@ def multi_one(): yield agent -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def mediation_invite(): invitation_url = os.getenv("MEDIATOR_INVITATION_URL") logger.info(f"MEDIATOR_INVITATION_URL = {invitation_url}") @@ -97,7 +97,7 @@ def initialize_mediation(agent: Agent, invitation): return result -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def faber_mediator(faber, mediation_invite): logger.info("faber_mediator...") result = initialize_mediation(faber, mediation_invite) @@ -105,7 +105,7 @@ def faber_mediator(faber, mediation_invite): yield result -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def alice_mediator(alice, mediation_invite): logger.info("alice_mediator...") result = initialize_mediation(alice, mediation_invite) @@ -113,7 +113,7 @@ def alice_mediator(alice, mediation_invite): yield result -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def multi_one_mediator(multi_one, mediation_invite): logger.info("multi_one_mediator...") result = initialize_mediation(multi_one, mediation_invite) diff --git a/demo/playground/examples/tests/test_ping_agents.py b/demo/playground/examples/tests/test_ping_agents.py index 64cb4cdad1..13846181f8 100644 --- a/demo/playground/examples/tests/test_ping_agents.py +++ b/demo/playground/examples/tests/test_ping_agents.py @@ -11,19 +11,19 @@ from . import ALICE, FABER, MULTI, Agent, logger -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def faber(): """faber agent fixture.""" yield Agent(FABER) -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def alice(): """resolver agent fixture.""" yield Agent(ALICE) -@pytest.fixture(scope="session") +@pytest.fixture(loop_scope="session") def multi_one(): """resolver agent fixture.""" agent = Agent(MULTI) @@ -35,7 +35,7 @@ def multi_one(): yield agent -@pytest.fixture(scope="session", autouse=True) +@pytest.fixture(loop_scope="session", autouse=True) def alice_faber_connection(faber, alice): """Established connection filter.""" logger.info("faber create invitation to alice") @@ -48,7 +48,7 @@ def alice_faber_connection(faber, alice): return result -@pytest.fixture(scope="session", autouse=True) +@pytest.fixture(loop_scope="session", autouse=True) def faber_alice_connection(faber, alice): """Established connection filter.""" logger.info("alice create invitation to faber") @@ -61,7 +61,7 @@ def faber_alice_connection(faber, alice): return result -@pytest.fixture(scope="session", autouse=True) +@pytest.fixture(loop_scope="session", autouse=True) def alice_multi_one_connection(multi_one, alice): """Established connection filter.""" logger.info("multi_one create invitation to alice") @@ -74,7 +74,7 @@ def alice_multi_one_connection(multi_one, alice): return result -@pytest.fixture(scope="session", autouse=True) +@pytest.fixture(loop_scope="session", autouse=True) def multi_one_alice_connection(multi_one, alice): """Established connection filter.""" logger.info("alice create invitation to multi_one") From 70364a41388eeb6efb5c97d2b279e1bfe957e15b Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 14 Nov 2024 12:59:48 +0200 Subject: [PATCH 05/72] :art: Filter Aries RFC 0160 DeprecationWarning in tests Signed-off-by: ff137 --- acapy_agent/core/tests/test_conductor.py | 1 + acapy_agent/protocols/connections/v1_0/tests/test_manager.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/acapy_agent/core/tests/test_conductor.py b/acapy_agent/core/tests/test_conductor.py index 4d3da3959b..875623deee 100644 --- a/acapy_agent/core/tests/test_conductor.py +++ b/acapy_agent/core/tests/test_conductor.py @@ -1186,6 +1186,7 @@ async def test_dispatch_complete_fatal_x(self): conductor.dispatch_complete(message, mock_task) mock_notify.assert_called_once_with() + @pytest.mark.filterwarnings("ignore:Aries RFC 0160.*:DeprecationWarning") async def test_print_invite_connection(self): builder: ContextBuilder = StubContextBuilder(self.test_settings) builder.update_settings( diff --git a/acapy_agent/protocols/connections/v1_0/tests/test_manager.py b/acapy_agent/protocols/connections/v1_0/tests/test_manager.py index 2d1896b652..a96363dc00 100644 --- a/acapy_agent/protocols/connections/v1_0/tests/test_manager.py +++ b/acapy_agent/protocols/connections/v1_0/tests/test_manager.py @@ -1,5 +1,7 @@ from unittest import IsolatedAsyncioTestCase +import pytest + from .....cache.base import BaseCache from .....cache.in_memory import InMemoryCache from .....connections.models.conn_record import ConnRecord @@ -29,6 +31,7 @@ from ..models.connection_detail import ConnectionDetail +@pytest.mark.filterwarnings("ignore:Aries RFC 0160.*:DeprecationWarning") class TestConnectionManager(IsolatedAsyncioTestCase): def make_did_doc(self, did, verkey): doc = DIDDoc(did=did) From 6f967c6719306d8105794eba9bf0dedf394ac40d Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 14 Nov 2024 13:02:35 +0200 Subject: [PATCH 06/72] :art: Filter Pydantic UserWarning in test Signed-off-by: ff137 --- acapy_agent/connections/tests/test_base_manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acapy_agent/connections/tests/test_base_manager.py b/acapy_agent/connections/tests/test_base_manager.py index 57cd426c2d..84089929ca 100644 --- a/acapy_agent/connections/tests/test_base_manager.py +++ b/acapy_agent/connections/tests/test_base_manager.py @@ -3,6 +3,7 @@ from unittest import IsolatedAsyncioTestCase from unittest.mock import call +import pytest from pydid import DID, DIDDocument, DIDDocumentBuilder from pydid.doc.builder import ServiceBuilder from pydid.verification_method import ( @@ -27,9 +28,7 @@ from ...protocols.connections.v1_0.messages.connection_invitation import ( ConnectionInvitation, ) -from ...protocols.coordinate_mediation.v1_0.models.mediation_record import ( - MediationRecord, -) +from ...protocols.coordinate_mediation.v1_0.models.mediation_record import MediationRecord from ...protocols.coordinate_mediation.v1_0.route_manager import ( CoordinateMediationV1RouteManager, RouteManager, @@ -1065,6 +1064,7 @@ async def test_resolve_connection_targets_x_bad_key_material(self): await self.manager.resolve_connection_targets(did) assert "not supported" in str(cm.exception) + @pytest.mark.filterwarnings("ignore::UserWarning") async def test_resolve_connection_targets_x_unsupported_key(self): did = "did:sov:" + self.test_did doc_builder = DIDDocumentBuilder(did) From c65f6ce7e02eaa9f3aaa20c634901003fb2ec1ca Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 14 Nov 2024 13:04:38 +0200 Subject: [PATCH 07/72] :arrow_up: Upgrade aiohttp to latest release and update lock file Signed-off-by: ff137 --- poetry.lock | 762 +++++++++++++++++++++++-------------------------- pyproject.toml | 2 +- 2 files changed, 366 insertions(+), 398 deletions(-) diff --git a/poetry.lock b/poetry.lock index baafdb007a..cc45282759 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -13,102 +13,87 @@ files = [ [[package]] name = "aiohttp" -version = "3.10.10" +version = "3.11.0" description = "Async http client/server framework (asyncio)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f"}, - {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9"}, - {file = "aiohttp-3.10.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68"}, - {file = "aiohttp-3.10.10-cp310-cp310-win32.whl", hash = "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257"}, - {file = "aiohttp-3.10.10-cp310-cp310-win_amd64.whl", hash = "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a"}, - {file = "aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94"}, - {file = "aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205"}, - {file = "aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628"}, - {file = "aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b"}, - {file = "aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8"}, - {file = "aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b"}, - {file = "aiohttp-3.10.10-cp38-cp38-win32.whl", hash = "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c"}, - {file = "aiohttp-3.10.10-cp38-cp38-win_amd64.whl", hash = "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91"}, - {file = "aiohttp-3.10.10-cp39-cp39-win32.whl", hash = "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983"}, - {file = "aiohttp-3.10.10-cp39-cp39-win_amd64.whl", hash = "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23"}, - {file = "aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a"}, + {file = "aiohttp-3.11.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:024409c1b1d6076d0ed933dcebd7e4fc6f3320a227bfa0c1b6b93a8b5a146f04"}, + {file = "aiohttp-3.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:62502b8ffee8c6a4b5c6bf99d1de277d42bf51b2fb713975d9b63b560150b7ac"}, + {file = "aiohttp-3.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c54c635d1f52490cde7ef3a423645167a8284e452a35405d5c7dc1242a8e75c9"}, + {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:104ea21994b1403e4c1b398866f1187c1694fa291314ad7216ec1d8ec6b49f38"}, + {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04b24497b3baf15035730de5f207ade88a67d4483a5f16ced7ece348933a5b47"}, + {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08474e71772a516ba2e2167b4707af8361d2c452b3d8a5364c984f4867869499"}, + {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f40380c96dd407dfa84eb2d264e68aa47717b53bdbe210a59cc3c35a4635f195"}, + {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1668ef2f3a7ec9881f4b6a917e5f97c87a343fa6b0d5fc826b7b0297ddd0887"}, + {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f3bf5c132eb48002bcc3825702d241d35b4e9585009e65e9dcf9c4635d0b7424"}, + {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0315978b2a4569e03fb59100f6a7e7d23f718a4521491f5c13d946d37549f3d"}, + {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d5cae4cd271e20b7ab757e966cc919186b9f02535418ab36c471a5377ef4deaa"}, + {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:31b91ff3a1fcb206a1fa76e0de1f08c9ffb1dc0deb7296fa2618adfe380fc676"}, + {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ebf610c37df4f09c71c9bbf8309b4b459107e6fe889ac0d7e16f6e4ebd975f86"}, + {file = "aiohttp-3.11.0-cp310-cp310-win32.whl", hash = "sha256:b40c304ab01e89ad0aeeecf91bbaa6ae3b00e27b796c9e8d50b71a4a7e885cc8"}, + {file = "aiohttp-3.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd0834e4260eab78671b81d34f110fbaac449563e48d419cec0030d9a8e58693"}, + {file = "aiohttp-3.11.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:89a96a0696dc67d548f69cb518c581a7a33cc1f26ab42229dea1709217c9d926"}, + {file = "aiohttp-3.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f6b925c7775ab857bdc1e52e1f5abcae7d18751c09b751aeb641a5276d9b990e"}, + {file = "aiohttp-3.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7867d0808614f04e78e0a8d5a2c1f8ac6bc626a0c0e2f62be48be6b749e2f8b2"}, + {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:229ae13959a5f499d90ffbb4b9eac2255d8599315027d6f7c22fa9803a94d5b1"}, + {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62a2f5268b672087c45b33479ba1bb1d5a48c6d76c133cfce3a4f77410c200d1"}, + {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a896059b6937d1a22d8ee8377cdcd097bd26cd8c653b8f972051488b9baadee9"}, + {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:104deb7873681273c5daa13c41924693df394043a118dae90387d35bc5531788"}, + {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae36ae52b0c22fb69fb8b744eff82a20db512a29eafc6e3a4ab43b17215b219d"}, + {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7349205bb163318dcc102329d30be59a647a3d24c82c3d91ed35b7e7301ea7e"}, + {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9095580806d9ed07c0c29b23364a0b1fb78258ef9f4bddf7e55bac0e475d4edf"}, + {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4d218d3eca40196384ad3b481309c56fd60e664128885d1734da0a8aa530d433"}, + {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6533dd06df3d17d1756829b68b365b1583929b54082db8f65083a4184bf68322"}, + {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72cd984f7f14e8c01b3e38f18f39ea85dba84e52ea05e37116ba5e2a72eef396"}, + {file = "aiohttp-3.11.0-cp311-cp311-win32.whl", hash = "sha256:c1828e10c3a49e2b234b87600ecb68a92b8a8dcf8b99bca9447f16c4baaa1630"}, + {file = "aiohttp-3.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:900ff74d78eb580ae4aa5883242893b123a0c442a46570902500f08d6a7e6696"}, + {file = "aiohttp-3.11.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f8f0d79b923070f25674e4ea8f3d61c9d89d24d9598d50ff32c5b9b23c79a25b"}, + {file = "aiohttp-3.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:113bf06b029143e94a47c4f36e11a8b7e396e9d1f1fc8cea58e6b7e370cfed38"}, + {file = "aiohttp-3.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3e1ed8d152cccceffb1ee7a2ac227c16372e453fb11b3aeaa56783049b85d3f6"}, + {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2e82e515e268b965424ecabebd91834a41b36260b6ef5db015ee12ddb28ef3"}, + {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c1c49bc393d854d4421ebc174a0a41f9261f50d3694d8ca277146cbbcfd24ee7"}, + {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57e17c6d71f2dc857a8a1d09be1be7802e35d90fb4ba4b06cf1aab6414a57894"}, + {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12071dd2cc95ba81e0f2737bebcb98b2a8656015e87772e84e8fb9e635b5da6e"}, + {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97056d3422594e0787733ac4c45bef58722d452f4dc6615fee42f59fe51707dd"}, + {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2ec5efbc872b00ddd85e3904059d274f284cff314e13f48776050ca2c58f451d"}, + {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:dd505a1121ad5b666191840b7bd1d8cb917df2647deeca6f3474331b72452362"}, + {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:600b1d9f86a130131915e2f2127664311b33902c486b21a747d626f5144b4471"}, + {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8c47a0ba6c2b3d3e5715f8338d657badd21f778c6be16701922c65521c5ecfc9"}, + {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8b323b5d3aef7dd811424c269322eec58a977c0c8152e650159e47210d900504"}, + {file = "aiohttp-3.11.0-cp312-cp312-win32.whl", hash = "sha256:aabc4e92cb153636d6be54e84dad1b252ddb9aebe077942b6dcffe5e468d476a"}, + {file = "aiohttp-3.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:508cfcc99534b1282595357592d8367b44392b21f6eb5d4dc021f8d0d809e94d"}, + {file = "aiohttp-3.11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c98a596ac20e8980cc6f34c0c92a113e98eb08f3997c150064d26d2aeb043e5a"}, + {file = "aiohttp-3.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ad14cdc0fba4df31c0f6e06c21928c5b924725cbf60d0ccc5f6e7132636250e9"}, + {file = "aiohttp-3.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:170fb2324826bb9f08055a8291f42192ae5ee2f25b2966c8f0f4537c61d73a7b"}, + {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdad66685fcf2ad14ce522cf849d4a025f4fd206d6cfc3f403d9873e4c243b03"}, + {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8b95a63a8e8b5f0464bd8b1b0d59d2bec98a59b6aacc71e9be23df6989b3dfb"}, + {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7bcfcede95531589295f56e924702cef7f9685c9e4e5407592e04ded6a65bf3"}, + {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ecc2fb1a0a9d48cf773add34196cddf7e488e48e9596e090849751bf43098f4"}, + {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8fef105113d56e817cb9bcc609667ee461321413a7b972b03f5b4939f40f307c"}, + {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d33b4490026968bdc7f0729b9d87a3a6b1e09043557d2fc1c605c6072deb2f11"}, + {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6362f50a6f0e5482c4330d2151cb682779230683da0e155c15ec9fc58cb50b6a"}, + {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f698aa61879df64425191d41213dfd99efdc1627e6398e6d7aa5c312fac9702"}, + {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0e7a0762cc29cd3acd01a4d2b547b3af7956ad230ebb80b529a8e4f3e4740fe8"}, + {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b3e4fb7f5354d39490d8209aefdf5830b208d01c7293a2164e404312c3d8bc55"}, + {file = "aiohttp-3.11.0-cp313-cp313-win32.whl", hash = "sha256:6c5a6958f4366496004cf503d847093d464814543f157ef3b738bbf604232415"}, + {file = "aiohttp-3.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:3ed360d6672a9423aad39902a4e9fe305464d20ed7931dbdba30a4625782d875"}, + {file = "aiohttp-3.11.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d1ea006426edf7e1299c52a58b0443158012f7a56fed3515164b60bfcb1503a9"}, + {file = "aiohttp-3.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c5e6a1f8b0268ffa1c84d7c3558724956002ba8361176e76406233e704bbcffb"}, + {file = "aiohttp-3.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40dc9446cff326672fcbf93efdb8ef7e949824de1097624efe4f61ac7f0d2c43"}, + {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b4545e8d96870da9652930c5198366605ff8f982757030e2148cf341e5746b"}, + {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:37f8cf3c43f292d9bb3e6760476c2b55b9663a581fad682a586a410c43a7683e"}, + {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329f5059e0bf6983dceebac8e6ed20e75eaff6163b3414f4a4cb59e0d7037672"}, + {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ae6f182be72c3531915e90625cc65afce4df8a0fc4988bd52d8a5d5faaeb68"}, + {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d664e5f937c08adb7908ea9f391fbf2928a9b09cb412ac0aba602bde9e499e4"}, + {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:feca9fafa4385aea6759c171cd25ea82f7375312fca04178dae35331be45e538"}, + {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c415b9601ff50709d6050c8a9281733a9b042b9e589265ac40305b875cf9c463"}, + {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:91d3991fad8b65e5dbc13cd95669ea689fe0a96ff63e4e64ac24ed724e4f8103"}, + {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9231d610754724273a6ac05a1f177979490bfa6f84d49646df3928af2e88cfd5"}, + {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4e4e155968040e32c124a89852a1a5426d0e920a35f4331e1b3949037bfe93a3"}, + {file = "aiohttp-3.11.0-cp39-cp39-win32.whl", hash = "sha256:76d6ee8bb132f8ee0fcb0e205b4708ddb6fba524eb515ee168113063d825131b"}, + {file = "aiohttp-3.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:577c7429f8869fa30186fc2c9eee64d75a30b51b61f26aac9725866ae5985cfd"}, + {file = "aiohttp-3.11.0.tar.gz", hash = "sha256:f57a0de48dda792629e7952d34a0c7b81ea336bb9b721391c7c58145b237fe55"}, ] [package.dependencies] @@ -117,7 +102,8 @@ aiosignal = ">=1.1.2" attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.12.0,<2.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] @@ -573,73 +559,73 @@ yaml = ["PyYAML"] [[package]] name = "coverage" -version = "7.6.3" +version = "7.6.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976"}, - {file = "coverage-7.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c"}, - {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc"}, - {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e"}, - {file = "coverage-7.6.3-cp310-cp310-win32.whl", hash = "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007"}, - {file = "coverage-7.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd"}, - {file = "coverage-7.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c51ef82302386d686feea1c44dbeef744585da16fcf97deea2a8d6c1556f519b"}, - {file = "coverage-7.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ca37993206402c6c35dc717f90d4c8f53568a8b80f0bf1a1b2b334f4d488fba"}, - {file = "coverage-7.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c77326300b839c44c3e5a8fe26c15b7e87b2f32dfd2fc9fee1d13604347c9b38"}, - {file = "coverage-7.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e484e479860e00da1f005cd19d1c5d4a813324e5951319ac3f3eefb497cc549"}, - {file = "coverage-7.6.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c6c0f4d53ef603397fc894a895b960ecd7d44c727df42a8d500031716d4e8d2"}, - {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:37be7b5ea3ff5b7c4a9db16074dc94523b5f10dd1f3b362a827af66a55198175"}, - {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:43b32a06c47539fe275106b376658638b418c7cfdfff0e0259fbf877e845f14b"}, - {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee77c7bef0724165e795b6b7bf9c4c22a9b8468a6bdb9c6b4281293c6b22a90f"}, - {file = "coverage-7.6.3-cp311-cp311-win32.whl", hash = "sha256:43517e1f6b19f610a93d8227e47790722c8bf7422e46b365e0469fc3d3563d97"}, - {file = "coverage-7.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:04f2189716e85ec9192df307f7c255f90e78b6e9863a03223c3b998d24a3c6c6"}, - {file = "coverage-7.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27bd5f18d8f2879e45724b0ce74f61811639a846ff0e5c0395b7818fae87aec6"}, - {file = "coverage-7.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d546cfa78844b8b9c1c0533de1851569a13f87449897bbc95d698d1d3cb2a30f"}, - {file = "coverage-7.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9975442f2e7a5cfcf87299c26b5a45266ab0696348420049b9b94b2ad3d40234"}, - {file = "coverage-7.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:583049c63106c0555e3ae3931edab5669668bbef84c15861421b94e121878d3f"}, - {file = "coverage-7.6.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2341a78ae3a5ed454d524206a3fcb3cec408c2a0c7c2752cd78b606a2ff15af4"}, - {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a4fb91d5f72b7e06a14ff4ae5be625a81cd7e5f869d7a54578fc271d08d58ae3"}, - {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e279f3db904e3b55f520f11f983cc8dc8a4ce9b65f11692d4718ed021ec58b83"}, - {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa23ce39661a3e90eea5f99ec59b763b7d655c2cada10729ed920a38bfc2b167"}, - {file = "coverage-7.6.3-cp312-cp312-win32.whl", hash = "sha256:52ac29cc72ee7e25ace7807249638f94c9b6a862c56b1df015d2b2e388e51dbd"}, - {file = "coverage-7.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:40e8b1983080439d4802d80b951f4a93d991ef3261f69e81095a66f86cf3c3c6"}, - {file = "coverage-7.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9134032f5aa445ae591c2ba6991d10136a1f533b1d2fa8f8c21126468c5025c6"}, - {file = "coverage-7.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:99670790f21a96665a35849990b1df447993880bb6463a0a1d757897f30da929"}, - {file = "coverage-7.6.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc7d6b380ca76f5e817ac9eef0c3686e7834c8346bef30b041a4ad286449990"}, - {file = "coverage-7.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7b26757b22faf88fcf232f5f0e62f6e0fd9e22a8a5d0d5016888cdfe1f6c1c4"}, - {file = "coverage-7.6.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c59d6a4a4633fad297f943c03d0d2569867bd5372eb5684befdff8df8522e39"}, - {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f263b18692f8ed52c8de7f40a0751e79015983dbd77b16906e5b310a39d3ca21"}, - {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79644f68a6ff23b251cae1c82b01a0b51bc40c8468ca9585c6c4b1aeee570e0b"}, - {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71967c35828c9ff94e8c7d405469a1fb68257f686bca7c1ed85ed34e7c2529c4"}, - {file = "coverage-7.6.3-cp313-cp313-win32.whl", hash = "sha256:e266af4da2c1a4cbc6135a570c64577fd3e6eb204607eaff99d8e9b710003c6f"}, - {file = "coverage-7.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:ea52bd218d4ba260399a8ae4bb6b577d82adfc4518b93566ce1fddd4a49d1dce"}, - {file = "coverage-7.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8d4c6ea0f498c7c79111033a290d060c517853a7bcb2f46516f591dab628ddd3"}, - {file = "coverage-7.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:331b200ad03dbaa44151d74daeb7da2cf382db424ab923574f6ecca7d3b30de3"}, - {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54356a76b67cf8a3085818026bb556545ebb8353951923b88292556dfa9f812d"}, - {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ebec65f5068e7df2d49466aab9128510c4867e532e07cb6960075b27658dca38"}, - {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33a785ea8354c480515e781554d3be582a86297e41ccbea627a5c632647f2cd"}, - {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f7ddb920106bbbbcaf2a274d56f46956bf56ecbde210d88061824a95bdd94e92"}, - {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:70d24936ca6c15a3bbc91ee9c7fc661132c6f4c9d42a23b31b6686c05073bde5"}, - {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c30e42ea11badb147f0d2e387115b15e2bd8205a5ad70d6ad79cf37f6ac08c91"}, - {file = "coverage-7.6.3-cp313-cp313t-win32.whl", hash = "sha256:365defc257c687ce3e7d275f39738dcd230777424117a6c76043459db131dd43"}, - {file = "coverage-7.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:23bb63ae3f4c645d2d82fa22697364b0046fbafb6261b258a58587441c5f7bd0"}, - {file = "coverage-7.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:da29ceabe3025a1e5a5aeeb331c5b1af686daab4ff0fb4f83df18b1180ea83e2"}, - {file = "coverage-7.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df8c05a0f574d480947cba11b947dc41b1265d721c3777881da2fb8d3a1ddfba"}, - {file = "coverage-7.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec1e3b40b82236d100d259854840555469fad4db64f669ab817279eb95cd535c"}, - {file = "coverage-7.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4adeb878a374126f1e5cf03b87f66279f479e01af0e9a654cf6d1509af46c40"}, - {file = "coverage-7.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43d6a66e33b1455b98fc7312b124296dad97a2e191c80320587234a77b1b736e"}, - {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1990b1f4e2c402beb317840030bb9f1b6a363f86e14e21b4212e618acdfce7f6"}, - {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:12f9515d875859faedb4144fd38694a761cd2a61ef9603bf887b13956d0bbfbb"}, - {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99ded130555c021d99729fabd4ddb91a6f4cc0707df4b1daf912c7850c373b13"}, - {file = "coverage-7.6.3-cp39-cp39-win32.whl", hash = "sha256:c3a79f56dee9136084cf84a6c7c4341427ef36e05ae6415bf7d787c96ff5eaa3"}, - {file = "coverage-7.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:aac7501ae73d4a02f4b7ac8fcb9dc55342ca98ffb9ed9f2dfb8a25d53eda0e4d"}, - {file = "coverage-7.6.3-pp39.pp310-none-any.whl", hash = "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181"}, - {file = "coverage-7.6.3.tar.gz", hash = "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, + {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, + {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, + {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, + {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, + {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, + {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, + {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, + {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, + {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, + {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, + {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, + {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, + {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, + {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, ] [package.extras] @@ -647,38 +633,38 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, - {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, - {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, - {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, - {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, - {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, - {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] [package.dependencies] @@ -691,7 +677,7 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -969,20 +955,19 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-utils" -version = "5.0.0" +version = "5.1.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" optional = false python-versions = "<4,>=3.8" files = [ - {file = "eth_utils-5.0.0-py3-none-any.whl", hash = "sha256:99c44eca11db74dbb881a1d70b24cd80436fc62fe527d2f5c3e3cf7932aba7b2"}, - {file = "eth_utils-5.0.0.tar.gz", hash = "sha256:a5eb9555f43f4579eb83cb84f9dda9f3d6663bbd4a5a6b693f8d35045f305a1f"}, + {file = "eth_utils-5.1.0-py3-none-any.whl", hash = "sha256:a99f1f01b51206620904c5af47fac65abc143aebd0a76bdec860381c5a3230f8"}, + {file = "eth_utils-5.1.0.tar.gz", hash = "sha256:84c6314b9cf1fcd526107464bbf487e3f87097a2e753360d5ed319f7d42e3f20"}, ] [package.dependencies] cytoolz = {version = ">=0.10.1", markers = "implementation_name == \"cpython\""} eth-hash = ">=0.3.1" eth-typing = ">=5.0.0" -hexbytes = ">=1.0.0" toolz = {version = ">0.8.2", markers = "implementation_name == \"pypy\""} [package.extras] @@ -1070,115 +1055,114 @@ files = [ [[package]] name = "frozenlist" -version = "1.4.1" +version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" files = [ - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, - {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, - {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, - {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, - {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, - {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, - {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, -] - -[[package]] -name = "hexbytes" -version = "1.2.1" -description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "hexbytes-1.2.1-py3-none-any.whl", hash = "sha256:e64890b203a31f4a23ef11470ecfcca565beaee9198df623047df322b757471a"}, - {file = "hexbytes-1.2.1.tar.gz", hash = "sha256:515f00dddf31053db4d0d7636dd16061c1d896c3109b8e751005db4ca46bcca7"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, + {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, + {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, + {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, + {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, + {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, + {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, ] -[package.extras] -dev = ["build (>=0.9.0)", "bump-my-version (>=0.19.0)", "eth-utils (>=2.0.0)", "hypothesis (>=3.44.24,<=6.31.6)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-utils (>=2.0.0)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - [[package]] name = "identify" -version = "2.6.1" +version = "2.6.2" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, - {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, + {file = "identify-2.6.2-py2.py3-none-any.whl", hash = "sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3"}, + {file = "identify-2.6.2.tar.gz", hash = "sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd"}, ] [package.extras] @@ -2340,13 +2324,13 @@ testing = ["filelock"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -2889,13 +2873,13 @@ files = [ [[package]] name = "virtualenv" -version = "20.26.6" +version = "20.27.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, - {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, + {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, + {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, ] [package.dependencies] @@ -2942,109 +2926,93 @@ tests = ["Django (>=2.2.0)", "Flask (>=0.12.5)", "aiohttp (>=3.0.8)", "bottle (> [[package]] name = "yarl" -version = "1.15.2" +version = "1.17.1" description = "Yet another URL library" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "yarl-1.15.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e4ee8b8639070ff246ad3649294336b06db37a94bdea0d09ea491603e0be73b8"}, - {file = "yarl-1.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a7cf963a357c5f00cb55b1955df8bbe68d2f2f65de065160a1c26b85a1e44172"}, - {file = "yarl-1.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:43ebdcc120e2ca679dba01a779333a8ea76b50547b55e812b8b92818d604662c"}, - {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3433da95b51a75692dcf6cc8117a31410447c75a9a8187888f02ad45c0a86c50"}, - {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38d0124fa992dbacd0c48b1b755d3ee0a9f924f427f95b0ef376556a24debf01"}, - {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ded1b1803151dd0f20a8945508786d57c2f97a50289b16f2629f85433e546d47"}, - {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace4cad790f3bf872c082366c9edd7f8f8f77afe3992b134cfc810332206884f"}, - {file = "yarl-1.15.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c77494a2f2282d9bbbbcab7c227a4d1b4bb829875c96251f66fb5f3bae4fb053"}, - {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b7f227ca6db5a9fda0a2b935a2ea34a7267589ffc63c8045f0e4edb8d8dcf956"}, - {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:31561a5b4d8dbef1559b3600b045607cf804bae040f64b5f5bca77da38084a8a"}, - {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3e52474256a7db9dcf3c5f4ca0b300fdea6c21cca0148c8891d03a025649d935"}, - {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1af74a9529a1137c67c887ed9cde62cff53aa4d84a3adbec329f9ec47a3936"}, - {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:15c87339490100c63472a76d87fe7097a0835c705eb5ae79fd96e343473629ed"}, - {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:74abb8709ea54cc483c4fb57fb17bb66f8e0f04438cff6ded322074dbd17c7ec"}, - {file = "yarl-1.15.2-cp310-cp310-win32.whl", hash = "sha256:ffd591e22b22f9cb48e472529db6a47203c41c2c5911ff0a52e85723196c0d75"}, - {file = "yarl-1.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:1695497bb2a02a6de60064c9f077a4ae9c25c73624e0d43e3aa9d16d983073c2"}, - {file = "yarl-1.15.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9fcda20b2de7042cc35cf911702fa3d8311bd40055a14446c1e62403684afdc5"}, - {file = "yarl-1.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0545de8c688fbbf3088f9e8b801157923be4bf8e7b03e97c2ecd4dfa39e48e0e"}, - {file = "yarl-1.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbda058a9a68bec347962595f50546a8a4a34fd7b0654a7b9697917dc2bf810d"}, - {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ac2bc069f4a458634c26b101c2341b18da85cb96afe0015990507efec2e417"}, - {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd126498171f752dd85737ab1544329a4520c53eed3997f9b08aefbafb1cc53b"}, - {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3db817b4e95eb05c362e3b45dafe7144b18603e1211f4a5b36eb9522ecc62bcf"}, - {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:076b1ed2ac819933895b1a000904f62d615fe4533a5cf3e052ff9a1da560575c"}, - {file = "yarl-1.15.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8cfd847e6b9ecf9f2f2531c8427035f291ec286c0a4944b0a9fce58c6446046"}, - {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:32b66be100ac5739065496c74c4b7f3015cef792c3174982809274d7e51b3e04"}, - {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34a2d76a1984cac04ff8b1bfc939ec9dc0914821264d4a9c8fd0ed6aa8d4cfd2"}, - {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0afad2cd484908f472c8fe2e8ef499facee54a0a6978be0e0cff67b1254fd747"}, - {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c68e820879ff39992c7f148113b46efcd6ec765a4865581f2902b3c43a5f4bbb"}, - {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:98f68df80ec6ca3015186b2677c208c096d646ef37bbf8b49764ab4a38183931"}, - {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56ec1eacd0a5d35b8a29f468659c47f4fe61b2cab948ca756c39b7617f0aa5"}, - {file = "yarl-1.15.2-cp311-cp311-win32.whl", hash = "sha256:eedc3f247ee7b3808ea07205f3e7d7879bc19ad3e6222195cd5fbf9988853e4d"}, - {file = "yarl-1.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:0ccaa1bc98751fbfcf53dc8dfdb90d96e98838010fc254180dd6707a6e8bb179"}, - {file = "yarl-1.15.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:82d5161e8cb8f36ec778fd7ac4d740415d84030f5b9ef8fe4da54784a1f46c94"}, - {file = "yarl-1.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa2bea05ff0a8fb4d8124498e00e02398f06d23cdadd0fe027d84a3f7afde31e"}, - {file = "yarl-1.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99e12d2bf587b44deb74e0d6170fec37adb489964dbca656ec41a7cd8f2ff178"}, - {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:243fbbbf003754fe41b5bdf10ce1e7f80bcc70732b5b54222c124d6b4c2ab31c"}, - {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:856b7f1a7b98a8c31823285786bd566cf06226ac4f38b3ef462f593c608a9bd6"}, - {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:553dad9af802a9ad1a6525e7528152a015b85fb8dbf764ebfc755c695f488367"}, - {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30c3ff305f6e06650a761c4393666f77384f1cc6c5c0251965d6bfa5fbc88f7f"}, - {file = "yarl-1.15.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:353665775be69bbfc6d54c8d134bfc533e332149faeddd631b0bc79df0897f46"}, - {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f4fe99ce44128c71233d0d72152db31ca119711dfc5f2c82385ad611d8d7f897"}, - {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9c1e3ff4b89cdd2e1a24c214f141e848b9e0451f08d7d4963cb4108d4d798f1f"}, - {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:711bdfae4e699a6d4f371137cbe9e740dc958530cb920eb6f43ff9551e17cfbc"}, - {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4388c72174868884f76affcdd3656544c426407e0043c89b684d22fb265e04a5"}, - {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f0e1844ad47c7bd5d6fa784f1d4accc5f4168b48999303a868fe0f8597bde715"}, - {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a5cafb02cf097a82d74403f7e0b6b9df3ffbfe8edf9415ea816314711764a27b"}, - {file = "yarl-1.15.2-cp312-cp312-win32.whl", hash = "sha256:156ececdf636143f508770bf8a3a0498de64da5abd890c7dbb42ca9e3b6c05b8"}, - {file = "yarl-1.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:435aca062444a7f0c884861d2e3ea79883bd1cd19d0a381928b69ae1b85bc51d"}, - {file = "yarl-1.15.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:416f2e3beaeae81e2f7a45dc711258be5bdc79c940a9a270b266c0bec038fb84"}, - {file = "yarl-1.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:173563f3696124372831007e3d4b9821746964a95968628f7075d9231ac6bb33"}, - {file = "yarl-1.15.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ce2e0f6123a60bd1a7f5ae3b2c49b240c12c132847f17aa990b841a417598a2"}, - {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaea112aed589131f73d50d570a6864728bd7c0c66ef6c9154ed7b59f24da611"}, - {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4ca3b9f370f218cc2a0309542cab8d0acdfd66667e7c37d04d617012485f904"}, - {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23ec1d3c31882b2a8a69c801ef58ebf7bae2553211ebbddf04235be275a38548"}, - {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75119badf45f7183e10e348edff5a76a94dc19ba9287d94001ff05e81475967b"}, - {file = "yarl-1.15.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e6fdc976ec966b99e4daa3812fac0274cc28cd2b24b0d92462e2e5ef90d368"}, - {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8657d3f37f781d987037f9cc20bbc8b40425fa14380c87da0cb8dfce7c92d0fb"}, - {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:93bed8a8084544c6efe8856c362af08a23e959340c87a95687fdbe9c9f280c8b"}, - {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:69d5856d526802cbda768d3e6246cd0d77450fa2a4bc2ea0ea14f0d972c2894b"}, - {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ccad2800dfdff34392448c4bf834be124f10a5bc102f254521d931c1c53c455a"}, - {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a880372e2e5dbb9258a4e8ff43f13888039abb9dd6d515f28611c54361bc5644"}, - {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c998d0558805860503bc3a595994895ca0f7835e00668dadc673bbf7f5fbfcbe"}, - {file = "yarl-1.15.2-cp313-cp313-win32.whl", hash = "sha256:533a28754e7f7439f217550a497bb026c54072dbe16402b183fdbca2431935a9"}, - {file = "yarl-1.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:5838f2b79dc8f96fdc44077c9e4e2e33d7089b10788464609df788eb97d03aad"}, - {file = "yarl-1.15.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fbbb63bed5fcd70cd3dd23a087cd78e4675fb5a2963b8af53f945cbbca79ae16"}, - {file = "yarl-1.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2e93b88ecc8f74074012e18d679fb2e9c746f2a56f79cd5e2b1afcf2a8a786b"}, - {file = "yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af8ff8d7dc07ce873f643de6dfbcd45dc3db2c87462e5c387267197f59e6d776"}, - {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66f629632220a4e7858b58e4857927dd01a850a4cef2fb4044c8662787165cf7"}, - {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:833547179c31f9bec39b49601d282d6f0ea1633620701288934c5f66d88c3e50"}, - {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2aa738e0282be54eede1e3f36b81f1e46aee7ec7602aa563e81e0e8d7b67963f"}, - {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a13a07532e8e1c4a5a3afff0ca4553da23409fad65def1b71186fb867eeae8d"}, - {file = "yarl-1.15.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c45817e3e6972109d1a2c65091504a537e257bc3c885b4e78a95baa96df6a3f8"}, - {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:670eb11325ed3a6209339974b276811867defe52f4188fe18dc49855774fa9cf"}, - {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:d417a4f6943112fae3924bae2af7112562285848d9bcee737fc4ff7cbd450e6c"}, - {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bc8936d06cd53fddd4892677d65e98af514c8d78c79864f418bbf78a4a2edde4"}, - {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:954dde77c404084c2544e572f342aef384240b3e434e06cecc71597e95fd1ce7"}, - {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5bc0df728e4def5e15a754521e8882ba5a5121bd6b5a3a0ff7efda5d6558ab3d"}, - {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b71862a652f50babab4a43a487f157d26b464b1dedbcc0afda02fd64f3809d04"}, - {file = "yarl-1.15.2-cp38-cp38-win32.whl", hash = "sha256:63eab904f8630aed5a68f2d0aeab565dcfc595dc1bf0b91b71d9ddd43dea3aea"}, - {file = "yarl-1.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:2cf441c4b6e538ba0d2591574f95d3fdd33f1efafa864faa077d9636ecc0c4e9"}, - {file = "yarl-1.15.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a32d58f4b521bb98b2c0aa9da407f8bd57ca81f34362bcb090e4a79e9924fefc"}, - {file = "yarl-1.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:766dcc00b943c089349d4060b935c76281f6be225e39994c2ccec3a2a36ad627"}, - {file = "yarl-1.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bed1b5dbf90bad3bfc19439258c97873eab453c71d8b6869c136346acfe497e7"}, - {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed20a4bdc635f36cb19e630bfc644181dd075839b6fc84cac51c0f381ac472e2"}, - {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d538df442c0d9665664ab6dd5fccd0110fa3b364914f9c85b3ef9b7b2e157980"}, - {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c6cf1d92edf936ceedc7afa61b07e9d78a27b15244aa46bbcd534c7458ee1b"}, - {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce44217ad99ffad8027d2fde0269ae368c86db66ea0571c62a000798d69401fb"}, - {file = "yarl-1.15.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47a6000a7e833ebfe5886b56a31cb2ff12120b1efd4578a6fcc38df16cc77bd"}, - {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e52f77a0cd246086afde8815039f3e16f8d2be51786c0a39b57104c563c5cbb0"}, - {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:f9ca0e6ce7774dc7830dc0cc4bb6b3eec769db667f230e7c770a628c1aa5681b"}, - {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:136f9db0f53c0206db38b8cd0c985c78ded5fd596c9a86ce5c0b92afb91c3a19"}, - {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:173866d9f7409c0fb514cf6e78952e65816600cb888c68b37b41147349fe0057"}, - {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:6e840553c9c494a35e449a987ca2c4f8372668ee954a03a9a9685075228e5036"}, - {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:458c0c65802d816a6b955cf3603186de79e8fdb46d4f19abaec4ef0a906f50a7"}, - {file = "yarl-1.15.2-cp39-cp39-win32.whl", hash = "sha256:5b48388ded01f6f2429a8c55012bdbd1c2a0c3735b3e73e221649e524c34a58d"}, - {file = "yarl-1.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:81dadafb3aa124f86dc267a2168f71bbd2bfb163663661ab0038f6e4b8edb810"}, - {file = "yarl-1.15.2-py3-none-any.whl", hash = "sha256:0d3105efab7c5c091609abacad33afff33bdff0035bece164c98bcf5a85ef90a"}, - {file = "yarl-1.15.2.tar.gz", hash = "sha256:a39c36f4218a5bb668b4f06874d676d35a035ee668e6e7e3538835c703634b84"}, + {file = "yarl-1.17.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1794853124e2f663f0ea54efb0340b457f08d40a1cef78edfa086576179c91"}, + {file = "yarl-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fbea1751729afe607d84acfd01efd95e3b31db148a181a441984ce9b3d3469da"}, + {file = "yarl-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ee427208c675f1b6e344a1f89376a9613fc30b52646a04ac0c1f6587c7e46ec"}, + {file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b74ff4767d3ef47ffe0cd1d89379dc4d828d4873e5528976ced3b44fe5b0a21"}, + {file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62a91aefff3d11bf60e5956d340eb507a983a7ec802b19072bb989ce120cd948"}, + {file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:846dd2e1243407133d3195d2d7e4ceefcaa5f5bf7278f0a9bda00967e6326b04"}, + {file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e844be8d536afa129366d9af76ed7cb8dfefec99f5f1c9e4f8ae542279a6dc3"}, + {file = "yarl-1.17.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc7c92c1baa629cb03ecb0c3d12564f172218fb1739f54bf5f3881844daadc6d"}, + {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae3476e934b9d714aa8000d2e4c01eb2590eee10b9d8cd03e7983ad65dfbfcba"}, + {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c7e177c619342e407415d4f35dec63d2d134d951e24b5166afcdfd1362828e17"}, + {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64cc6e97f14cf8a275d79c5002281f3040c12e2e4220623b5759ea7f9868d6a5"}, + {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:84c063af19ef5130084db70ada40ce63a84f6c1ef4d3dbc34e5e8c4febb20822"}, + {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:482c122b72e3c5ec98f11457aeb436ae4aecca75de19b3d1de7cf88bc40db82f"}, + {file = "yarl-1.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:380e6c38ef692b8fd5a0f6d1fa8774d81ebc08cfbd624b1bca62a4d4af2f9931"}, + {file = "yarl-1.17.1-cp310-cp310-win32.whl", hash = "sha256:16bca6678a83657dd48df84b51bd56a6c6bd401853aef6d09dc2506a78484c7b"}, + {file = "yarl-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:561c87fea99545ef7d692403c110b2f99dced6dff93056d6e04384ad3bc46243"}, + {file = "yarl-1.17.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cbad927ea8ed814622305d842c93412cb47bd39a496ed0f96bfd42b922b4a217"}, + {file = "yarl-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fca4b4307ebe9c3ec77a084da3a9d1999d164693d16492ca2b64594340999988"}, + {file = "yarl-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff5c6771c7e3511a06555afa317879b7db8d640137ba55d6ab0d0c50425cab75"}, + {file = "yarl-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b29beab10211a746f9846baa39275e80034e065460d99eb51e45c9a9495bcca"}, + {file = "yarl-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a52a1ffdd824fb1835272e125385c32fd8b17fbdefeedcb4d543cc23b332d74"}, + {file = "yarl-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58c8e9620eb82a189c6c40cb6b59b4e35b2ee68b1f2afa6597732a2b467d7e8f"}, + {file = "yarl-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d216e5d9b8749563c7f2c6f7a0831057ec844c68b4c11cb10fc62d4fd373c26d"}, + {file = "yarl-1.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:881764d610e3269964fc4bb3c19bb6fce55422828e152b885609ec176b41cf11"}, + {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8c79e9d7e3d8a32d4824250a9c6401194fb4c2ad9a0cec8f6a96e09a582c2cc0"}, + {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:299f11b44d8d3a588234adbe01112126010bd96d9139c3ba7b3badd9829261c3"}, + {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cc7d768260f4ba4ea01741c1b5fe3d3a6c70eb91c87f4c8761bbcce5181beafe"}, + {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:de599af166970d6a61accde358ec9ded821234cbbc8c6413acfec06056b8e860"}, + {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2b24ec55fad43e476905eceaf14f41f6478780b870eda5d08b4d6de9a60b65b4"}, + {file = "yarl-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9fb815155aac6bfa8d86184079652c9715c812d506b22cfa369196ef4e99d1b4"}, + {file = "yarl-1.17.1-cp311-cp311-win32.whl", hash = "sha256:7615058aabad54416ddac99ade09a5510cf77039a3b903e94e8922f25ed203d7"}, + {file = "yarl-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:14bc88baa44e1f84164a392827b5defb4fa8e56b93fecac3d15315e7c8e5d8b3"}, + {file = "yarl-1.17.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:327828786da2006085a4d1feb2594de6f6d26f8af48b81eb1ae950c788d97f61"}, + {file = "yarl-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cc353841428d56b683a123a813e6a686e07026d6b1c5757970a877195f880c2d"}, + {file = "yarl-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c73df5b6e8fabe2ddb74876fb82d9dd44cbace0ca12e8861ce9155ad3c886139"}, + {file = "yarl-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bdff5e0995522706c53078f531fb586f56de9c4c81c243865dd5c66c132c3b5"}, + {file = "yarl-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06157fb3c58f2736a5e47c8fcbe1afc8b5de6fb28b14d25574af9e62150fcaac"}, + {file = "yarl-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1654ec814b18be1af2c857aa9000de7a601400bd4c9ca24629b18486c2e35463"}, + {file = "yarl-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6595c852ca544aaeeb32d357e62c9c780eac69dcd34e40cae7b55bc4fb1147"}, + {file = "yarl-1.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:459e81c2fb920b5f5df744262d1498ec2c8081acdcfe18181da44c50f51312f7"}, + {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e48cdb8226644e2fbd0bdb0a0f87906a3db07087f4de77a1b1b1ccfd9e93685"}, + {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d9b6b28a57feb51605d6ae5e61a9044a31742db557a3b851a74c13bc61de5172"}, + {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e594b22688d5747b06e957f1ef822060cb5cb35b493066e33ceac0cf882188b7"}, + {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5f236cb5999ccd23a0ab1bd219cfe0ee3e1c1b65aaf6dd3320e972f7ec3a39da"}, + {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a2a64e62c7a0edd07c1c917b0586655f3362d2c2d37d474db1a509efb96fea1c"}, + {file = "yarl-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d0eea830b591dbc68e030c86a9569826145df485b2b4554874b07fea1275a199"}, + {file = "yarl-1.17.1-cp312-cp312-win32.whl", hash = "sha256:46ddf6e0b975cd680eb83318aa1d321cb2bf8d288d50f1754526230fcf59ba96"}, + {file = "yarl-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:117ed8b3732528a1e41af3aa6d4e08483c2f0f2e3d3d7dca7cf538b3516d93df"}, + {file = "yarl-1.17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5d1d42556b063d579cae59e37a38c61f4402b47d70c29f0ef15cee1acaa64488"}, + {file = "yarl-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0167540094838ee9093ef6cc2c69d0074bbf84a432b4995835e8e5a0d984374"}, + {file = "yarl-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2f0a6423295a0d282d00e8701fe763eeefba8037e984ad5de44aa349002562ac"}, + {file = "yarl-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b078134f48552c4d9527db2f7da0b5359abd49393cdf9794017baec7506170"}, + {file = "yarl-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d401f07261dc5aa36c2e4efc308548f6ae943bfff20fcadb0a07517a26b196d8"}, + {file = "yarl-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5f1ac7359e17efe0b6e5fec21de34145caef22b260e978336f325d5c84e6938"}, + {file = "yarl-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f63d176a81555984e91f2c84c2a574a61cab7111cc907e176f0f01538e9ff6e"}, + {file = "yarl-1.17.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e275792097c9f7e80741c36de3b61917aebecc08a67ae62899b074566ff8556"}, + {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:81713b70bea5c1386dc2f32a8f0dab4148a2928c7495c808c541ee0aae614d67"}, + {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:aa46dce75078fceaf7cecac5817422febb4355fbdda440db55206e3bd288cfb8"}, + {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1ce36ded585f45b1e9bb36d0ae94765c6608b43bd2e7f5f88079f7a85c61a4d3"}, + {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2d374d70fdc36f5863b84e54775452f68639bc862918602d028f89310a034ab0"}, + {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2d9f0606baaec5dd54cb99667fcf85183a7477f3766fbddbe3f385e7fc253299"}, + {file = "yarl-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b0341e6d9a0c0e3cdc65857ef518bb05b410dbd70d749a0d33ac0f39e81a4258"}, + {file = "yarl-1.17.1-cp313-cp313-win32.whl", hash = "sha256:2e7ba4c9377e48fb7b20dedbd473cbcbc13e72e1826917c185157a137dac9df2"}, + {file = "yarl-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:949681f68e0e3c25377462be4b658500e85ca24323d9619fdc41f68d46a1ffda"}, + {file = "yarl-1.17.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8994b29c462de9a8fce2d591028b986dbbe1b32f3ad600b2d3e1c482c93abad6"}, + {file = "yarl-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f9cbfbc5faca235fbdf531b93aa0f9f005ec7d267d9d738761a4d42b744ea159"}, + {file = "yarl-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b40d1bf6e6f74f7c0a567a9e5e778bbd4699d1d3d2c0fe46f4b717eef9e96b95"}, + {file = "yarl-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5efe0661b9fcd6246f27957f6ae1c0eb29bc60552820f01e970b4996e016004"}, + {file = "yarl-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5c4804e4039f487e942c13381e6c27b4b4e66066d94ef1fae3f6ba8b953f383"}, + {file = "yarl-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5d6a6c9602fd4598fa07e0389e19fe199ae96449008d8304bf5d47cb745462e"}, + {file = "yarl-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4c9156c4d1eb490fe374fb294deeb7bc7eaccda50e23775b2354b6a6739934"}, + {file = "yarl-1.17.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6324274b4e0e2fa1b3eccb25997b1c9ed134ff61d296448ab8269f5ac068c4c"}, + {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d8a8b74d843c2638f3864a17d97a4acda58e40d3e44b6303b8cc3d3c44ae2d29"}, + {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7fac95714b09da9278a0b52e492466f773cfe37651cf467a83a1b659be24bf71"}, + {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c180ac742a083e109c1a18151f4dd8675f32679985a1c750d2ff806796165b55"}, + {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:578d00c9b7fccfa1745a44f4eddfdc99d723d157dad26764538fbdda37209857"}, + {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1a3b91c44efa29e6c8ef8a9a2b583347998e2ba52c5d8280dbd5919c02dfc3b5"}, + {file = "yarl-1.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a7ac5b4984c468ce4f4a553df281450df0a34aefae02e58d77a0847be8d1e11f"}, + {file = "yarl-1.17.1-cp39-cp39-win32.whl", hash = "sha256:7294e38f9aa2e9f05f765b28ffdc5d81378508ce6dadbe93f6d464a8c9594473"}, + {file = "yarl-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:eb6dce402734575e1a8cc0bb1509afca508a400a57ce13d306ea2c663bad1138"}, + {file = "yarl-1.17.1-py3-none-any.whl", hash = "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06"}, + {file = "yarl-1.17.1.tar.gz", hash = "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47"}, ] [package.dependencies] @@ -3060,4 +3028,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "20aeb9b87b2d4e7153898e75523ad9da8cc9ef611b17e96ac9ffbd2d463f974d" +content-hash = "d81899e5cdc890d282640cb4e12b4d6f1c5c294f1d59ba7045b96c0b35c0ef61" diff --git a/pyproject.toml b/pyproject.toml index 3d47940686..bcfe87c352 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ repository = "https://github.com/openwallet-foundation/acapy" [tool.poetry.dependencies] python = "^3.12" -aiohttp = "~3.10.5" +aiohttp = "~3.11.0" aiohttp-apispec-acapy = "~3.0.2" aiohttp-cors = "~0.7.0" apispec = "^6.6.0" From d84a384ec0f651b037e1ca466d244c00e462cf53 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 14 Nov 2024 13:23:00 +0200 Subject: [PATCH 08/72] :art: Remove unnecessary asyncio pytest markers Resolves unclosed event loop warnings. Signed-off-by: ff137 --- acapy_agent/anoncreds/tests/test_revocation.py | 1 - acapy_agent/multitenant/admin/tests/test_routes.py | 3 --- .../v1_0/handlers/tests/test_response_handler.py | 7 ------- .../v2_0/formats/vc_di/tests/test_handler.py | 2 -- .../present_proof/dif/tests/test_pres_exch_handler.py | 9 --------- 5 files changed, 22 deletions(-) diff --git a/acapy_agent/anoncreds/tests/test_revocation.py b/acapy_agent/anoncreds/tests/test_revocation.py index 2f8ce80de4..5de4ef368e 100644 --- a/acapy_agent/anoncreds/tests/test_revocation.py +++ b/acapy_agent/anoncreds/tests/test_revocation.py @@ -1414,7 +1414,6 @@ async def test_create_credential_w3c(self, mock_supports_revocation): assert isinstance(result, tuple) assert mock_supports_revocation.call_count == 1 - @pytest.mark.asyncio @mock.patch.object(AskarAnoncredsProfileSession, "handle") async def test_create_credential_w3c_keyerror(self, mock_handle): mock_handle.fetch = mock.CoroutineMock(side_effect=[MockEntry(), MockEntry()]) diff --git a/acapy_agent/multitenant/admin/tests/test_routes.py b/acapy_agent/multitenant/admin/tests/test_routes.py index 2431e6f6d5..823d8704aa 100644 --- a/acapy_agent/multitenant/admin/tests/test_routes.py +++ b/acapy_agent/multitenant/admin/tests/test_routes.py @@ -1,6 +1,5 @@ from unittest import IsolatedAsyncioTestCase -import pytest from marshmallow.exceptions import ValidationError from ....admin.request_context import AdminRequestContext @@ -143,7 +142,6 @@ async def test_wallets_list_query(self): } ) - @pytest.mark.asyncio(loop_scope="function") async def test_wallet_create_tenant_settings(self): body = { "wallet_name": "test", @@ -796,7 +794,6 @@ async def test_wallet_create_token_x(self): ) await test_module.wallet_create_token(self.request) - @pytest.mark.asyncio(loop_scope="function") async def test_wallet_remove_managed(self): self.request.has_body = False self.request.match_info = {"wallet_id": "dummy"} diff --git a/acapy_agent/protocols/didexchange/v1_0/handlers/tests/test_response_handler.py b/acapy_agent/protocols/didexchange/v1_0/handlers/tests/test_response_handler.py index 87abd74791..d835ca2fc1 100644 --- a/acapy_agent/protocols/didexchange/v1_0/handlers/tests/test_response_handler.py +++ b/acapy_agent/protocols/didexchange/v1_0/handlers/tests/test_response_handler.py @@ -1,7 +1,5 @@ from unittest import IsolatedAsyncioTestCase -import pytest - from ......connections.models import connection_target from ......connections.models.diddoc import DIDDoc, PublicKey, PublicKeyType, Service from ......messaging.decorators.attach_decorator import AttachDecorator @@ -75,7 +73,6 @@ async def asyncSetUp(self): did_doc_attach=self.did_doc_attach, ) - @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") async def test_called(self, mock_didx_mgr): mock_didx_mgr.return_value.accept_response = mock.CoroutineMock() @@ -89,7 +86,6 @@ async def test_called(self, mock_didx_mgr): ) assert not responder.messages - @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") async def test_called_auto_ping(self, mock_didx_mgr): self.ctx.update_settings({"auto_ping_connection": True}) @@ -107,7 +103,6 @@ async def test_called_auto_ping(self, mock_didx_mgr): result, _ = messages[0] assert isinstance(result, Ping) - @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") @mock.patch.object(connection_target, "ConnectionTarget") async def test_problem_report(self, mock_conn_target, mock_didx_mgr): @@ -144,7 +139,6 @@ async def test_problem_report(self, mock_conn_target, mock_didx_mgr): ) assert target == {"target_list": [mock_conn_target]} - @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") @mock.patch.object(connection_target, "ConnectionTarget") async def test_problem_report_did_doc( @@ -191,7 +185,6 @@ async def test_problem_report_did_doc( ) assert target == {"target_list": [mock_conn_target]} - @pytest.mark.asyncio(loop_scope="function") @mock.patch.object(test_module, "DIDXManager") @mock.patch.object(connection_target, "ConnectionTarget") async def test_problem_report_did_doc_no_conn_target( diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py index 65d050e75e..ae8f23fa69 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py @@ -727,7 +727,6 @@ async def test_issue_credential_non_revocable(self): # assert data is encoded as base64 assert attachment.data.base64 - @pytest.mark.asyncio async def test_match_sent_cred_def_id_error(self): tag_query = {"tag": "test_tag"} @@ -737,7 +736,6 @@ async def test_match_sent_cred_def_id_error(self): context.exception ) - @pytest.mark.asyncio async def test_store_credential(self): attr_values = { "legalName": "value", diff --git a/acapy_agent/protocols/present_proof/dif/tests/test_pres_exch_handler.py b/acapy_agent/protocols/present_proof/dif/tests/test_pres_exch_handler.py index 35171b0d16..654c62f432 100644 --- a/acapy_agent/protocols/present_proof/dif/tests/test_pres_exch_handler.py +++ b/acapy_agent/protocols/present_proof/dif/tests/test_pres_exch_handler.py @@ -1549,7 +1549,6 @@ async def test_filter_string(self): ) assert len(tmp_vp.get("verifiableCredential")) == 1 - @pytest.mark.asyncio @pytest.mark.ursa_bbs_signatures async def test_filter_schema(self): cred_list, _ = await self.setup_tuple(self.profile) @@ -2384,7 +2383,6 @@ async def test_no_filter(self): ) assert len(tmp_vp.get("verifiableCredential")) == 6 - @pytest.mark.asyncio @pytest.mark.ursa_bbs_signatures async def test_filter_with_only_string_type(self): cred_list, _ = await self.setup_tuple(self.profile) @@ -2436,7 +2434,6 @@ async def test_filter_with_only_string_type(self): ) assert len(tmp_vp.get("verifiableCredential")) == 6 - @pytest.mark.asyncio @pytest.mark.ursa_bbs_signatures async def test_filter_with_only_num_type(self): await self.setup_tuple(self.profile) @@ -2850,7 +2847,6 @@ async def test_filter_by_field_path_match_on_proof(self): with pytest.raises(DIFPresExchError): await dif_pres_exch_handler.filter_by_field(field, cred) - @pytest.mark.asyncio async def test_filter_creds_record_id(self): dif_pres_exch_handler = DIFPresExchHandler(self.profile) cred_list = [ @@ -3214,7 +3210,6 @@ async def test_apply_constraint_received_cred_path_update(self): constraint=constraint, cred_dict=cred_dict ) - @pytest.mark.asyncio @pytest.mark.ursa_bbs_signatures async def test_apply_constraint_received_cred_invalid(self): dif_pres_exch_handler = DIFPresExchHandler( @@ -3270,7 +3265,6 @@ async def test_apply_constraint_received_cred_invalid(self): constraint=constraint, cred_dict=cred_dict ) - @pytest.mark.asyncio @pytest.mark.ursa_bbs_signatures async def test_apply_constraint_received_cred_valid(self): dif_pres_exch_handler = DIFPresExchHandler( @@ -3464,7 +3458,6 @@ async def test_apply_constraint_received_cred_no_sel_disc(self): constraint=constraint, cred_dict=cred_dict ) - @pytest.mark.asyncio async def test_get_updated_path(self): dif_pres_exch_handler = DIFPresExchHandler( self.profile, proof_type=BbsBlsSignature2020.signature_type @@ -3532,7 +3525,6 @@ def test_get_dict_keys_from_path(self): cred_dict, "credentialSubject.Patient.address" ) == ["@id"] - @pytest.mark.asyncio async def test_filter_by_field_keyerror(self): dif_pres_exch_handler = DIFPresExchHandler( self.profile, proof_type=BbsBlsSignature2020.signature_type @@ -3555,7 +3547,6 @@ async def test_filter_by_field_keyerror(self): ) assert not await dif_pres_exch_handler.filter_by_field(field, vc_record_cred) - @pytest.mark.asyncio async def test_filter_by_field_xsd_parser(self): dif_pres_exch_handler = DIFPresExchHandler( self.profile, proof_type=BbsBlsSignature2020.signature_type From 1d07edec1783ce44de58c0b7501287e272c5686d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:28:57 -0800 Subject: [PATCH 09/72] chore(deps-dev): Bump ruff from 0.7.3 to 0.7.4 (#3341) Bumps [ruff](https://github.com/astral-sh/ruff) from 0.7.3 to 0.7.4. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.7.3...0.7.4) --- updated-dependencies: - dependency-name: ruff dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 42 +++++++++++++++++++++--------------------- pyproject.toml | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/poetry.lock b/poetry.lock index cc45282759..0d804a62de 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -2501,29 +2501,29 @@ test = ["hypothesis (==5.19.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "ruff" -version = "0.7.3" +version = "0.7.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.7.3-py3-none-linux_armv6l.whl", hash = "sha256:34f2339dc22687ec7e7002792d1f50712bf84a13d5152e75712ac08be565d344"}, - {file = "ruff-0.7.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fb397332a1879b9764a3455a0bb1087bda876c2db8aca3a3cbb67b3dbce8cda0"}, - {file = "ruff-0.7.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:37d0b619546103274e7f62643d14e1adcbccb242efda4e4bdb9544d7764782e9"}, - {file = "ruff-0.7.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59f0c3ee4d1a6787614e7135b72e21024875266101142a09a61439cb6e38a5"}, - {file = "ruff-0.7.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:44eb93c2499a169d49fafd07bc62ac89b1bc800b197e50ff4633aed212569299"}, - {file = "ruff-0.7.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d0242ce53f3a576c35ee32d907475a8d569944c0407f91d207c8af5be5dae4e"}, - {file = "ruff-0.7.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6b6224af8b5e09772c2ecb8dc9f3f344c1aa48201c7f07e7315367f6dd90ac29"}, - {file = "ruff-0.7.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c50f95a82b94421c964fae4c27c0242890a20fe67d203d127e84fbb8013855f5"}, - {file = "ruff-0.7.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f3eff9961b5d2644bcf1616c606e93baa2d6b349e8aa8b035f654df252c8c67"}, - {file = "ruff-0.7.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8963cab06d130c4df2fd52c84e9f10d297826d2e8169ae0c798b6221be1d1d2"}, - {file = "ruff-0.7.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:61b46049d6edc0e4317fb14b33bd693245281a3007288b68a3f5b74a22a0746d"}, - {file = "ruff-0.7.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:10ebce7696afe4644e8c1a23b3cf8c0f2193a310c18387c06e583ae9ef284de2"}, - {file = "ruff-0.7.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3f36d56326b3aef8eeee150b700e519880d1aab92f471eefdef656fd57492aa2"}, - {file = "ruff-0.7.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5d024301109a0007b78d57ab0ba190087b43dce852e552734ebf0b0b85e4fb16"}, - {file = "ruff-0.7.3-py3-none-win32.whl", hash = "sha256:4ba81a5f0c5478aa61674c5a2194de8b02652f17addf8dfc40c8937e6e7d79fc"}, - {file = "ruff-0.7.3-py3-none-win_amd64.whl", hash = "sha256:588a9ff2fecf01025ed065fe28809cd5a53b43505f48b69a1ac7707b1b7e4088"}, - {file = "ruff-0.7.3-py3-none-win_arm64.whl", hash = "sha256:1713e2c5545863cdbfe2cbce21f69ffaf37b813bfd1fb3b90dc9a6f1963f5a8c"}, - {file = "ruff-0.7.3.tar.gz", hash = "sha256:e1d1ba2e40b6e71a61b063354d04be669ab0d39c352461f3d789cac68b54a313"}, + {file = "ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478"}, + {file = "ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63"}, + {file = "ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a"}, + {file = "ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac"}, + {file = "ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6"}, + {file = "ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f"}, + {file = "ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2"}, ] [[package]] @@ -3028,4 +3028,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "d81899e5cdc890d282640cb4e12b4d6f1c5c294f1d59ba7045b96c0b35c0ef61" +content-hash = "1ac7b5e9aa0c4f3168be836875f38790bbf1e6d784d77951d36ce1f018f369d5" diff --git a/pyproject.toml b/pyproject.toml index bcfe87c352..2d1c5b9dd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,7 @@ canonicaljson = "^2.0.0" [tool.poetry.group.dev.dependencies] pre-commit = "~3.8.0" # Sync with version in .pre-commit-config.yaml -ruff = "0.7.3" +ruff = "0.7.4" sphinx = "^5.3.0" sphinx-rtd-theme = ">=0.4.3" From 2522877d475524084c5c2bbdc69ef41670dd6313 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:38:07 -0800 Subject: [PATCH 10/72] chore(deps): Bump aiohttp from 3.11.0 to 3.11.2 (#3340) Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.11.0 to 3.11.2. - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.11.0...v3.11.2) --- updated-dependencies: - dependency-name: aiohttp dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 156 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/poetry.lock b/poetry.lock index 0d804a62de..021ea10faa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -13,87 +13,87 @@ files = [ [[package]] name = "aiohttp" -version = "3.11.0" +version = "3.11.2" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" files = [ - {file = "aiohttp-3.11.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:024409c1b1d6076d0ed933dcebd7e4fc6f3320a227bfa0c1b6b93a8b5a146f04"}, - {file = "aiohttp-3.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:62502b8ffee8c6a4b5c6bf99d1de277d42bf51b2fb713975d9b63b560150b7ac"}, - {file = "aiohttp-3.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c54c635d1f52490cde7ef3a423645167a8284e452a35405d5c7dc1242a8e75c9"}, - {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:104ea21994b1403e4c1b398866f1187c1694fa291314ad7216ec1d8ec6b49f38"}, - {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04b24497b3baf15035730de5f207ade88a67d4483a5f16ced7ece348933a5b47"}, - {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08474e71772a516ba2e2167b4707af8361d2c452b3d8a5364c984f4867869499"}, - {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f40380c96dd407dfa84eb2d264e68aa47717b53bdbe210a59cc3c35a4635f195"}, - {file = "aiohttp-3.11.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1668ef2f3a7ec9881f4b6a917e5f97c87a343fa6b0d5fc826b7b0297ddd0887"}, - {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f3bf5c132eb48002bcc3825702d241d35b4e9585009e65e9dcf9c4635d0b7424"}, - {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0315978b2a4569e03fb59100f6a7e7d23f718a4521491f5c13d946d37549f3d"}, - {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d5cae4cd271e20b7ab757e966cc919186b9f02535418ab36c471a5377ef4deaa"}, - {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:31b91ff3a1fcb206a1fa76e0de1f08c9ffb1dc0deb7296fa2618adfe380fc676"}, - {file = "aiohttp-3.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ebf610c37df4f09c71c9bbf8309b4b459107e6fe889ac0d7e16f6e4ebd975f86"}, - {file = "aiohttp-3.11.0-cp310-cp310-win32.whl", hash = "sha256:b40c304ab01e89ad0aeeecf91bbaa6ae3b00e27b796c9e8d50b71a4a7e885cc8"}, - {file = "aiohttp-3.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd0834e4260eab78671b81d34f110fbaac449563e48d419cec0030d9a8e58693"}, - {file = "aiohttp-3.11.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:89a96a0696dc67d548f69cb518c581a7a33cc1f26ab42229dea1709217c9d926"}, - {file = "aiohttp-3.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f6b925c7775ab857bdc1e52e1f5abcae7d18751c09b751aeb641a5276d9b990e"}, - {file = "aiohttp-3.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7867d0808614f04e78e0a8d5a2c1f8ac6bc626a0c0e2f62be48be6b749e2f8b2"}, - {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:229ae13959a5f499d90ffbb4b9eac2255d8599315027d6f7c22fa9803a94d5b1"}, - {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62a2f5268b672087c45b33479ba1bb1d5a48c6d76c133cfce3a4f77410c200d1"}, - {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a896059b6937d1a22d8ee8377cdcd097bd26cd8c653b8f972051488b9baadee9"}, - {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:104deb7873681273c5daa13c41924693df394043a118dae90387d35bc5531788"}, - {file = "aiohttp-3.11.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae36ae52b0c22fb69fb8b744eff82a20db512a29eafc6e3a4ab43b17215b219d"}, - {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7349205bb163318dcc102329d30be59a647a3d24c82c3d91ed35b7e7301ea7e"}, - {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9095580806d9ed07c0c29b23364a0b1fb78258ef9f4bddf7e55bac0e475d4edf"}, - {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4d218d3eca40196384ad3b481309c56fd60e664128885d1734da0a8aa530d433"}, - {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6533dd06df3d17d1756829b68b365b1583929b54082db8f65083a4184bf68322"}, - {file = "aiohttp-3.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72cd984f7f14e8c01b3e38f18f39ea85dba84e52ea05e37116ba5e2a72eef396"}, - {file = "aiohttp-3.11.0-cp311-cp311-win32.whl", hash = "sha256:c1828e10c3a49e2b234b87600ecb68a92b8a8dcf8b99bca9447f16c4baaa1630"}, - {file = "aiohttp-3.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:900ff74d78eb580ae4aa5883242893b123a0c442a46570902500f08d6a7e6696"}, - {file = "aiohttp-3.11.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f8f0d79b923070f25674e4ea8f3d61c9d89d24d9598d50ff32c5b9b23c79a25b"}, - {file = "aiohttp-3.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:113bf06b029143e94a47c4f36e11a8b7e396e9d1f1fc8cea58e6b7e370cfed38"}, - {file = "aiohttp-3.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3e1ed8d152cccceffb1ee7a2ac227c16372e453fb11b3aeaa56783049b85d3f6"}, - {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2e82e515e268b965424ecabebd91834a41b36260b6ef5db015ee12ddb28ef3"}, - {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c1c49bc393d854d4421ebc174a0a41f9261f50d3694d8ca277146cbbcfd24ee7"}, - {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57e17c6d71f2dc857a8a1d09be1be7802e35d90fb4ba4b06cf1aab6414a57894"}, - {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12071dd2cc95ba81e0f2737bebcb98b2a8656015e87772e84e8fb9e635b5da6e"}, - {file = "aiohttp-3.11.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97056d3422594e0787733ac4c45bef58722d452f4dc6615fee42f59fe51707dd"}, - {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2ec5efbc872b00ddd85e3904059d274f284cff314e13f48776050ca2c58f451d"}, - {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:dd505a1121ad5b666191840b7bd1d8cb917df2647deeca6f3474331b72452362"}, - {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:600b1d9f86a130131915e2f2127664311b33902c486b21a747d626f5144b4471"}, - {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8c47a0ba6c2b3d3e5715f8338d657badd21f778c6be16701922c65521c5ecfc9"}, - {file = "aiohttp-3.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8b323b5d3aef7dd811424c269322eec58a977c0c8152e650159e47210d900504"}, - {file = "aiohttp-3.11.0-cp312-cp312-win32.whl", hash = "sha256:aabc4e92cb153636d6be54e84dad1b252ddb9aebe077942b6dcffe5e468d476a"}, - {file = "aiohttp-3.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:508cfcc99534b1282595357592d8367b44392b21f6eb5d4dc021f8d0d809e94d"}, - {file = "aiohttp-3.11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c98a596ac20e8980cc6f34c0c92a113e98eb08f3997c150064d26d2aeb043e5a"}, - {file = "aiohttp-3.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ad14cdc0fba4df31c0f6e06c21928c5b924725cbf60d0ccc5f6e7132636250e9"}, - {file = "aiohttp-3.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:170fb2324826bb9f08055a8291f42192ae5ee2f25b2966c8f0f4537c61d73a7b"}, - {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdad66685fcf2ad14ce522cf849d4a025f4fd206d6cfc3f403d9873e4c243b03"}, - {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8b95a63a8e8b5f0464bd8b1b0d59d2bec98a59b6aacc71e9be23df6989b3dfb"}, - {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7bcfcede95531589295f56e924702cef7f9685c9e4e5407592e04ded6a65bf3"}, - {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ecc2fb1a0a9d48cf773add34196cddf7e488e48e9596e090849751bf43098f4"}, - {file = "aiohttp-3.11.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8fef105113d56e817cb9bcc609667ee461321413a7b972b03f5b4939f40f307c"}, - {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d33b4490026968bdc7f0729b9d87a3a6b1e09043557d2fc1c605c6072deb2f11"}, - {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6362f50a6f0e5482c4330d2151cb682779230683da0e155c15ec9fc58cb50b6a"}, - {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f698aa61879df64425191d41213dfd99efdc1627e6398e6d7aa5c312fac9702"}, - {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0e7a0762cc29cd3acd01a4d2b547b3af7956ad230ebb80b529a8e4f3e4740fe8"}, - {file = "aiohttp-3.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b3e4fb7f5354d39490d8209aefdf5830b208d01c7293a2164e404312c3d8bc55"}, - {file = "aiohttp-3.11.0-cp313-cp313-win32.whl", hash = "sha256:6c5a6958f4366496004cf503d847093d464814543f157ef3b738bbf604232415"}, - {file = "aiohttp-3.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:3ed360d6672a9423aad39902a4e9fe305464d20ed7931dbdba30a4625782d875"}, - {file = "aiohttp-3.11.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d1ea006426edf7e1299c52a58b0443158012f7a56fed3515164b60bfcb1503a9"}, - {file = "aiohttp-3.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c5e6a1f8b0268ffa1c84d7c3558724956002ba8361176e76406233e704bbcffb"}, - {file = "aiohttp-3.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40dc9446cff326672fcbf93efdb8ef7e949824de1097624efe4f61ac7f0d2c43"}, - {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b4545e8d96870da9652930c5198366605ff8f982757030e2148cf341e5746b"}, - {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:37f8cf3c43f292d9bb3e6760476c2b55b9663a581fad682a586a410c43a7683e"}, - {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329f5059e0bf6983dceebac8e6ed20e75eaff6163b3414f4a4cb59e0d7037672"}, - {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ae6f182be72c3531915e90625cc65afce4df8a0fc4988bd52d8a5d5faaeb68"}, - {file = "aiohttp-3.11.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d664e5f937c08adb7908ea9f391fbf2928a9b09cb412ac0aba602bde9e499e4"}, - {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:feca9fafa4385aea6759c171cd25ea82f7375312fca04178dae35331be45e538"}, - {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c415b9601ff50709d6050c8a9281733a9b042b9e589265ac40305b875cf9c463"}, - {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:91d3991fad8b65e5dbc13cd95669ea689fe0a96ff63e4e64ac24ed724e4f8103"}, - {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9231d610754724273a6ac05a1f177979490bfa6f84d49646df3928af2e88cfd5"}, - {file = "aiohttp-3.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4e4e155968040e32c124a89852a1a5426d0e920a35f4331e1b3949037bfe93a3"}, - {file = "aiohttp-3.11.0-cp39-cp39-win32.whl", hash = "sha256:76d6ee8bb132f8ee0fcb0e205b4708ddb6fba524eb515ee168113063d825131b"}, - {file = "aiohttp-3.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:577c7429f8869fa30186fc2c9eee64d75a30b51b61f26aac9725866ae5985cfd"}, - {file = "aiohttp-3.11.0.tar.gz", hash = "sha256:f57a0de48dda792629e7952d34a0c7b81ea336bb9b721391c7c58145b237fe55"}, + {file = "aiohttp-3.11.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:783741f534c14957fbe657d62a34b947ec06db23d45a2fd4a8aeb73d9c84d7e6"}, + {file = "aiohttp-3.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:435f7a08d8aa42371a94e7c141205a9cb092ba551084b5e0c57492e6673601a3"}, + {file = "aiohttp-3.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c681f34e2814bc6e1eef49752b338061b94a42c92734d0be9513447d3f83718c"}, + {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73a664478ae1ea011b5a710fb100b115ca8b2146864fa0ce4143ff944df714b8"}, + {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1d06c8fd8b453c3e553c956bd3b8395100401060430572174bb7876dd95ad49"}, + {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b1f4844909321ef2c1cee50ddeccbd6018cd8c8d1ddddda3f553e94a5859497"}, + {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdc6f8dce09281ae534eaf08a54f0d38612398375f28dad733a8885f3bf9b978"}, + {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2d942421cf3a1d1eceae8fa192f1fbfb74eb9d3e207d35ad2696bd2ce2c987c"}, + {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:08ebe7a1d6c1e5ca766d68407280d69658f5f98821c2ba6c41c63cabfed159af"}, + {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2793d3297f3e49015140e6d3ea26142c967e07998e2fb00b6ee8d041138fbc4e"}, + {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4a23475d8d5c56e447b7752a1e2ac267c1f723f765e406c81feddcd16cdc97bc"}, + {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:556564d89e2f4a6e8fe000894c03e4e84cf0b6cfa5674e425db122633ee244d1"}, + {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:57993f406ce3f114b2a6756d7809be3ffd0cc40f33e8f8b9a4aa1b027fd4e3eb"}, + {file = "aiohttp-3.11.2-cp310-cp310-win32.whl", hash = "sha256:177b000efaf8d2f7012c649e8aee5b0bf488677b1162be5e7511aa4f9d567607"}, + {file = "aiohttp-3.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:ff5d22eece44528023254b595c670dfcf9733ac6af74c4b6cb4f6a784dc3870c"}, + {file = "aiohttp-3.11.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:50e0aee4adc9abcd2109c618a8d1b2c93b85ac277b24a003ab147d91e068b06d"}, + {file = "aiohttp-3.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9aa4e68f1e4f303971ec42976fb170204fb5092de199034b57199a1747e78a2d"}, + {file = "aiohttp-3.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d84930b4145991214602372edd7305fc76b700220db79ac0dd57d3afd0f0a1ca"}, + {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ec8afd362356b8798c8caa806e91deb3f0602d8ffae8e91d2d3ced2a90c35e"}, + {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb0544a0e8294a5a5e20d3cacdaaa9a911d7c0a9150f5264aef36e7d8fdfa07e"}, + {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7b0a1618060e3f5aa73d3526ca2108a16a1b6bf86612cd0bb2ddcbef9879d06"}, + {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d878a0186023ac391861958035174d0486f3259cabf8fd94e591985468da3ea"}, + {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e33a7eddcd07545ccf5c3ab230f60314a17dc33e285475e8405e26e21f02660"}, + {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4d7fad8c456d180a6d2f44c41cfab4b80e2e81451815825097db48b8293f59d5"}, + {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d954ba0eae7f33884d27dc00629ca4389d249eb8d26ca07c30911257cae8c96"}, + {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:afa55e863224e664a782effa62245df73fdfc55aee539bed6efacf35f6d4e4b7"}, + {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:10a5f91c319d9d4afba812f72984816b5fcd20742232ff7ecc1610ffbf3fc64d"}, + {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6e8e19a80ba194db5c06915a9df23c0c06e0e9ca9a4db9386a6056cca555a027"}, + {file = "aiohttp-3.11.2-cp311-cp311-win32.whl", hash = "sha256:9c8d1db4f65bbc9d75b7b271d68fb996f1c8c81a525263862477d93611856c2d"}, + {file = "aiohttp-3.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:2adb967454e10e69478ba4a8d8afbba48a7c7a8619216b7c807f8481cc66ddfb"}, + {file = "aiohttp-3.11.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f833a80d9de9307d736b6af58c235b17ef7f90ebea7b9c49cd274dec7a66a2f1"}, + {file = "aiohttp-3.11.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:382f853516664d2ebfc75dc01da4a10fdef5edcb335fe7b45cf471ce758ecb18"}, + {file = "aiohttp-3.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3a2bcf6c81639a165da93469e1e0aff67c956721f3fa9c0560f07dd1e505116"}, + {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de3b4d5fb5d69749104b880a157f38baeea7765c93d9cd3837cedd5b84729e10"}, + {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a90a0dc4b054b5af299a900bf950fe8f9e3e54322bc405005f30aa5cacc5c98"}, + {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32334f35824811dd20a12cc90825d000e6b50faaeaa71408d42269151a66140d"}, + {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cba0b8d25aa2d450762f3dd6df85498f5e7c3ad0ddeb516ef2b03510f0eea32"}, + {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bbb2dbc2701ab7e9307ca3a8fa4999c5b28246968e0a0202a5afabf48a42e22"}, + {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97fba98fc5d9ccd3d33909e898d00f2494d6a9eec7cbda3d030632e2c8bb4d00"}, + {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0ebdf5087e2ce903d8220cc45dcece90c2199ae4395fd83ca616fcc81010db2c"}, + {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:122768e3ae9ce74f981b46edefea9c6e5a40aea38aba3ac50168e6370459bf20"}, + {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5587da333b7d280a312715b843d43e734652aa382cba824a84a67c81f75b338b"}, + {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:85de9904bc360fd29a98885d2bfcbd4e02ab33c53353cb70607f2bea2cb92468"}, + {file = "aiohttp-3.11.2-cp312-cp312-win32.whl", hash = "sha256:b470de64d17156c37e91effc109d3b032b39867000e2c126732fe01d034441f9"}, + {file = "aiohttp-3.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:3f617a48b70f4843d54f52440ea1e58da6bdab07b391a3a6aed8d3b311a4cc04"}, + {file = "aiohttp-3.11.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5d90b5a3b0f32a5fecf5dd83d828713986c019585f5cddf40d288ff77f366615"}, + {file = "aiohttp-3.11.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d23854e5867650d40cba54d49956aad8081452aa80b2cf0d8c310633f4f48510"}, + {file = "aiohttp-3.11.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:486273d3b5af75a80c31c311988931bdd2a4b96a74d5c7f422bad948f99988ef"}, + {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9075313f8e41b481e4cb10af405054564b0247dc335db5398ed05f8ec38787e2"}, + {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44b69c69c194ffacbc50165911cf023a4b1b06422d1e1199d3aea82eac17004e"}, + {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b339d91ac9060bd6ecdc595a82dc151045e5d74f566e0864ef3f2ba0887fec42"}, + {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64e8f5178958a9954043bc8cd10a5ae97352c3f2fc99aa01f2aebb0026010910"}, + {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3129151378f858cdc4a0a4df355c9a0d060ab49e2eea7e62e9f085bac100551b"}, + {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:14eb6c628432720e41b4fab1ada879d56cfe7034159849e083eb536b4c2afa99"}, + {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e57a10aacedcf24666f4c90d03e599f71d172d1c5e00dcf48205c445806745b0"}, + {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:66e58a2e8c7609a3545c4b38fb8b01a6b8346c4862e529534f7674c5265a97b8"}, + {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9b6d15adc9768ff167614ca853f7eeb6ee5f1d55d5660e3af85ce6744fed2b82"}, + {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2914061f5ca573f990ec14191e6998752fa8fe50d518e3405410353c3f44aa5d"}, + {file = "aiohttp-3.11.2-cp313-cp313-win32.whl", hash = "sha256:1c2496182e577042e0e07a328d91c949da9e77a2047c7291071e734cd7a6e780"}, + {file = "aiohttp-3.11.2-cp313-cp313-win_amd64.whl", hash = "sha256:cccb2937bece1310c5c0163d0406aba170a2e5fb1f0444d7b0e7fdc9bd6bb713"}, + {file = "aiohttp-3.11.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:994cb893936dd2e1803655ae8667a45066bfd53360b148e22b4e3325cc5ea7a3"}, + {file = "aiohttp-3.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3666c750b73ce463a413692e3a57c60f7089e2d9116a2aa5a0f0eaf2ae325148"}, + {file = "aiohttp-3.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6ad9a7d2a3a0f235184426425f80bd3b26c66b24fd5fddecde66be30c01ebe6e"}, + {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c979fc92aba66730b66099cd5becb42d869a26c0011119bc1c2478408a8bf7a"}, + {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:766d0ebf8703d28f854f945982aa09224d5a27a29594c70d921c43c3930fe7ac"}, + {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79efd1ee3827b2f16797e14b1e45021206c3271249b4d0025014466d416d7413"}, + {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d6e069b882c1fdcbe5577dc4be372eda705180197140577a4cddb648c29d22e"}, + {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e9a766c346b2ed7e88937919d84ed64b4ef489dad1d8939f806ee52901dc142"}, + {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2b02a68b9445c70d7f5c8b578c5f5e5866b1d67ca23eb9e8bc8658ae9e3e2c74"}, + {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:374baefcb1b6275f350da605951f5f02487a9bc84a574a7d5b696439fabd49a3"}, + {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d2f991c18132f3e505c108147925372ffe4549173b7c258cf227df1c5977a635"}, + {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:34f37c59b12bc3afc52bab6fcd9cd3be82ff01c4598a84cbea934ccb3a9c54a0"}, + {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:33af11eca7bb0f5c6ffaf5e7d9d2336c2448f9c6279b93abdd6f3c35f9ee321f"}, + {file = "aiohttp-3.11.2-cp39-cp39-win32.whl", hash = "sha256:83a70e22e0f6222effe7f29fdeba6c6023f9595e59a0479edacfbd7de4b77bb7"}, + {file = "aiohttp-3.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:c28c1677ea33ccb8b14330560094cc44d3ff4fad617a544fd18beb90403fe0f1"}, + {file = "aiohttp-3.11.2.tar.gz", hash = "sha256:68d1f46f9387db3785508f5225d3acbc5825ca13d9c29f2b5cce203d5863eb79"}, ] [package.dependencies] @@ -3028,4 +3028,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "1ac7b5e9aa0c4f3168be836875f38790bbf1e6d784d77951d36ce1f018f369d5" +content-hash = "0b4f353fe6535b24f7eef4f13d6c415c9247da3fa47efd51ecc87413e248f3b8" diff --git a/pyproject.toml b/pyproject.toml index 2d1c5b9dd0..febe67b4d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ repository = "https://github.com/openwallet-foundation/acapy" [tool.poetry.dependencies] python = "^3.12" -aiohttp = "~3.11.0" +aiohttp = "~3.11.2" aiohttp-apispec-acapy = "~3.0.2" aiohttp-cors = "~0.7.0" apispec = "^6.6.0" From c18f6d19bcd9274dfb9cf7048c49291f4e1fc43b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:05:59 -0800 Subject: [PATCH 11/72] chore(deps): Bump pyjwt from 2.9.0 to 2.10.0 (#3339) Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.9.0 to 2.10.0. - [Release notes](https://github.com/jpadilla/pyjwt/releases) - [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst) - [Commits](https://github.com/jpadilla/pyjwt/compare/2.9.0...2.10.0) --- updated-dependencies: - dependency-name: pyjwt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 021ea10faa..60bfdb4510 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2168,13 +2168,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.9.0" +version = "2.10.0" description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, - {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, + {file = "PyJWT-2.10.0-py3-none-any.whl", hash = "sha256:543b77207db656de204372350926bed5a86201c4cbff159f623f79c7bb487a15"}, + {file = "pyjwt-2.10.0.tar.gz", hash = "sha256:7628a7eb7938959ac1b26e819a1df0fd3259505627b575e4bad6d08f76db695c"}, ] [package.extras] @@ -3028,4 +3028,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "0b4f353fe6535b24f7eef4f13d6c415c9247da3fa47efd51ecc87413e248f3b8" +content-hash = "d5ab2d9c2721f87d92ca77cc8bf7a044cfc2c41b58b111af84a454ac2cc96910" diff --git a/pyproject.toml b/pyproject.toml index febe67b4d6..0064c4701d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ packaging = "~23.2" portalocker = "~2.10.1" prompt_toolkit = ">=2.0.9,<2.1.0" pydid = "^0.5.1" -pyjwt = "~2.9.0" +pyjwt = "~2.10.0" pyld = "^2.0.4" pynacl = "~1.5.0" python-dateutil = "^2.9.0" From f5c49b0710dd180ea31c45f73bc82ef06f9523b4 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:40:31 -0800 Subject: [PATCH 12/72] did:tdw resolver (#3237) * did:tdw resolver Signed-off-by: jamshale * Update unit tests Signed-off-by: jamshale * Update poetry.lock Signed-off-by: jamshale --------- Signed-off-by: jamshale --- acapy_agent/messaging/tests/test_valid.py | 19 +++ acapy_agent/messaging/valid.py | 17 +++ acapy_agent/resolver/__init__.py | 6 + acapy_agent/resolver/default/tdw.py | 40 ++++++ .../resolver/default/tests/test_tdw.py | 36 ++++++ acapy_agent/wallet/did_method.py | 8 ++ poetry.lock | 119 +++++++++++++++++- pyproject.toml | 6 +- 8 files changed, 246 insertions(+), 5 deletions(-) create mode 100644 acapy_agent/resolver/default/tdw.py create mode 100644 acapy_agent/resolver/default/tests/test_tdw.py diff --git a/acapy_agent/messaging/tests/test_valid.py b/acapy_agent/messaging/tests/test_valid.py index 8983d27964..0f3b3d3363 100644 --- a/acapy_agent/messaging/tests/test_valid.py +++ b/acapy_agent/messaging/tests/test_valid.py @@ -12,6 +12,7 @@ CREDENTIAL_TYPE_VALIDATE, DID_KEY_VALIDATE, DID_POSTURE_VALIDATE, + DID_TDW_VALIDATE, ENDPOINT_TYPE_VALIDATE, ENDPOINT_VALIDATE, INDY_CRED_DEF_ID_VALIDATE, @@ -114,6 +115,24 @@ def test_indy_did(self): INDY_DID_VALIDATE("Q4zqM7aXqm7gDQkUVLng9h") INDY_DID_VALIDATE("did:sov:Q4zqM7aXqm7gDQkUVLng9h") + def test_tdw_did(self): + valid_tdw_dids = [ + "did:tdw:QmUchSB5f5DJQks9CeyLJjhAy4iKJcYzRyiuYq3sjV13px:example.com", + "did:tdw:QmZiKXwQVfyZVuvCsuHpQh4arSUpEmeVVRvSfv3uiEycSr:example.com%3A5000", + ] + for valid_tdw_did in valid_tdw_dids: + DID_TDW_VALIDATE(valid_tdw_did) + + non_valid_tdw_dids = [ + "did:web:QmUchSB5f5DJQks9CeyLJjhAy4iKJcYzRyiuYq3sjV13px", + # Did urls are not allowed + "did:tdw:QmP9VWaTCHcyztDpRj9XSHvZbmYe3m9HZ61KoDtZgWaXVU:example.com%3A5000#z6MkkzY9skorPaoEbCJFKUo7thD8Yb8MBs28aJRopf1TUo9V", + "did:tdw:QmZiKXwQVfyZVuvCsuHpQh4arSUpEmeVVRvSfv3uiEycSr:example.com%3A5000/whois", + ] + for non_valid_tdw_did in non_valid_tdw_dids: + with self.assertRaises(ValidationError): + DID_TDW_VALIDATE(non_valid_tdw_did) + def test_indy_raw_public_key(self): non_indy_raw_public_keys = [ "Q4zqM7aXqm7gDQkUVLng9JQ4zqM7aXqm7gDQkUVLng9I", # 'I' not a base58 char diff --git a/acapy_agent/messaging/valid.py b/acapy_agent/messaging/valid.py index 894c1a819b..fc1749d600 100644 --- a/acapy_agent/messaging/valid.py +++ b/acapy_agent/messaging/valid.py @@ -319,6 +319,20 @@ def __init__(self): ) +class DIDTdw(Regexp): + """Validate value against did:tdw specification.""" + + EXAMPLE = "did:tdw:QmP9VWaTCHcyztDpRj9XSHvZbmYe3m9HZ61KoDtZgWaXVU:example.com%3A5000" + PATTERN = re.compile(r"^(did:tdw:)([a-zA-Z0-9%._-]*:)*[a-zA-Z0-9%._-]+$") + + def __init__(self): + """Initialize the instance.""" + + super().__init__( + DIDTdw.PATTERN, error="Value {input} is not in W3C did:tdw format" + ) + + class DIDPosture(OneOf): """Validate value against defined DID postures.""" @@ -934,6 +948,9 @@ def __init__( DID_WEB_VALIDATE = DIDWeb() DID_WEB_EXAMPLE = DIDWeb.EXAMPLE +DID_TDW_VALIDATE = DIDTdw() +DID_TDW_EXAMPLE = DIDTdw.EXAMPLE + ROUTING_KEY_VALIDATE = RoutingKey() ROUTING_KEY_EXAMPLE = RoutingKey.EXAMPLE diff --git a/acapy_agent/resolver/__init__.py b/acapy_agent/resolver/__init__.py index 005cce6df9..3998b3da1c 100644 --- a/acapy_agent/resolver/__init__.py +++ b/acapy_agent/resolver/__init__.py @@ -49,6 +49,12 @@ async def setup(context: InjectionContext): await web_resolver.setup(context) registry.register_resolver(web_resolver) + tdw_resolver = ClassProvider( + "acapy_agent.resolver.default.tdw.TdwDIDResolver" + ).provide(context.settings, context.injector) + await tdw_resolver.setup(context) + registry.register_resolver(tdw_resolver) + if context.settings.get("resolver.universal"): universal_resolver = ClassProvider( "acapy_agent.resolver.default.universal.UniversalResolver" diff --git a/acapy_agent/resolver/default/tdw.py b/acapy_agent/resolver/default/tdw.py new file mode 100644 index 0000000000..4aabd198e8 --- /dev/null +++ b/acapy_agent/resolver/default/tdw.py @@ -0,0 +1,40 @@ +"""TDW DID Resolver. + +Resolution is performed by the did_tdw library. +""" + +from re import Pattern +from typing import Optional, Sequence, Text + +from did_tdw.resolver import ResolutionResult, resolve_did + +from ...config.injection_context import InjectionContext +from ...core.profile import Profile +from ...messaging.valid import DIDTdw +from ..base import BaseDIDResolver, ResolverType + + +class TdwDIDResolver(BaseDIDResolver): + """TDW DID Resolver.""" + + def __init__(self): + """Initialize the TDW DID Resolver.""" + super().__init__(ResolverType.NATIVE) + + async def setup(self, context: InjectionContext): + """Perform required setup for TDW DID resolution.""" + + @property + def supported_did_regex(self) -> Pattern: + """Return supported DID regex of TDW DID Resolver.""" + return DIDTdw.PATTERN + + async def _resolve( + self, profile: Profile, did: str, service_accept: Optional[Sequence[Text]] = None + ) -> dict: + """Resolve DID using TDW.""" + response: ResolutionResult = await resolve_did(did) + if response.resolution_metadata and response.resolution_metadata.get("error"): + return response.resolution_metadata + + return response.document diff --git a/acapy_agent/resolver/default/tests/test_tdw.py b/acapy_agent/resolver/default/tests/test_tdw.py new file mode 100644 index 0000000000..8829b9f031 --- /dev/null +++ b/acapy_agent/resolver/default/tests/test_tdw.py @@ -0,0 +1,36 @@ +import pytest + +from ....core.profile import Profile +from ....messaging.valid import DIDTdw +from ....utils.testing import create_test_profile +from ..tdw import TdwDIDResolver + +TEST_DID = "did:tdw:Qma6mc1qZw3NqxwX6SB5GPQYzP4pGN2nXD15Jwi4bcDBKu:domain.example" + + +@pytest.fixture +def resolver(): + """Resolver fixture.""" + yield TdwDIDResolver() + + +@pytest.fixture +async def profile(): + """Profile fixture.""" + yield await create_test_profile() + + +@pytest.mark.asyncio +async def test_supported_did_regex(profile, resolver: TdwDIDResolver): + """Test the supported_did_regex.""" + assert resolver.supported_did_regex == DIDTdw.PATTERN + assert await resolver.supports( + profile, + TEST_DID, + ) + + +@pytest.mark.asyncio +async def test_resolve(resolver: TdwDIDResolver, profile: Profile): + """Test resolve method.""" + assert await resolver.resolve(profile, TEST_DID) diff --git a/acapy_agent/wallet/did_method.py b/acapy_agent/wallet/did_method.py index bf6ff57304..2acf670837 100644 --- a/acapy_agent/wallet/did_method.py +++ b/acapy_agent/wallet/did_method.py @@ -90,6 +90,13 @@ def holder_defined_did(self) -> HolderDefinedDid: holder_defined_did=HolderDefinedDid.NO, ) +TDW = DIDMethod( + name="tdw", + key_types=[ED25519, X25519], + rotation=False, + holder_defined_did=HolderDefinedDid.NO, +) + class DIDMethods: """DID Method class specifying DID methods with supported key types.""" @@ -102,6 +109,7 @@ def __init__(self) -> None: WEB.method_name: WEB, PEER2.method_name: PEER2, PEER4.method_name: PEER4, + TDW.method_name: TDW, } def registered(self, method: str) -> bool: diff --git a/poetry.lock b/poetry.lock index 60bfdb4510..465055db55 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,15 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "aiofiles" +version = "24.1.0" +description = "File support for asyncio." +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, + {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, +] [[package]] name = "aiohappyeyeballs" @@ -213,7 +224,7 @@ yaml = ["PyYAML (>=3.10)"] name = "aries-askar" version = "0.3.2" description = "" -optional = true +optional = false python-versions = ">=3.6.3" files = [ {file = "aries_askar-0.3.2-py3-none-macosx_10_9_universal2.whl", hash = "sha256:02ddbe1773ce72c57edafff5777a1337d4a678da7484596712949170fb3ca1dc"}, @@ -283,11 +294,29 @@ files = [ [package.extras] tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-flake8"] +[[package]] +name = "bases" +version = "0.3.0" +description = "Python library for general Base-N encodings." +optional = false +python-versions = ">=3.7" +files = [ + {file = "bases-0.3.0-py3-none-any.whl", hash = "sha256:a2fef3366f3e522ff473d2e95c21523fe8e44251038d5c6150c01481585ebf5b"}, + {file = "bases-0.3.0.tar.gz", hash = "sha256:70f04a4a45d63245787f9e89095ca11042685b6b64b542ad916575ba3ccd1570"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0" +typing-validation = ">=1.1.0" + +[package.extras] +dev = ["base58", "mypy", "pylint", "pytest", "pytest-cov"] + [[package]] name = "cached-property" version = "1.5.2" description = "A decorator for caching properties in classes." -optional = true +optional = false python-versions = "*" files = [ {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, @@ -855,6 +884,25 @@ files = [ [package.dependencies] base58 = ">=2.1.1" +[[package]] +name = "did-tdw" +version = "0.2.1" +description = "This repository includes Python libraries for working with `did:tdw` (Trust DID Web) DID documents and the underlying log format." +optional = false +python-versions = "<4.0,>=3.10" +files = [ + {file = "did_tdw-0.2.1-py3-none-any.whl", hash = "sha256:80c727d0bef37e2211d3caddb97ba3c4aa508c67d4ef502da5f326d9bf4c3ffb"}, + {file = "did_tdw-0.2.1.tar.gz", hash = "sha256:a61ed9f49369ea4c365e5e380431feae8cb3988375de37f73be2abe15d0bfde6"}, +] + +[package.dependencies] +aiofiles = ">=24.1.0,<25.0.0" +aiohttp = ">=3.10.5,<4.0.0" +aries-askar = ">=0.3.2,<0.4.0" +base58 = ">=2.1.0,<2.2.0" +jsoncanon = ">=0.2.3,<0.3.0" +multiformats = ">=0.3.1,<0.4.0" + [[package]] name = "didcomm-messaging" version = "0.1.1" @@ -1258,6 +1306,17 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "jsoncanon" +version = "0.2.3" +description = "Typed Python implementation of JSON Canonicalization Scheme as described in RFC 8785. Currently lacks full floating point support" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "jsoncanon-0.2.3-py3-none-any.whl", hash = "sha256:adb35dac2d0c5dd56f1cb374f1ea6f1fff2ebbb4e844b06d9c96b9ccadf12bf0"}, + {file = "jsoncanon-0.2.3.tar.gz", hash = "sha256:483c1ef14e6c8151ba69c0bf646551f249698dd523e9c6da1339a688c5f96d6d"}, +] + [[package]] name = "jsonpath-ng" version = "1.7.0" @@ -1644,6 +1703,44 @@ files = [ {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[[package]] +name = "multiformats" +version = "0.3.1.post4" +description = "Python implementation of multiformats protocols." +optional = false +python-versions = ">=3.7" +files = [ + {file = "multiformats-0.3.1.post4-py3-none-any.whl", hash = "sha256:5b1d61bd8275c9e817bdbee38dbd501b26629011962ee3c86c46e7ccd0b14129"}, + {file = "multiformats-0.3.1.post4.tar.gz", hash = "sha256:d00074fdbc7d603c2084b4c38fa17bbc28173cf2750f51f46fbbc5c4d5605fbb"}, +] + +[package.dependencies] +bases = ">=0.3.0" +multiformats-config = ">=0.3.0" +typing-extensions = ">=4.6.0" +typing-validation = ">=1.1.0" + +[package.extras] +dev = ["blake3", "mmh3", "mypy", "pycryptodomex", "pylint", "pyskein", "pytest", "pytest-cov", "rich"] +full = ["blake3", "mmh3", "pycryptodomex", "pyskein", "rich"] + +[[package]] +name = "multiformats-config" +version = "0.3.1" +description = "Pre-loading configuration module for the 'multiformats' package." +optional = false +python-versions = ">=3.7" +files = [ + {file = "multiformats-config-0.3.1.tar.gz", hash = "sha256:7eaa80ef5d9c5ee9b86612d21f93a087c4a655cbcb68960457e61adbc62b47a7"}, + {file = "multiformats_config-0.3.1-py3-none-any.whl", hash = "sha256:dec4c9d42ed0d9305889b67440f72e8e8d74b82b80abd7219667764b5b0a8e1d"}, +] + +[package.dependencies] +multiformats = "*" + +[package.extras] +dev = ["mypy", "pylint", "pytest", "pytest-cov"] + [[package]] name = "nest-asyncio" version = "1.6.0" @@ -2746,6 +2843,20 @@ files = [ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "typing-validation" +version = "1.2.11.post4" +description = "A simple library for runtime type-checking." +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_validation-1.2.11.post4-py3-none-any.whl", hash = "sha256:73dd504ddebf5210e80d5f65ba9b30efbd0fa42f266728fda7c4f0ba335c699c"}, + {file = "typing_validation-1.2.11.post4.tar.gz", hash = "sha256:7aed04ecfbda07e63b7266f90e5d096f96344f7facfe04bb081b21e4a9781670"}, +] + +[package.extras] +dev = ["mypy", "pylint", "pytest", "pytest-cov", "rich"] + [[package]] name = "unflatten" version = "0.2.0" @@ -3028,4 +3139,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "d5ab2d9c2721f87d92ca77cc8bf7a044cfc2c41b58b111af84a454ac2cc96910" +content-hash = "543d20028efad5a9d798071ba86e9d1ab39b202fe1afaa27f8f4c7f656f1d7cc" diff --git a/pyproject.toml b/pyproject.toml index 0064c4701d..7de97f37b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,9 +45,13 @@ requests = "~2.32.3" rlp = "4.0.1" unflatten = "~0.2" sd-jwt = "^0.10.3" +uuid_utils = "^0.9.0" + +# did libraries did-peer-2 = "^0.1.2" did-peer-4 = "^0.1.4" -uuid_utils = "^0.9.0" +did-tdw = "^0.2.1" + # askar aries-askar = { version = "~0.3.2", optional = true } From 3c7dee88572facbb77304fca138320591ab76d1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:42:10 +0000 Subject: [PATCH 13/72] chore(deps): Bump aiohttp (#3342) Bumps the pip group with 1 update in the /scenarios directory: [aiohttp](https://github.com/aio-libs/aiohttp). Updates `aiohttp` from 3.10.5 to 3.10.11 - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.10.5...v3.10.11) --- updated-dependencies: - dependency-name: aiohttp dependency-type: indirect dependency-group: pip ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- scenarios/poetry.lock | 474 +++++++++++++++++++++++++----------------- 1 file changed, 287 insertions(+), 187 deletions(-) diff --git a/scenarios/poetry.lock b/scenarios/poetry.lock index 512f6c51a0..87805a2cb5 100644 --- a/scenarios/poetry.lock +++ b/scenarios/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "acapy-controller" @@ -36,112 +36,112 @@ files = [ [[package]] name = "aiohttp" -version = "3.10.5" +version = "3.10.11" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683"}, - {file = "aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef"}, - {file = "aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058"}, - {file = "aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072"}, - {file = "aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6"}, - {file = "aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12"}, - {file = "aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987"}, - {file = "aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04"}, - {file = "aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511"}, - {file = "aiohttp-3.10.5-cp38-cp38-win32.whl", hash = "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a"}, - {file = "aiohttp-3.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11"}, - {file = "aiohttp-3.10.5-cp39-cp39-win32.whl", hash = "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1"}, - {file = "aiohttp-3.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862"}, - {file = "aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5077b1a5f40ffa3ba1f40d537d3bec4383988ee51fbba6b74aa8fb1bc466599e"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d6a14a4d93b5b3c2891fca94fa9d41b2322a68194422bef0dd5ec1e57d7d298"}, + {file = "aiohttp-3.10.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffbfde2443696345e23a3c597049b1dd43049bb65337837574205e7368472177"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20b3d9e416774d41813bc02fdc0663379c01817b0874b932b81c7f777f67b217"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b943011b45ee6bf74b22245c6faab736363678e910504dd7531a58c76c9015a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48bc1d924490f0d0b3658fe5c4b081a4d56ebb58af80a6729d4bd13ea569797a"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e12eb3f4b1f72aaaf6acd27d045753b18101524f72ae071ae1c91c1cd44ef115"}, + {file = "aiohttp-3.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f14ebc419a568c2eff3c1ed35f634435c24ead2fe19c07426af41e7adb68713a"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:72b191cdf35a518bfc7ca87d770d30941decc5aaf897ec8b484eb5cc8c7706f3"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ab2328a61fdc86424ee540d0aeb8b73bbcad7351fb7cf7a6546fc0bcffa0038"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa93063d4af05c49276cf14e419550a3f45258b6b9d1f16403e777f1addf4519"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:30283f9d0ce420363c24c5c2421e71a738a2155f10adbb1a11a4d4d6d2715cfc"}, + {file = "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e5358addc8044ee49143c546d2182c15b4ac3a60be01c3209374ace05af5733d"}, + {file = "aiohttp-3.10.11-cp310-cp310-win32.whl", hash = "sha256:e1ffa713d3ea7cdcd4aea9cddccab41edf6882fa9552940344c44e59652e1120"}, + {file = "aiohttp-3.10.11-cp310-cp310-win_amd64.whl", hash = "sha256:778cbd01f18ff78b5dd23c77eb82987ee4ba23408cbed233009fd570dda7e674"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:80ff08556c7f59a7972b1e8919f62e9c069c33566a6d28586771711e0eea4f07"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c8f96e9ee19f04c4914e4e7a42a60861066d3e1abf05c726f38d9d0a466e695"}, + {file = "aiohttp-3.10.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fb8601394d537da9221947b5d6e62b064c9a43e88a1ecd7414d21a1a6fba9c24"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea224cf7bc2d8856d6971cea73b1d50c9c51d36971faf1abc169a0d5f85a382"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db9503f79e12d5d80b3efd4d01312853565c05367493379df76d2674af881caa"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0f449a50cc33f0384f633894d8d3cd020e3ccef81879c6e6245c3c375c448625"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82052be3e6d9e0c123499127782a01a2b224b8af8c62ab46b3f6197035ad94e9"}, + {file = "aiohttp-3.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20063c7acf1eec550c8eb098deb5ed9e1bb0521613b03bb93644b810986027ac"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:489cced07a4c11488f47aab1f00d0c572506883f877af100a38f1fedaa884c3a"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ea9b3bab329aeaa603ed3bf605f1e2a6f36496ad7e0e1aa42025f368ee2dc07b"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ca117819d8ad113413016cb29774b3f6d99ad23c220069789fc050267b786c16"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2dfb612dcbe70fb7cdcf3499e8d483079b89749c857a8f6e80263b021745c730"}, + {file = "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9b615d3da0d60e7d53c62e22b4fd1c70f4ae5993a44687b011ea3a2e49051b8"}, + {file = "aiohttp-3.10.11-cp311-cp311-win32.whl", hash = "sha256:29103f9099b6068bbdf44d6a3d090e0a0b2be6d3c9f16a070dd9d0d910ec08f9"}, + {file = "aiohttp-3.10.11-cp311-cp311-win_amd64.whl", hash = "sha256:236b28ceb79532da85d59aa9b9bf873b364e27a0acb2ceaba475dc61cffb6f3f"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7480519f70e32bfb101d71fb9a1f330fbd291655a4c1c922232a48c458c52710"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f65267266c9aeb2287a6622ee2bb39490292552f9fbf851baabc04c9f84e048d"}, + {file = "aiohttp-3.10.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7400a93d629a0608dc1d6c55f1e3d6e07f7375745aaa8bd7f085571e4d1cee97"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f34b97e4b11b8d4eb2c3a4f975be626cc8af99ff479da7de49ac2c6d02d35725"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e7b825da878464a252ccff2958838f9caa82f32a8dbc334eb9b34a026e2c636"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9f92a344c50b9667827da308473005f34767b6a2a60d9acff56ae94f895f385"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f1ab987a27b83c5268a17218463c2ec08dbb754195113867a27b166cd6087"}, + {file = "aiohttp-3.10.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1dc0f4ca54842173d03322793ebcf2c8cc2d34ae91cc762478e295d8e361e03f"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7ce6a51469bfaacff146e59e7fb61c9c23006495d11cc24c514a455032bcfa03"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aad3cd91d484d065ede16f3cf15408254e2469e3f613b241a1db552c5eb7ab7d"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f4df4b8ca97f658c880fb4b90b1d1ec528315d4030af1ec763247ebfd33d8b9a"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2e4e18a0a2d03531edbc06c366954e40a3f8d2a88d2b936bbe78a0c75a3aab3e"}, + {file = "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ce66780fa1a20e45bc753cda2a149daa6dbf1561fc1289fa0c308391c7bc0a4"}, + {file = "aiohttp-3.10.11-cp312-cp312-win32.whl", hash = "sha256:a919c8957695ea4c0e7a3e8d16494e3477b86f33067478f43106921c2fef15bb"}, + {file = "aiohttp-3.10.11-cp312-cp312-win_amd64.whl", hash = "sha256:b5e29706e6389a2283a91611c91bf24f218962717c8f3b4e528ef529d112ee27"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:703938e22434d7d14ec22f9f310559331f455018389222eed132808cd8f44127"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9bc50b63648840854e00084c2b43035a62e033cb9b06d8c22b409d56eb098413"}, + {file = "aiohttp-3.10.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f0463bf8b0754bc744e1feb61590706823795041e63edf30118a6f0bf577461"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6c6dec398ac5a87cb3a407b068e1106b20ef001c344e34154616183fe684288"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcaf2d79104d53d4dcf934f7ce76d3d155302d07dae24dff6c9fffd217568067"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25fd5470922091b5a9aeeb7e75be609e16b4fba81cdeaf12981393fb240dd10e"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbde2ca67230923a42161b1f408c3992ae6e0be782dca0c44cb3206bf330dee1"}, + {file = "aiohttp-3.10.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:249c8ff8d26a8b41a0f12f9df804e7c685ca35a207e2410adbd3e924217b9006"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:878ca6a931ee8c486a8f7b432b65431d095c522cbeb34892bee5be97b3481d0f"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8663f7777ce775f0413324be0d96d9730959b2ca73d9b7e2c2c90539139cbdd6"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6cd3f10b01f0c31481fba8d302b61603a2acb37b9d30e1d14e0f5a58b7b18a31"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e8d8aad9402d3aa02fdc5ca2fe68bcb9fdfe1f77b40b10410a94c7f408b664d"}, + {file = "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:38e3c4f80196b4f6c3a85d134a534a56f52da9cb8d8e7af1b79a32eefee73a00"}, + {file = "aiohttp-3.10.11-cp313-cp313-win32.whl", hash = "sha256:fc31820cfc3b2863c6e95e14fcf815dc7afe52480b4dc03393c4873bb5599f71"}, + {file = "aiohttp-3.10.11-cp313-cp313-win_amd64.whl", hash = "sha256:4996ff1345704ffdd6d75fb06ed175938c133425af616142e7187f28dc75f14e"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74baf1a7d948b3d640badeac333af581a367ab916b37e44cf90a0334157cdfd2"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:473aebc3b871646e1940c05268d451f2543a1d209f47035b594b9d4e91ce8339"}, + {file = "aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c2f746a6968c54ab2186574e15c3f14f3e7f67aef12b761e043b33b89c5b5f95"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d110cabad8360ffa0dec8f6ec60e43286e9d251e77db4763a87dcfe55b4adb92"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0099c7d5d7afff4202a0c670e5b723f7718810000b4abcbc96b064129e64bc7"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0316e624b754dbbf8c872b62fe6dcb395ef20c70e59890dfa0de9eafccd2849d"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a5f7ab8baf13314e6b2485965cbacb94afff1e93466ac4d06a47a81c50f9cca"}, + {file = "aiohttp-3.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c891011e76041e6508cbfc469dd1a8ea09bc24e87e4c204e05f150c4c455a5fa"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9208299251370ee815473270c52cd3f7069ee9ed348d941d574d1457d2c73e8b"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:459f0f32c8356e8125f45eeff0ecf2b1cb6db1551304972702f34cd9e6c44658"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:14cdc8c1810bbd4b4b9f142eeee23cda528ae4e57ea0923551a9af4820980e39"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:971aa438a29701d4b34e4943e91b5e984c3ae6ccbf80dd9efaffb01bd0b243a9"}, + {file = "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9a309c5de392dfe0f32ee57fa43ed8fc6ddf9985425e84bd51ed66bb16bce3a7"}, + {file = "aiohttp-3.10.11-cp38-cp38-win32.whl", hash = "sha256:9ec1628180241d906a0840b38f162a3215114b14541f1a8711c368a8739a9be4"}, + {file = "aiohttp-3.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:9c6e0ffd52c929f985c7258f83185d17c76d4275ad22e90aa29f38e211aacbec"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdc493a2e5d8dc79b2df5bec9558425bcd39aff59fc949810cbd0832e294b106"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3e70f24e7d0405be2348da9d5a7836936bf3a9b4fd210f8c37e8d48bc32eca6"}, + {file = "aiohttp-3.10.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968b8fb2a5eee2770eda9c7b5581587ef9b96fbdf8dcabc6b446d35ccc69df01"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deef4362af9493d1382ef86732ee2e4cbc0d7c005947bd54ad1a9a16dd59298e"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:686b03196976e327412a1b094f4120778c7c4b9cff9bce8d2fdfeca386b89829"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3bf6d027d9d1d34e1c2e1645f18a6498c98d634f8e373395221121f1c258ace8"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:099fd126bf960f96d34a760e747a629c27fb3634da5d05c7ef4d35ef4ea519fc"}, + {file = "aiohttp-3.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c73c4d3dae0b4644bc21e3de546530531d6cdc88659cdeb6579cd627d3c206aa"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c5580f3c51eea91559db3facd45d72e7ec970b04528b4709b1f9c2555bd6d0b"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fdf6429f0caabfd8a30c4e2eaecb547b3c340e4730ebfe25139779b9815ba138"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d97187de3c276263db3564bb9d9fad9e15b51ea10a371ffa5947a5ba93ad6777"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0acafb350cfb2eba70eb5d271f55e08bd4502ec35e964e18ad3e7d34d71f7261"}, + {file = "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c13ed0c779911c7998a58e7848954bd4d63df3e3575f591e321b19a2aec8df9f"}, + {file = "aiohttp-3.10.11-cp39-cp39-win32.whl", hash = "sha256:22b7c540c55909140f63ab4f54ec2c20d2635c0289cdd8006da46f3327f971b9"}, + {file = "aiohttp-3.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:7b26b1551e481012575dab8e3727b16fe7dd27eb2711d2e63ced7368756268fb"}, + {file = "aiohttp-3.10.11.tar.gz", hash = "sha256:9dc2b8f3dcab2e39e0fa309c8da50c3b55e6f34ab25f1a71d3288f24924d33a7"}, ] [package.dependencies] aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" +yarl = ">=1.12.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] @@ -485,6 +485,113 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + [[package]] name = "pydantic" version = "2.8.2" @@ -683,106 +790,99 @@ files = [ [[package]] name = "yarl" -version = "1.9.4" +version = "1.17.2" description = "Yet another URL library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, + {file = "yarl-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:93771146ef048b34201bfa382c2bf74c524980870bb278e6df515efaf93699ff"}, + {file = "yarl-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8281db240a1616af2f9c5f71d355057e73a1409c4648c8949901396dc0a3c151"}, + {file = "yarl-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:170ed4971bf9058582b01a8338605f4d8c849bd88834061e60e83b52d0c76870"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc61b005f6521fcc00ca0d1243559a5850b9dd1e1fe07b891410ee8fe192d0c0"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:871e1b47eec7b6df76b23c642a81db5dd6536cbef26b7e80e7c56c2fd371382e"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a58a2f2ca7aaf22b265388d40232f453f67a6def7355a840b98c2d547bd037f"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:736bb076f7299c5c55dfef3eb9e96071a795cb08052822c2bb349b06f4cb2e0a"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8fd51299e21da709eabcd5b2dd60e39090804431292daacbee8d3dabe39a6bc0"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:358dc7ddf25e79e1cc8ee16d970c23faee84d532b873519c5036dbb858965795"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:50d866f7b1a3f16f98603e095f24c0eeba25eb508c85a2c5939c8b3870ba2df8"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8b9c4643e7d843a0dca9cd9d610a0876e90a1b2cbc4c5ba7930a0d90baf6903f"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d63123bfd0dce5f91101e77c8a5427c3872501acece8c90df457b486bc1acd47"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4e76381be3d8ff96a4e6c77815653063e87555981329cf8f85e5be5abf449021"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:734144cd2bd633a1516948e477ff6c835041c0536cef1d5b9a823ae29899665b"}, + {file = "yarl-1.17.2-cp310-cp310-win32.whl", hash = "sha256:26bfb6226e0c157af5da16d2d62258f1ac578d2899130a50433ffee4a5dfa673"}, + {file = "yarl-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:76499469dcc24759399accd85ec27f237d52dec300daaca46a5352fcbebb1071"}, + {file = "yarl-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:792155279dc093839e43f85ff7b9b6493a8eaa0af1f94f1f9c6e8f4de8c63500"}, + {file = "yarl-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38bc4ed5cae853409cb193c87c86cd0bc8d3a70fd2268a9807217b9176093ac6"}, + {file = "yarl-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4a8c83f6fcdc327783bdc737e8e45b2e909b7bd108c4da1892d3bc59c04a6d84"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6d5fed96f0646bfdf698b0a1cebf32b8aae6892d1bec0c5d2d6e2df44e1e2d"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:782ca9c58f5c491c7afa55518542b2b005caedaf4685ec814fadfcee51f02493"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff6af03cac0d1a4c3c19e5dcc4c05252411bf44ccaa2485e20d0a7c77892ab6e"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a3f47930fbbed0f6377639503848134c4aa25426b08778d641491131351c2c8"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1fa68a3c921365c5745b4bd3af6221ae1f0ea1bf04b69e94eda60e57958907f"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:187df91395c11e9f9dc69b38d12406df85aa5865f1766a47907b1cc9855b6303"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:93d1c8cc5bf5df401015c5e2a3ce75a5254a9839e5039c881365d2a9dcfc6dc2"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:11d86c6145ac5c706c53d484784cf504d7d10fa407cb73b9d20f09ff986059ef"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c42774d1d1508ec48c3ed29e7b110e33f5e74a20957ea16197dbcce8be6b52ba"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8e589379ef0407b10bed16cc26e7392ef8f86961a706ade0a22309a45414d7"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1056cadd5e850a1c026f28e0704ab0a94daaa8f887ece8dfed30f88befb87bb0"}, + {file = "yarl-1.17.2-cp311-cp311-win32.whl", hash = "sha256:be4c7b1c49d9917c6e95258d3d07f43cfba2c69a6929816e77daf322aaba6628"}, + {file = "yarl-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:ac8eda86cc75859093e9ce390d423aba968f50cf0e481e6c7d7d63f90bae5c9c"}, + {file = "yarl-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dd90238d3a77a0e07d4d6ffdebc0c21a9787c5953a508a2231b5f191455f31e9"}, + {file = "yarl-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c74f0b0472ac40b04e6d28532f55cac8090e34c3e81f118d12843e6df14d0909"}, + {file = "yarl-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d486ddcaca8c68455aa01cf53d28d413fb41a35afc9f6594a730c9779545876"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25b7e93f5414b9a983e1a6c1820142c13e1782cc9ed354c25e933aebe97fcf2"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a0baff7827a632204060f48dca9e63fbd6a5a0b8790c1a2adfb25dc2c9c0d50"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:460024cacfc3246cc4d9f47a7fc860e4fcea7d1dc651e1256510d8c3c9c7cde0"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5870d620b23b956f72bafed6a0ba9a62edb5f2ef78a8849b7615bd9433384171"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2941756754a10e799e5b87e2319bbec481ed0957421fba0e7b9fb1c11e40509f"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9611b83810a74a46be88847e0ea616794c406dbcb4e25405e52bff8f4bee2d0a"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cd7e35818d2328b679a13268d9ea505c85cd773572ebb7a0da7ccbca77b6a52e"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6b981316fcd940f085f646b822c2ff2b8b813cbd61281acad229ea3cbaabeb6b"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:688058e89f512fb7541cb85c2f149c292d3fa22f981d5a5453b40c5da49eb9e8"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56afb44a12b0864d17b597210d63a5b88915d680f6484d8d202ed68ade38673d"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:17931dfbb84ae18b287279c1f92b76a3abcd9a49cd69b92e946035cff06bcd20"}, + {file = "yarl-1.17.2-cp312-cp312-win32.whl", hash = "sha256:ff8d95e06546c3a8c188f68040e9d0360feb67ba8498baf018918f669f7bc39b"}, + {file = "yarl-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:4c840cc11163d3c01a9d8aad227683c48cd3e5be5a785921bcc2a8b4b758c4f3"}, + {file = "yarl-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3294f787a437cb5d81846de3a6697f0c35ecff37a932d73b1fe62490bef69211"}, + {file = "yarl-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f1e7fedb09c059efee2533119666ca7e1a2610072076926fa028c2ba5dfeb78c"}, + {file = "yarl-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:da9d3061e61e5ae3f753654813bc1cd1c70e02fb72cf871bd6daf78443e9e2b1"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91c012dceadc695ccf69301bfdccd1fc4472ad714fe2dd3c5ab4d2046afddf29"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f11fd61d72d93ac23718d393d2a64469af40be2116b24da0a4ca6922df26807e"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46c465ad06971abcf46dd532f77560181387b4eea59084434bdff97524444032"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef6eee1a61638d29cd7c85f7fd3ac7b22b4c0fabc8fd00a712b727a3e73b0685"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4434b739a8a101a837caeaa0137e0e38cb4ea561f39cb8960f3b1e7f4967a3fc"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:752485cbbb50c1e20908450ff4f94217acba9358ebdce0d8106510859d6eb19a"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:17791acaa0c0f89323c57da7b9a79f2174e26d5debbc8c02d84ebd80c2b7bff8"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5c6ea72fe619fee5e6b5d4040a451d45d8175f560b11b3d3e044cd24b2720526"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db5ac3871ed76340210fe028f535392f097fb31b875354bcb69162bba2632ef4"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7a1606ba68e311576bcb1672b2a1543417e7e0aa4c85e9e718ba6466952476c0"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9bc27dd5cfdbe3dc7f381b05e6260ca6da41931a6e582267d5ca540270afeeb2"}, + {file = "yarl-1.17.2-cp313-cp313-win32.whl", hash = "sha256:52492b87d5877ec405542f43cd3da80bdcb2d0c2fbc73236526e5f2c28e6db28"}, + {file = "yarl-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:8e1bf59e035534ba4077f5361d8d5d9194149f9ed4f823d1ee29ef3e8964ace3"}, + {file = "yarl-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c556fbc6820b6e2cda1ca675c5fa5589cf188f8da6b33e9fc05b002e603e44fa"}, + {file = "yarl-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f2f44a4247461965fed18b2573f3a9eb5e2c3cad225201ee858726cde610daca"}, + {file = "yarl-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3a3ede8c248f36b60227eb777eac1dbc2f1022dc4d741b177c4379ca8e75571a"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2654caaf5584449d49c94a6b382b3cb4a246c090e72453493ea168b931206a4d"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d41c684f286ce41fa05ab6af70f32d6da1b6f0457459a56cf9e393c1c0b2217"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2270d590997445a0dc29afa92e5534bfea76ba3aea026289e811bf9ed4b65a7f"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18662443c6c3707e2fc7fad184b4dc32dd428710bbe72e1bce7fe1988d4aa654"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75ac158560dec3ed72f6d604c81090ec44529cfb8169b05ae6fcb3e986b325d9"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1fee66b32e79264f428dc8da18396ad59cc48eef3c9c13844adec890cd339db5"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:585ce7cd97be8f538345de47b279b879e091c8b86d9dbc6d98a96a7ad78876a3"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c019abc2eca67dfa4d8fb72ba924871d764ec3c92b86d5b53b405ad3d6aa56b0"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c6e659b9a24d145e271c2faf3fa6dd1fcb3e5d3f4e17273d9e0350b6ab0fe6e2"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:d17832ba39374134c10e82d137e372b5f7478c4cceeb19d02ae3e3d1daed8721"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bc3003710e335e3f842ae3fd78efa55f11a863a89a72e9a07da214db3bf7e1f8"}, + {file = "yarl-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f5ffc6b7ace5b22d9e73b2a4c7305740a339fbd55301d52735f73e21d9eb3130"}, + {file = "yarl-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:48e424347a45568413deec6f6ee2d720de2cc0385019bedf44cd93e8638aa0ed"}, + {file = "yarl-1.17.2-py3-none-any.whl", hash = "sha256:dd7abf4f717e33b7487121faf23560b3a50924f80e4bef62b22dab441ded8f3b"}, + {file = "yarl-1.17.2.tar.gz", hash = "sha256:753eaaa0c7195244c84b5cc159dc8204b7fd99f716f11198f999f2332a86b178"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [metadata] lock-version = "2.0" From 815a0f3288e807a084fd18b6004a2ca4d8cc0f58 Mon Sep 17 00:00:00 2001 From: ff137 Date: Wed, 6 Nov 2024 20:27:33 +0200 Subject: [PATCH 14/72] :art: Refactor `register_plugin` steps for maintainability Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 144 ++++++++++++++++------------ 1 file changed, 84 insertions(+), 60 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index b3fa709386..43aacdb810 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -117,70 +117,94 @@ def validate_version(self, version_list, module_name): return True - def register_plugin(self, module_name: str) -> ModuleType: + def register_plugin(self, module_name: str) -> Optional[ModuleType]: """Register a plugin module.""" - if module_name in self._plugins: - mod = self._plugins[module_name] - elif module_name in self._blocklist: - LOGGER.debug(f"Blocked {module_name} from loading due to blocklist") + if self._is_already_registered(module_name): + return self._plugins.get(module_name) + + if self._is_blocked(module_name): return None - else: - try: - mod = ClassLoader.load_module(module_name) - LOGGER.debug(f"Loaded module: {module_name}") - except ModuleLoadError as e: - LOGGER.error(f"Error loading plugin module: {e}") - return None - # Module must exist - if not mod: - LOGGER.error(f"Module doesn't exist: {module_name}") - return None - - # Any plugin with a setup method is considered valid. - if hasattr(mod, "setup"): - self._plugins[module_name] = mod - return mod - - # Make an exception for non-protocol modules - # that contain admin routes and for old-style protocol - # modules without version support - routes = ClassLoader.load_module("routes", module_name) - message_types = ClassLoader.load_module("message_types", module_name) - if routes or message_types: - self._plugins[module_name] = mod - return mod - - definition = ClassLoader.load_module("definition", module_name) - - # definition.py must exist in protocol - if not definition: - LOGGER.error(f"Protocol does not include definition.py: {module_name}") - return None - - # definition.py must include versions attribute - if not hasattr(definition, "versions"): - LOGGER.error( - "Protocol definition does not include " - f"versions attribute: {module_name}" - ) - return None + mod = self._load_module(module_name) + if not mod: + return None - # Definition list must not be malformed - try: - self.validate_version(definition.versions, module_name) - except ProtocolDefinitionValidationError as e: - LOGGER.error(f"Protocol versions definition is malformed. {e}") - return None - - self._plugins[module_name] = mod - return mod - - # # Load each version as a separate plugin - # for version in definition.versions: - # mod = ClassLoader.load_module(f"{module_name}.{version['path']}") - # self._plugins[module_name] = mod - # return mod + if self._is_valid_plugin(mod, module_name): + self._plugins[module_name] = mod + LOGGER.debug("Registered plugin: %s", module_name) + return mod + + LOGGER.debug("Failed to register plugin: %s", module_name) + return None + + def _is_already_registered(self, module_name: str) -> bool: + """Check if the plugin is already registered.""" + if module_name in self._plugins: + LOGGER.debug("Plugin %s is already registered.", module_name) + return True + return False + + def _is_blocked(self, module_name: str) -> bool: + """Check if the plugin is in the blocklist.""" + if module_name in self._blocklist: + LOGGER.debug("Blocked %s from loading due to blocklist.", module_name) + return True + return False + + def _load_module(self, module_name: str) -> Optional[ModuleType]: + """Load the plugin module using ClassLoader.""" + try: + mod = ClassLoader.load_module(module_name) + LOGGER.debug("Successfully loaded module: %s", module_name) + return mod + except ModuleLoadError as e: + LOGGER.error("Error loading plugin module '%s': %s", module_name, e) + return None + + def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: + """Validate the plugin based on various criteria.""" + # Check if the plugin has a 'setup' method + if hasattr(mod, "setup"): + LOGGER.debug("Plugin %s has a 'setup' method.", module_name) + return True + + # Check for 'routes' or 'message_types' modules + # This makes an exception for non-protocol modules that contain admin routes + # and for old-style protocol modules without version support + routes = ClassLoader.load_module("routes", module_name) + message_types = ClassLoader.load_module("message_types", module_name) + if routes or message_types: + LOGGER.debug("Plugin %s has 'routes' or 'message_types'.", module_name) + return True + + # Check for 'definition' module with 'versions' attribute + definition = ClassLoader.load_module("definition", module_name) + if not definition: + LOGGER.error( + "Protocol does not include 'definition.py' for module: %s", + module_name, + ) + return False + + if not hasattr(definition, "versions"): + LOGGER.error( + "Protocol definition does not include versions attribute for module: %s", + module_name, + ) + return False + + # Validate the 'versions' attribute + try: + self.validate_version(definition.versions, module_name) + LOGGER.debug("Plugin %s has valid versions.", module_name) + return True + except ProtocolDefinitionValidationError as e: + LOGGER.error( + "Protocol versions definition is malformed for module '%s': %s", + module_name, + e, + ) + return False def register_package(self, package_name: str) -> Sequence[ModuleType]: """Register all modules (sub-packages) under a given package name.""" From ce9f8b766a0ae88162786c259290e6dd688c2354 Mon Sep 17 00:00:00 2001 From: ff137 Date: Wed, 6 Nov 2024 20:36:43 +0200 Subject: [PATCH 15/72] :art: improve logging in register_package Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 43aacdb810..3a97d50ee4 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -208,21 +208,27 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: def register_package(self, package_name: str) -> Sequence[ModuleType]: """Register all modules (sub-packages) under a given package name.""" + LOGGER.debug("Registering package: %s", package_name) try: module_names = ClassLoader.scan_subpackages(package_name) except ModuleLoadError: LOGGER.error("Plugin module package not found: %s", package_name) module_names = [] - return list( - filter( - None, - ( - self.register_plugin(module_name) - for module_name in module_names - if module_name.split(".")[-1] != "tests" - ), - ) - ) + + registered_plugins = [] + for module_name in module_names: + # Skip any module whose last segment is 'tests' + if module_name.split(".")[-1] == "tests": + LOGGER.debug("Skipping test module: %s", module_name) + continue + + plugin = self.register_plugin(module_name) + if plugin: + registered_plugins.append(plugin) + else: + LOGGER.debug("Failed to register %s under %s", module_name, package_name) + + return registered_plugins async def init_context(self, context: InjectionContext): """Call plugin setup methods on the current context.""" From 3e5088e911a748fcffb80db767e46dbe0fb60e67 Mon Sep 17 00:00:00 2001 From: ff137 Date: Wed, 6 Nov 2024 21:07:22 +0200 Subject: [PATCH 16/72] :art: Rename method and remove redundant main call Signed-off-by: ff137 --- acapy_agent/commands/provision.py | 11 +++-------- acapy_agent/commands/tests/test_provision.py | 13 ++++++++----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/acapy_agent/commands/provision.py b/acapy_agent/commands/provision.py index 962b38dc8e..a463dd6e48 100644 --- a/acapy_agent/commands/provision.py +++ b/acapy_agent/commands/provision.py @@ -67,7 +67,7 @@ async def provision(settings: dict): raise ProvisionError("Error during provisioning") from e -def execute(argv: Sequence[str] = None): +def execute_provision(argv: Sequence[str] = None): """Entrypoint.""" parser = arg.create_argument_parser(prog=PROG) parser.prog += " provision" @@ -84,10 +84,5 @@ def execute(argv: Sequence[str] = None): loop.run_until_complete(provision(settings)) -def main(): - """Execute the main line.""" - if __name__ == "__main__": - execute() - - -main() +if __name__ == "__main__": + execute_provision() diff --git a/acapy_agent/commands/tests/test_provision.py b/acapy_agent/commands/tests/test_provision.py index 65d0d488bd..3fbeb00208 100644 --- a/acapy_agent/commands/tests/test_provision.py +++ b/acapy_agent/commands/tests/test_provision.py @@ -14,10 +14,10 @@ class TestProvision(IsolatedAsyncioTestCase): def test_bad_calls(self): with self.assertRaises(ArgsParseError): - test_module.execute([]) + test_module.execute_provision([]) with self.assertRaises(SystemExit): - test_module.execute(["bad"]) + test_module.execute_provision(["bad"]) async def test_provision_ledger_configured(self): profile = mock.MagicMock(close=mock.CoroutineMock()) @@ -43,11 +43,14 @@ async def test_provision_config_x(self): with self.assertRaises(test_module.ProvisionError): await test_module.provision({}) - def test_main(self): + def test_main_entry_point(self): + """Test that the execute_provision function is called when the module is run as main.""" with mock.patch.object(test_module, "__name__", "__main__"), mock.patch.object( - test_module, "execute", mock.MagicMock() + test_module, "execute_provision", mock.MagicMock() ) as mock_execute: - test_module.main() + import importlib + + importlib.reload(test_module) # Reload the module to trigger the main guard mock_execute.assert_called_once async def test_provision_should_store_provided_mediation_invite(self): From 59e49518ecf144318d2db8fd9f9f1502a6e70ef2 Mon Sep 17 00:00:00 2001 From: ff137 Date: Wed, 6 Nov 2024 21:08:48 +0200 Subject: [PATCH 17/72] :art: Signed-off-by: ff137 --- acapy_agent/config/argparse.py | 2 +- acapy_agent/config/default_context.py | 12 +++++------ acapy_agent/core/plugin_registry.py | 30 +++++++++++++-------------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/acapy_agent/config/argparse.py b/acapy_agent/config/argparse.py index ec0d3d95e1..222c7c2461 100644 --- a/acapy_agent/config/argparse.py +++ b/acapy_agent/config/argparse.py @@ -63,7 +63,7 @@ def get_registered(cls, category: Optional[str] = None): def create_argument_parser(*, prog: Optional[str] = None): - """Create am instance of an arg parser, force yaml format for external config.""" + """Create an instance of an arg parser, force yaml format for external config.""" return ArgumentParser(config_file_parser_class=YAMLConfigFileParser, prog=prog) diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index 136c79791d..d3c345136d 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -132,9 +132,7 @@ async def load_plugins(self, context: InjectionContext): # Currently providing admin routes only plugin_registry.register_plugin("acapy_agent.holder") - plugin_registry.register_plugin("acapy_agent.ledger") - plugin_registry.register_plugin("acapy_agent.messaging.jsonld") plugin_registry.register_plugin("acapy_agent.resolver") plugin_registry.register_plugin("acapy_agent.settings") @@ -165,15 +163,15 @@ def register_anoncreds_plugins(): for plugin in anoncreds_plugins: plugin_registry.register_plugin(plugin) - if wallet_type == "askar-anoncreds": - register_anoncreds_plugins() - else: - register_askar_plugins() - if context.settings.get("multitenant.admin_enabled"): plugin_registry.register_plugin("acapy_agent.multitenant.admin") register_askar_plugins() register_anoncreds_plugins() + else: + if wallet_type == "askar-anoncreds": + register_anoncreds_plugins() + else: + register_askar_plugins() # Register external plugins for plugin_path in self.settings.get("external_plugins", []): diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 3a97d50ee4..61ea440f74 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -3,7 +3,7 @@ import logging from collections import OrderedDict from types import ModuleType -from typing import Iterable, Optional, Sequence +from typing import Optional, Sequence, Set from ..config.injection_context import InjectionContext from ..core.event_bus import EventBus @@ -18,10 +18,10 @@ class PluginRegistry: """Plugin registry for indexing application plugins.""" - def __init__(self, blocklist: Iterable[str] = []): + def __init__(self, blocklist: Optional[Set[str]] = None): """Initialize a `PluginRegistry` instance.""" - self._plugins = OrderedDict() - self._blocklist = set(blocklist) + self._plugins: OrderedDict[str, ModuleType] = OrderedDict() + self._blocklist: Set[str] = set(blocklist) if blocklist else set() @property def plugin_names(self) -> Sequence[str]: @@ -57,7 +57,6 @@ def validate_version(self, version_list, module_name): for version_dict in version_list: # Dicts must have correct format - try: if not ( isinstance(version_dict["major_version"], int) @@ -89,8 +88,8 @@ def validate_version(self, version_list, module_name): > version_dict["current_minor_version"] ): raise ProtocolDefinitionValidationError( - "Minimum supported minor version cannot" - + " be greater than current minor version" + "Minimum supported minor version cannot " + "be greater than current minor version" ) # There can only be one definition per major version @@ -102,7 +101,7 @@ def validate_version(self, version_list, module_name): if count > 1: raise ProtocolDefinitionValidationError( "There can only be one definition per major version. " - + f"Found {count} for major version {major_version}." + f"Found {count} for major version {major_version}." ) # Specified module must be loadable @@ -111,8 +110,7 @@ def validate_version(self, version_list, module_name): if not mod: raise ProtocolDefinitionValidationError( - "Version module path is not " - + f"loadable: {module_name}, {version_path}" + f"Version module path is not loadable: {module_name}, {version_path}" ) return True @@ -230,7 +228,7 @@ def register_package(self, package_name: str) -> Sequence[ModuleType]: return registered_plugins - async def init_context(self, context: InjectionContext): + async def init_context(self, context: InjectionContext) -> None: """Call plugin setup methods on the current context.""" for plugin in self._plugins.values(): if hasattr(plugin, "setup"): @@ -246,7 +244,7 @@ async def load_protocol_version( context: InjectionContext, mod: ModuleType, version_definition: Optional[dict] = None, - ): + ) -> None: """Load a particular protocol version.""" protocol_registry = context.inject(ProtocolRegistry) goal_code_registry = context.inject(GoalCodeRegistry) @@ -258,7 +256,7 @@ async def load_protocol_version( protocol_registry.register_controllers(mod.CONTROLLERS) goal_code_registry.register_controllers(mod.CONTROLLERS) - async def load_protocols(self, context: InjectionContext, plugin: ModuleType): + async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> None: """For modules that don't implement setup, register protocols manually.""" # If this module contains message_types, then assume that @@ -293,7 +291,7 @@ async def load_protocols(self, context: InjectionContext, plugin: ModuleType): LOGGER.error("Error loading plugin module message types: %s", e) return - async def register_admin_routes(self, app): + async def register_admin_routes(self, app) -> None: """Call route registration methods on the current context.""" for plugin in self._plugins.values(): definition = ClassLoader.load_module("definition", plugin.__name__) @@ -319,7 +317,7 @@ async def register_admin_routes(self, app): if mod and hasattr(mod, "register"): await mod.register(app) - def register_protocol_events(self, context: InjectionContext): + def register_protocol_events(self, context: InjectionContext) -> None: """Call route register_events methods on the current context.""" event_bus = context.inject_or(EventBus) if not event_bus: @@ -349,7 +347,7 @@ def register_protocol_events(self, context: InjectionContext): if mod and hasattr(mod, "register_events"): mod.register_events(event_bus) - def post_process_routes(self, app): + def post_process_routes(self, app) -> None: """Call route binary file response OpenAPI fixups if applicable.""" for plugin in self._plugins.values(): definition = ClassLoader.load_module("definition", plugin.__name__) From 02011a83486c06a0706ab8215640885efcc10f22 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 11:42:14 +0200 Subject: [PATCH 18/72] :loud_sound: Add debug logging to Context Builder Signed-off-by: ff137 --- acapy_agent/config/default_context.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index d3c345136d..1f049f8ece 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -1,5 +1,7 @@ """Classes for configuring the default injection context.""" +import logging + from ..anoncreds.registry import AnonCredsRegistry from ..cache.base import BaseCache from ..cache.in_memory import InMemoryCache @@ -26,17 +28,22 @@ from .injection_context import InjectionContext from .provider import CachedProvider, ClassProvider +LOGGER = logging.getLogger(__name__) + class DefaultContextBuilder(ContextBuilder): """Default context builder.""" async def build_context(self) -> InjectionContext: """Build the base injection context; set DIDComm prefix to emit.""" + LOGGER.debug("Building new injection context with settings: %s", self.settings) + context = InjectionContext(settings=self.settings) context.settings.set_default("default_label", "Aries Cloud Agent") if context.settings.get("timing.enabled"): timing_log = context.settings.get("timing.log_file") + LOGGER.debug("Enabling timing collector with log file: %s", timing_log) collector = Collector(log_path=timing_log) context.injector.bind_instance(Collector, collector) @@ -63,11 +70,8 @@ async def build_context(self) -> InjectionContext: # DIDComm Messaging if context.settings.get("experiment.didcomm_v2"): - from didcomm_messaging import ( - CryptoService, - PackagingService, - RoutingService, - ) + LOGGER.info("DIDComm v2 experimental mode enabled") + from didcomm_messaging import CryptoService, PackagingService, RoutingService from didcomm_messaging.crypto.backend.askar import AskarCryptoService context.injector.bind_instance(CryptoService, AskarCryptoService()) @@ -81,11 +85,13 @@ async def build_context(self) -> InjectionContext: async def bind_providers(self, context: InjectionContext): """Bind various class providers.""" + LOGGER.debug("Begin binding providers to context") context.injector.bind_provider(ProfileManager, ProfileManagerProvider()) wallet_type = self.settings.get("wallet.type") if wallet_type == "askar-anoncreds": + LOGGER.debug("Using AnonCreds tails server") context.injector.bind_provider( BaseTailsServer, ClassProvider( @@ -93,6 +99,7 @@ async def bind_providers(self, context: InjectionContext): ), ) else: + LOGGER.debug("Using Indy tails server") context.injector.bind_provider( BaseTailsServer, ClassProvider( @@ -120,6 +127,7 @@ async def bind_providers(self, context: InjectionContext): async def load_plugins(self, context: InjectionContext): """Set up plugin registry and load plugins.""" + LOGGER.debug("Initializing plugin registry") plugin_registry = PluginRegistry( blocklist=self.settings.get("blocked_plugins", []) ) @@ -164,6 +172,7 @@ def register_anoncreds_plugins(): plugin_registry.register_plugin(plugin) if context.settings.get("multitenant.admin_enabled"): + LOGGER.debug("Multitenant admin enabled - registering additional plugins") plugin_registry.register_plugin("acapy_agent.multitenant.admin") register_askar_plugins() register_anoncreds_plugins() @@ -175,6 +184,7 @@ def register_anoncreds_plugins(): # Register external plugins for plugin_path in self.settings.get("external_plugins", []): + LOGGER.debug("Registering external plugin: %s", plugin_path) plugin_registry.register_plugin(plugin_path) # Register message protocols From 12631918269608b77d00229f73de4d2e60df4cb6 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 11:42:34 +0200 Subject: [PATCH 19/72] :art: Deduplicate registering list of plugins Signed-off-by: ff137 --- acapy_agent/config/default_context.py | 36 ++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index 1f049f8ece..8f2978b4fc 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -138,16 +138,18 @@ async def load_plugins(self, context: InjectionContext): if not self.settings.get("transport.disabled"): plugin_registry.register_package("acapy_agent.protocols") - # Currently providing admin routes only - plugin_registry.register_plugin("acapy_agent.holder") - plugin_registry.register_plugin("acapy_agent.ledger") - plugin_registry.register_plugin("acapy_agent.messaging.jsonld") - plugin_registry.register_plugin("acapy_agent.resolver") - plugin_registry.register_plugin("acapy_agent.settings") - plugin_registry.register_plugin("acapy_agent.vc") - plugin_registry.register_plugin("acapy_agent.vc.data_integrity") - plugin_registry.register_plugin("acapy_agent.wallet") - plugin_registry.register_plugin("acapy_agent.wallet.keys") + # Define plugin groups + default_plugins = [ + "acapy_agent.holder", + "acapy_agent.ledger", + "acapy_agent.messaging.jsonld", + "acapy_agent.resolver", + "acapy_agent.settings", + "acapy_agent.vc", + "acapy_agent.vc.data_integrity", + "acapy_agent.wallet", + "acapy_agent.wallet.keys", + ] anoncreds_plugins = [ "acapy_agent.anoncreds", @@ -163,13 +165,19 @@ async def load_plugins(self, context: InjectionContext): "acapy_agent.revocation", ] - def register_askar_plugins(): - for plugin in askar_plugins: + def register_plugins(plugins: list[str], plugin_type: str): + """Register a group of plugins with logging.""" + LOGGER.debug("Registering %s plugins", plugin_type) + for plugin in plugins: plugin_registry.register_plugin(plugin) + def register_askar_plugins(): + register_plugins(askar_plugins, "askar") + def register_anoncreds_plugins(): - for plugin in anoncreds_plugins: - plugin_registry.register_plugin(plugin) + register_plugins(anoncreds_plugins, "anoncreds") + + register_plugins(default_plugins, "default") if context.settings.get("multitenant.admin_enabled"): LOGGER.debug("Multitenant admin enabled - registering additional plugins") From 24c14269b6a2d98a934e6afb1cd00367ce122df9 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 11:45:36 +0200 Subject: [PATCH 20/72] :art: Signed-off-by: ff137 --- acapy_agent/config/default_context.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index 8f2978b4fc..ed49ff175d 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -111,12 +111,7 @@ async def bind_providers(self, context: InjectionContext): context.injector.bind_provider( BaseWireFormat, CachedProvider( - # StatsProvider( ClassProvider("acapy_agent.transport.pack_format.PackWireFormat"), - # ( - # "encode_message", "parse_message" - # ), - # ) ), ) From 826468878e7a65f915b7ec542134dac0a9cbe55f Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 12:23:58 +0200 Subject: [PATCH 21/72] :loud_sound: Add debug logging to init_context Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 61ea440f74..be58ba0661 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -230,10 +230,17 @@ def register_package(self, package_name: str) -> Sequence[ModuleType]: async def init_context(self, context: InjectionContext) -> None: """Call plugin setup methods on the current context.""" + LOGGER.debug("Initializing plugin context for %d plugins", len(self._plugins)) + for plugin in self._plugins.values(): + plugin_name = plugin.__name__ if hasattr(plugin, "setup"): + LOGGER.debug("Running setup for plugin: %s", plugin_name) await plugin.setup(context) else: + LOGGER.debug( + "Loading protocols for plugin without setup: %s", plugin_name + ) await self.load_protocols(context, plugin) # register event handlers for each protocol, if provided From b539ab0a130147399edb3a8e0c67ce16cd1d16fc Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 12:24:10 +0200 Subject: [PATCH 22/72] :loud_sound: Add debug logging to load_protocol_version Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index be58ba0661..1ad320e2d4 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -255,11 +255,18 @@ async def load_protocol_version( """Load a particular protocol version.""" protocol_registry = context.inject(ProtocolRegistry) goal_code_registry = context.inject(GoalCodeRegistry) + + module_name = mod.__name__ + LOGGER.debug("Loading protocol version for module: %s", module_name) + if hasattr(mod, "MESSAGE_TYPES"): + LOGGER.debug("Registering message types for: %s", module_name) protocol_registry.register_message_types( mod.MESSAGE_TYPES, version_definition=version_definition ) + if hasattr(mod, "CONTROLLERS"): + LOGGER.debug("Registering controllers for: %s", module_name) protocol_registry.register_controllers(mod.CONTROLLERS) goal_code_registry.register_controllers(mod.CONTROLLERS) From 595d391cc3da3349bcae21b5a19f2890f134858b Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 12:25:30 +0200 Subject: [PATCH 23/72] :loud_sound: Add debug logging to load_protocols Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 31 +++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 1ad320e2d4..d21eebeb66 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -272,37 +272,48 @@ async def load_protocol_version( async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> None: """For modules that don't implement setup, register protocols manually.""" + plugin_name = plugin.__name__ + LOGGER.debug("Loading protocols for plugin: %s", plugin_name) # If this module contains message_types, then assume that # this is a valid module of the old style (not versioned) try: - mod = ClassLoader.load_module(plugin.__name__ + ".message_types") + message_types_path = f"{plugin_name}.message_types" + LOGGER.debug("Attempting to load message types from: %s", message_types_path) + mod = ClassLoader.load_module(message_types_path) except ModuleLoadError as e: LOGGER.error("Error loading plugin module message types: %s", e) return if mod: + LOGGER.debug("Found non-versioned message types for: %s", plugin_name) await self.load_protocol_version(context, mod) else: - # Otherwise, try check for definition.py for versioned - # protocol packages + # Otherwise, try check for definition.py for versioned protocol packages try: - definition = ClassLoader.load_module(plugin.__name__ + ".definition") + definition_path = f"{plugin_name}.definition" + LOGGER.debug("Attempting to load definition from: %s", definition_path) + definition = ClassLoader.load_module(definition_path) except ModuleLoadError as e: LOGGER.error("Error loading plugin definition module: %s", e) return if definition: + LOGGER.debug("Loading versioned protocols for: %s", plugin_name) for protocol_version in definition.versions: + version_path = ( + f"{plugin_name}.{protocol_version['path']}.message_types" + ) try: - mod = ClassLoader.load_module( - f"{plugin.__name__}.{protocol_version['path']}" - + ".message_types" - ) + LOGGER.debug("Loading message types from: %s", version_path) + mod = ClassLoader.load_module(version_path) await self.load_protocol_version(context, mod, protocol_version) - except ModuleLoadError as e: - LOGGER.error("Error loading plugin module message types: %s", e) + LOGGER.error( + "Error loading plugin module message types from %s: %s", + version_path, + e, + ) return async def register_admin_routes(self, app) -> None: From b1a73a03df21aebbcb67be225e9a88e49900109f Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 12:25:52 +0200 Subject: [PATCH 24/72] :loud_sound: Add debug logging to register_admin_routes Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 32 +++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index d21eebeb66..909bac2436 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -318,29 +318,39 @@ async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> async def register_admin_routes(self, app) -> None: """Call route registration methods on the current context.""" + LOGGER.debug("Registering admin routes for %d plugins", len(self._plugins)) + for plugin in self._plugins.values(): - definition = ClassLoader.load_module("definition", plugin.__name__) + plugin_name = plugin.__name__ + LOGGER.debug("Processing routes for plugin: %s", plugin_name) + mod = None + definition = ClassLoader.load_module("definition", plugin_name) if definition: # Load plugin routes that are in a versioned package. + LOGGER.debug("Loading versioned routes for: %s", plugin_name) for plugin_version in definition.versions: + version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - mod = ClassLoader.load_module( - f"{plugin.__name__}.{plugin_version['path']}.routes" - ) + LOGGER.debug("Loading routes from: %s", version_path) + mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error( + "Error loading admin routes from %s: %s", version_path, e + ) continue - if mod and hasattr(mod, "register"): - await mod.register(app) else: # Load plugin routes that aren't in a versioned package. + routes_path = f"{plugin_name}.routes" try: - mod = ClassLoader.load_module(f"{plugin.__name__}.routes") + LOGGER.debug("Loading non-versioned routes from: %s", routes_path) + mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading admin routes from %s: %s", routes_path, e) continue - if mod and hasattr(mod, "register"): - await mod.register(app) + + if mod and hasattr(mod, "register"): + LOGGER.debug("Registering routes from: %s", version_path) + await mod.register(app) def register_protocol_events(self, context: InjectionContext) -> None: """Call route register_events methods on the current context.""" From 5e199d19df420c2592785983aeaee7cf23078f63 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 12:26:17 +0200 Subject: [PATCH 25/72] :loud_sound: Add debug logging to register_protocol_events Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 31 +++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 909bac2436..302a409062 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -354,33 +354,42 @@ async def register_admin_routes(self, app) -> None: def register_protocol_events(self, context: InjectionContext) -> None: """Call route register_events methods on the current context.""" + LOGGER.debug("Registering protocol events for %d plugins", len(self._plugins)) + event_bus = context.inject_or(EventBus) if not event_bus: LOGGER.error("No event bus in context") return + for plugin in self._plugins.values(): - definition = ClassLoader.load_module("definition", plugin.__name__) + plugin_name = plugin.__name__ + LOGGER.debug("Processing events for plugin: %s", plugin_name) + mod = None + definition = ClassLoader.load_module("definition", plugin_name) if definition: # Load plugin routes that are in a versioned package. + LOGGER.debug("Loading versioned events for: %s", plugin_name) for plugin_version in definition.versions: + version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - mod = ClassLoader.load_module( - f"{plugin.__name__}.{plugin_version['path']}.routes" - ) + LOGGER.debug("Loading events from: %s", version_path) + mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading events from %s: %s", version_path, e) continue - if mod and hasattr(mod, "register_events"): - mod.register_events(event_bus) else: # Load plugin routes that aren't in a versioned package. + routes_path = f"{plugin_name}.routes" try: - mod = ClassLoader.load_module(f"{plugin.__name__}.routes") + LOGGER.debug("Loading non-versioned events from: %s", routes_path) + mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading events from %s: %s", routes_path, e) continue - if mod and hasattr(mod, "register_events"): - mod.register_events(event_bus) + + if mod and hasattr(mod, "register_events"): + LOGGER.debug("Registering events from: %s", version_path) + mod.register_events(event_bus) def post_process_routes(self, app) -> None: """Call route binary file response OpenAPI fixups if applicable.""" From 9cf03f6bb4a088c9de66b8ede70d42804626e70f Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 12:26:40 +0200 Subject: [PATCH 26/72] :loud_sound: Add debug logging to post_process_routes Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 30 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 302a409062..b4094e4e19 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -393,29 +393,37 @@ def register_protocol_events(self, context: InjectionContext) -> None: def post_process_routes(self, app) -> None: """Call route binary file response OpenAPI fixups if applicable.""" + LOGGER.debug("Post-processing routes for %d plugins", len(self._plugins)) + for plugin in self._plugins.values(): - definition = ClassLoader.load_module("definition", plugin.__name__) + plugin_name = plugin.__name__ + LOGGER.debug("Post-processing routes for plugin: %s", plugin_name) + mod = None + definition = ClassLoader.load_module("definition", plugin_name) if definition: # Set binary file responses for routes that are in a versioned package. + LOGGER.debug("Processing versioned routes for: %s", plugin_name) for plugin_version in definition.versions: + version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - mod = ClassLoader.load_module( - f"{plugin.__name__}.{plugin_version['path']}.routes" - ) + LOGGER.debug("Loading routes from: %s", version_path) + mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading routes from %s: %s", version_path, e) continue - if mod and hasattr(mod, "post_process_routes"): - mod.post_process_routes(app) else: # Set binary file responses for routes not in a versioned package. + routes_path = f"{plugin_name}.routes" try: - mod = ClassLoader.load_module(f"{plugin.__name__}.routes") + LOGGER.debug("Loading non-versioned routes from: %s", routes_path) + mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: - LOGGER.error("Error loading admin routes: %s", e) + LOGGER.error("Error loading routes from %s: %s", routes_path, e) continue - if mod and hasattr(mod, "post_process_routes"): - mod.post_process_routes(app) + + if mod and hasattr(mod, "post_process_routes"): + LOGGER.debug("Post-processing routes from: %s", version_path) + mod.post_process_routes(app) def __repr__(self) -> str: """Return a string representation for this class.""" From 6330701c912ac0c8e510dce329a6afe0d709b82e Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 12:38:00 +0200 Subject: [PATCH 27/72] :art: Replace print statements with info logs Signed-off-by: ff137 --- acapy_agent/core/conductor.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index d9db66ad7a..36bb6017ba 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -401,18 +401,19 @@ async def start(self) -> None: their_endpoint=their_endpoint, alias="test-suite", ) - print("Created static connection for test suite") - print(" - My DID:", test_conn.my_did) - print(" - Their DID:", test_conn.their_did) - print(" - Their endpoint:", their_endpoint) - print() + LOGGER.info( + "Created static connection for test suite\n" + f" - My DID: {test_conn.my_did}\n" + f" - Their DID: {test_conn.their_did}\n" + f" - Their endpoint: {their_endpoint}\n" + ) del mgr # Clear default mediator if context.settings.get("mediation.clear"): mediation_mgr = MediationManager(self.root_profile) await mediation_mgr.clear_default_mediator() - print("Default mediator cleared.") + LOGGER.info("Default mediator cleared.") # Clear default mediator # Set default mediator by id @@ -421,7 +422,7 @@ async def start(self) -> None: mediation_mgr = MediationManager(self.root_profile) try: await mediation_mgr.set_default_mediator_by_id(default_mediator_id) - print(f"Default mediator set to {default_mediator_id}") + LOGGER.info(f"Default mediator set to {default_mediator_id}") except Exception: LOGGER.exception("Error updating default mediator") @@ -440,8 +441,7 @@ async def start(self) -> None: ) base_url = context.settings.get("invite_base_url") invite_url = invi_rec.invitation.to_url(base_url) - print("Invitation URL:") - print(invite_url, flush=True) + LOGGER.info(f"Invitation URL:\n{invite_url}") qr = QRCode(border=1) qr.add_data(invite_url) qr.print_ascii(invert=True) @@ -463,8 +463,7 @@ async def start(self) -> None: ) base_url = context.settings.get("invite_base_url") invite_url = invite.to_url(base_url) - print("Invitation URL (Connections protocol):") - print(invite_url, flush=True) + LOGGER.info(f"Invitation URL (Connections protocol):\n{invite_url}") qr = QRCode(border=1) qr.add_data(invite_url) qr.print_ascii(invert=True) @@ -525,7 +524,7 @@ async def start(self) -> None: session, MediationManager.SET_TO_DEFAULT_ON_GRANTED, True ) - print("Attempting to connect to mediator...") + LOGGER.info("Attempting to connect to mediator...") del mgr except Exception: LOGGER.exception("Error accepting mediation invitation") From 6a8febdf6f731a008bbf6dfd2077ad1fd5df443e Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 12:58:06 +0200 Subject: [PATCH 28/72] :art: Replace almost all print statements with info logs Signed-off-by: ff137 --- acapy_agent/__main__.py | 13 +++++++---- .../anoncreds/default/did_indy/registry.py | 2 +- .../anoncreds/default/did_web/registry.py | 5 ++++- .../anoncreds/default/legacy_indy/registry.py | 2 +- acapy_agent/commands/provision.py | 7 ++++-- acapy_agent/commands/start.py | 4 ++-- acapy_agent/config/wallet.py | 22 +++++++++---------- acapy_agent/transport/v2_pack_format.py | 3 +-- acapy_agent/vc/vc_di/prove.py | 5 ++++- acapy_agent/wallet/crypto.py | 5 ++++- 10 files changed, 42 insertions(+), 26 deletions(-) diff --git a/acapy_agent/__main__.py b/acapy_agent/__main__.py index bd0c964705..9669588b83 100644 --- a/acapy_agent/__main__.py +++ b/acapy_agent/__main__.py @@ -1,8 +1,11 @@ """acapy_agent package entry point.""" +import logging import os import sys +LOGGER = logging.getLogger(__name__) + def init_debug(args): """Initialize debugging environment.""" @@ -26,16 +29,18 @@ def init_debug(args): import debugpy debugpy.listen((DAP_HOST, DAP_PORT)) - print(f"=== Waiting for debugger to attach to {DAP_HOST}:{DAP_PORT} ===") + LOGGER.info( + f"=== Waiting for debugger to attach to {DAP_HOST}:{DAP_PORT} ===" + ) debugpy.wait_for_client() except ImportError: - print("debugpy library was not found") + LOGGER.error("debugpy library was not found") if ENABLE_PYDEVD_PYCHARM or "--debug-pycharm" in args: try: import pydevd_pycharm - print( + LOGGER.info( "aca-py remote debugging to " f"{PYDEVD_PYCHARM_HOST}:{PYDEVD_PYCHARM_AGENT_PORT}" ) @@ -47,7 +52,7 @@ def init_debug(args): suspend=False, ) except ImportError: - print("pydevd_pycharm library was not found") + LOGGER.error("pydevd_pycharm library was not found") def run(args): diff --git a/acapy_agent/anoncreds/default/did_indy/registry.py b/acapy_agent/anoncreds/default/did_indy/registry.py index 567d90ccce..5bef819f82 100644 --- a/acapy_agent/anoncreds/default/did_indy/registry.py +++ b/acapy_agent/anoncreds/default/did_indy/registry.py @@ -41,7 +41,7 @@ def supported_identifiers_regex(self) -> Pattern: async def setup(self, context: InjectionContext): """Setup.""" - print("Successfully registered DIDIndyRegistry") + LOGGER.info("Successfully registered DIDIndyRegistry") async def get_schema(self, profile: Profile, schema_id: str) -> GetSchemaResult: """Get a schema from the registry.""" diff --git a/acapy_agent/anoncreds/default/did_web/registry.py b/acapy_agent/anoncreds/default/did_web/registry.py index 63382f3606..0585e2b924 100644 --- a/acapy_agent/anoncreds/default/did_web/registry.py +++ b/acapy_agent/anoncreds/default/did_web/registry.py @@ -1,5 +1,6 @@ """DID Web Registry.""" +import logging import re from typing import Optional, Pattern, Sequence @@ -17,6 +18,8 @@ ) from ...models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult +LOGGER = logging.getLogger(__name__) + class DIDWebRegistry(BaseAnonCredsResolver, BaseAnonCredsRegistrar): """DIDWebRegistry.""" @@ -40,7 +43,7 @@ def supported_identifiers_regex(self) -> Pattern: async def setup(self, context: InjectionContext): """Setup.""" - print("Successfully registered DIDWebRegistry") + LOGGER.info("Successfully registered DIDWebRegistry") async def get_schema(self, profile, schema_id: str) -> GetSchemaResult: """Get a schema from the registry.""" diff --git a/acapy_agent/anoncreds/default/legacy_indy/registry.py b/acapy_agent/anoncreds/default/legacy_indy/registry.py index e173bbde32..892a9d17fe 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/registry.py +++ b/acapy_agent/anoncreds/default/legacy_indy/registry.py @@ -144,7 +144,7 @@ def supported_identifiers_regex(self) -> Pattern: async def setup(self, context: InjectionContext): """Setup.""" - print("Successfully registered LegacyIndyRegistry") + LOGGER.info("Successfully registered LegacyIndyRegistry") @staticmethod def make_schema_id(schema: AnonCredsSchema) -> str: diff --git a/acapy_agent/commands/provision.py b/acapy_agent/commands/provision.py index a463dd6e48..6d86d412b6 100644 --- a/acapy_agent/commands/provision.py +++ b/acapy_agent/commands/provision.py @@ -1,6 +1,7 @@ """Provision command for setting up agent settings before starting.""" import asyncio +import logging from typing import Sequence from configargparse import ArgumentParser @@ -22,6 +23,8 @@ from ..storage.base import BaseStorage from . import PROG +LOGGER = logging.getLogger(__name__) + class ProvisionError(BaseError): """Base exception for provisioning errors.""" @@ -58,9 +61,9 @@ async def provision(settings: dict): ) if await ledger_config(root_profile, public_did and public_did.did, True): - print("Ledger configured") + LOGGER.info("Ledger configured") else: - print("Ledger not configured") + LOGGER.warning("Ledger not configured") await root_profile.close() except BaseError as e: diff --git a/acapy_agent/commands/start.py b/acapy_agent/commands/start.py index f30fc5c582..ee256f1e4c 100644 --- a/acapy_agent/commands/start.py +++ b/acapy_agent/commands/start.py @@ -31,7 +31,7 @@ async def start_app(conductor: Conductor): async def shutdown_app(conductor: Conductor): """Shut down.""" - print("\nShutting down") + LOGGER.warning("Shutting down") await conductor.stop() @@ -59,7 +59,7 @@ def execute(argv: Sequence[str] = None): # Run the application if uvloop: uvloop.install() - print("uvloop installed") + LOGGER.info("uvloop installed") run_loop(start_app(conductor), shutdown_app(conductor)) diff --git a/acapy_agent/config/wallet.py b/acapy_agent/config/wallet.py index f857b07847..89bfdad681 100644 --- a/acapy_agent/config/wallet.py +++ b/acapy_agent/config/wallet.py @@ -61,11 +61,11 @@ async def wallet_config( if provision: if profile.created: - print("Created new profile") + LOGGER.info("Created new profile") else: - print("Opened existing profile") - print("Profile backend:", profile.backend) - print("Profile name:", profile.name) + LOGGER.info("Opened existing profile") + LOGGER.info("Profile backend:", profile.backend) + LOGGER.info("Profile name:", profile.name) wallet_seed = context.settings.get("wallet.seed") wallet_local_did = context.settings.get("wallet.local_did") @@ -84,8 +84,8 @@ async def wallet_config( ) public_did = replace_did_info.did await wallet.set_public_did(public_did) - print(f"Created new public DID: {public_did}") - print(f"Verkey: {replace_did_info.verkey}") + LOGGER.info(f"Created new public DID: {public_did}") + LOGGER.info(f"Verkey: {replace_did_info.verkey}") else: # If we already have a registered public did and it doesn't match # the one derived from `wallet_seed` then we error out. @@ -107,20 +107,20 @@ async def wallet_config( ) local_did = local_did_info.did if provision: - print(f"Created new local DID: {local_did}") - print(f"Verkey: {local_did_info.verkey}") + LOGGER.info(f"Created new local DID: {local_did}") + LOGGER.info(f"Verkey: {local_did_info.verkey}") else: public_did_info = await wallet.create_public_did( method=SOV, key_type=ED25519, seed=wallet_seed ) public_did = public_did_info.did if provision: - print(f"Created new public DID: {public_did}") - print(f"Verkey: {public_did_info.verkey}") + LOGGER.info(f"Created new public DID: {public_did}") + LOGGER.info(f"Verkey: {public_did_info.verkey}") # wait until ledger config to set public DID endpoint - wallet goes first if provision and not wallet_local_did and not public_did: - print("No public DID") + LOGGER.info("No public DID") # Debug settings test_seed = context.settings.get("debug.seed") diff --git a/acapy_agent/transport/v2_pack_format.py b/acapy_agent/transport/v2_pack_format.py index 266c0b8b08..92e26da698 100644 --- a/acapy_agent/transport/v2_pack_format.py +++ b/acapy_agent/transport/v2_pack_format.py @@ -63,8 +63,7 @@ async def parse_message( try: message_unpack = await messaging.unpack(message_json) except CryptoServiceError: - LOGGER.debug("Message unpack failed, falling back to JSON") - print("HIT CRTYPTO SER ERR EXCEPT BLOC") + LOGGER.info("Message unpack failed, falling back to JSON") else: # Set message_dict to be the dictionary that we unpacked message_dict = message_unpack.message diff --git a/acapy_agent/vc/vc_di/prove.py b/acapy_agent/vc/vc_di/prove.py index 33c94fa544..acba4359fe 100644 --- a/acapy_agent/vc/vc_di/prove.py +++ b/acapy_agent/vc/vc_di/prove.py @@ -1,6 +1,7 @@ """Verifiable Credential and Presentation proving methods.""" import asyncio +import logging import re from hashlib import sha256 from typing import Any, Optional, Tuple @@ -20,6 +21,8 @@ from ...core.profile import Profile from ..ld_proofs import LinkedDataProofException, ProofPurpose +LOGGER = logging.getLogger(__name__) + async def create_signed_anoncreds_presentation( *, @@ -311,7 +314,7 @@ async def prepare_data_for_presentation( # issuer_id = field["filter"]["const"] pass else: - print("... skipping:", path) + LOGGER.info("... skipping: %s", path) return anoncreds_proofrequest, w3c_creds_metadata diff --git a/acapy_agent/wallet/crypto.py b/acapy_agent/wallet/crypto.py index 0ceef63a91..37ddeb7a13 100644 --- a/acapy_agent/wallet/crypto.py +++ b/acapy_agent/wallet/crypto.py @@ -1,5 +1,6 @@ """Cryptography functions used by BasicWallet.""" +import logging import re from collections import OrderedDict from typing import Callable, List, Optional, Sequence, Tuple, Union @@ -20,6 +21,8 @@ from .key_type import BLS12381G2, ED25519, KeyType from .util import b58_to_bytes, b64_to_bytes, bytes_to_b58, random_seed +LOGGER = logging.getLogger(__name__) + def create_keypair( key_type: KeyType, seed: Optional[bytes] = None @@ -423,7 +426,7 @@ def decode_pack_message_outer(enc_message: bytes) -> Tuple[dict, dict, bool]: try: wrapper = JweEnvelope.from_json(enc_message) except ValidationError as err: - print(err) + LOGGER.error(err) raise ValueError("Invalid packed message") alg = wrapper.protected.get("alg") From 8f46fdb4f00a33c3bcaee3dc6a62c4b561616dbe Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 13:05:40 +0200 Subject: [PATCH 29/72] :loud_sound: Expand logging for Conductor setup Signed-off-by: ff137 --- acapy_agent/core/conductor.py | 49 ++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index 36bb6017ba..1384ff9e87 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -124,41 +124,62 @@ def context(self) -> InjectionContext: async def setup(self): """Initialize the global request context.""" + LOGGER.debug("Starting setup of the Conductor") context = await self.context_builder.build_context() + LOGGER.debug("Context built successfully") if self.force_agent_anoncreds: + LOGGER.debug( + "Force agent anoncreds is enabled. " + "Setting wallet type to 'askar-anoncreds'." + ) context.settings.set_value("wallet.type", "askar-anoncreds") # Fetch genesis transactions if necessary if context.settings.get("ledger.ledger_config_list"): + LOGGER.debug( + "Ledger config list found. Loading multiple genesis transactions" + ) await load_multiple_genesis_transactions_from_config(context.settings) if ( context.settings.get("ledger.genesis_transactions") or context.settings.get("ledger.genesis_file") or context.settings.get("ledger.genesis_url") ): + LOGGER.debug( + "Genesis transactions/configurations found. Fetching genesis transactions" + ) await get_genesis_transactions(context.settings) # Configure the root profile + LOGGER.debug("Configuring the root profile and setting up public DID") self.root_profile, self.setup_public_did = await wallet_config(context) context = self.root_profile.context + LOGGER.debug("Root profile configured successfully") # Multiledger Setup if ( context.settings.get("ledger.ledger_config_list") and len(context.settings.get("ledger.ledger_config_list")) > 0 ): + LOGGER.debug("Setting up multiledger manager") context.injector.bind_provider( BaseMultipleLedgerManager, MultiIndyLedgerManagerProvider(self.root_profile), ) if not (context.settings.get("ledger.genesis_transactions")): ledger = context.injector.inject(BaseLedger) + LOGGER.debug( + "Ledger backend: %s, Profile backend: %s", + ledger.BACKEND_NAME, + self.root_profile.BACKEND_NAME, + ) if ( self.root_profile.BACKEND_NAME == "askar" and ledger.BACKEND_NAME == "indy-vdr" ): + LOGGER.debug("Binding IndyCredxVerifier for 'askar' backend.") context.injector.bind_provider( IndyVerifier, ClassProvider( @@ -170,6 +191,9 @@ async def setup(self): self.root_profile.BACKEND_NAME == "askar-anoncreds" and ledger.BACKEND_NAME == "indy-vdr" ): + LOGGER.debug( + "Binding IndyCredxVerifier for 'askar-anoncreds' backend." + ) context.injector.bind_provider( IndyVerifier, ClassProvider( @@ -178,6 +202,7 @@ async def setup(self): ), ) else: + LOGGER.error("Unsupported ledger backend for multiledger setup.") raise MultipleLedgerManagerError( "Multiledger is supported only for Indy SDK or Askar " "[Indy VDR] profile" @@ -190,10 +215,13 @@ async def setup(self): if not await ledger_config( self.root_profile, self.setup_public_did and self.setup_public_did.did ): - LOGGER.warning("No ledger configured") + LOGGER.warning("No ledger configured.") + else: + LOGGER.debug("Ledger configured successfully.") if not context.settings.get("transport.disabled"): # Register all inbound transports if enabled + LOGGER.debug("Transport not disabled. Setting up inbound transports.") self.inbound_transport_manager = InboundTransportManager( self.root_profile, self.inbound_message_router, self.handle_not_returned ) @@ -201,45 +229,55 @@ async def setup(self): context.injector.bind_instance( InboundTransportManager, self.inbound_transport_manager ) + LOGGER.debug("Inbound transports registered successfully.") if not context.settings.get("transport.disabled"): # Register all outbound transports + LOGGER.debug("Transport not disabled. Setting up outbound transports.") self.outbound_transport_manager = OutboundTransportManager( self.root_profile, self.handle_not_delivered ) await self.outbound_transport_manager.setup() + LOGGER.debug("Outbound transports registered successfully.") # Initialize dispatcher + LOGGER.debug("Initializing dispatcher.") self.dispatcher = Dispatcher(self.root_profile) await self.dispatcher.setup() + LOGGER.debug("Dispatcher initialized successfully.") wire_format = context.inject_or(BaseWireFormat) if wire_format and hasattr(wire_format, "task_queue"): wire_format.task_queue = self.dispatcher.task_queue + LOGGER.debug("Wire format task queue bound to dispatcher.") # Bind manager for multitenancy related tasks if context.settings.get("multitenant.enabled"): + LOGGER.debug("Multitenant is enabled. Binding MultitenantManagerProvider.") context.injector.bind_provider( BaseMultitenantManager, MultitenantManagerProvider(self.root_profile) ) # Bind route manager provider + LOGGER.debug("Binding RouteManagerProvider.") context.injector.bind_provider( RouteManager, RouteManagerProvider(self.root_profile) ) - # Bind oob message processor to be able to receive and process un-encrypted - # messages + # Bind oob message processor to be able to receive and process un-encrypted messages + LOGGER.debug("Binding OobMessageProcessor.") context.injector.bind_instance( OobMessageProcessor, OobMessageProcessor(inbound_message_router=self.inbound_message_router), ) # Bind default PyLD document loader + LOGGER.debug("Binding default DocumentLoader.") context.injector.bind_instance(DocumentLoader, DocumentLoader(self.root_profile)) # Admin API if context.settings.get("admin.enabled"): + LOGGER.debug("Admin API is enabled. Attempting to register admin server.") try: admin_host = context.settings.get("admin.host", "0.0.0.0") admin_port = context.settings.get("admin.port", "80") @@ -255,13 +293,15 @@ async def setup(self): self.get_stats, ) context.injector.bind_instance(BaseAdminServer, self.admin_server) + LOGGER.debug("Admin server registered on %s:%s.", admin_host, admin_port) except Exception: - LOGGER.exception("Unable to register admin server") + LOGGER.exception("Unable to register admin server.") raise # Fetch stats collector, if any collector = context.inject_or(Collector) if collector: + LOGGER.debug("Stats collector found. Wrapping methods for collection.") # add stats to our own methods collector.wrap( self, @@ -280,6 +320,7 @@ async def setup(self): "find_inbound_connection", ), ) + LOGGER.debug("Methods wrapped with stats collector.") async def start(self) -> None: """Start the agent.""" From edde403a119959a26c385d878e790d38faac22c1 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 13:30:26 +0200 Subject: [PATCH 30/72] :art: Correct to uphold previous "Module doesn't exist" log behaviour Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index b4094e4e19..e1743afb0c 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -125,6 +125,7 @@ def register_plugin(self, module_name: str) -> Optional[ModuleType]: mod = self._load_module(module_name) if not mod: + LOGGER.error("Module doesn't exist: %s", module_name) return None if self._is_valid_plugin(mod, module_name): @@ -153,7 +154,6 @@ def _load_module(self, module_name: str) -> Optional[ModuleType]: """Load the plugin module using ClassLoader.""" try: mod = ClassLoader.load_module(module_name) - LOGGER.debug("Successfully loaded module: %s", module_name) return mod except ModuleLoadError as e: LOGGER.error("Error loading plugin module '%s': %s", module_name, e) From cc5ceab5c40f293a1d78725398e27ea5d9ae8ba3 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 13:37:00 +0200 Subject: [PATCH 31/72] :white_check_mark: Fix test by using assertLogs instead of capturing stdout Signed-off-by: ff137 --- acapy_agent/core/tests/test_conductor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acapy_agent/core/tests/test_conductor.py b/acapy_agent/core/tests/test_conductor.py index 875623deee..9d4525e4e9 100644 --- a/acapy_agent/core/tests/test_conductor.py +++ b/acapy_agent/core/tests/test_conductor.py @@ -1210,7 +1210,7 @@ async def test_print_invite_connection(self): test_profile, DIDInfo("did", "verkey", metadata={}, method=SOV, key_type=ED25519), ), - ), mock.patch("sys.stdout", new=StringIO()) as captured, mock.patch.object( + ), self.assertLogs(level="INFO") as captured, mock.patch.object( test_module, "OutboundTransportManager", autospec=True ) as mock_outbound_mgr: mock_outbound_mgr.return_value.registered_transports = { @@ -1220,9 +1220,9 @@ async def test_print_invite_connection(self): await conductor.start() await conductor.stop() - value = captured.getvalue() - assert "http://localhost?oob=" in value - assert "http://localhost?c_i=" in value + value = captured.output + assert any("http://localhost?oob=" in msg for msg in value) + assert any("http://localhost?c_i=" in msg for msg in value) async def test_clear_default_mediator(self): builder: ContextBuilder = StubContextBuilder(self.test_settings) From 44e980772de6f9da2044460f2c4d446db14c1f22 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 13:51:54 +0200 Subject: [PATCH 32/72] Revert ":art: Rename method and remove redundant main call" This reverts commit 2f6526d108b3a8df527d2694c9ce3c46e438f963. Signed-off-by: ff137 --- acapy_agent/commands/provision.py | 11 ++++++++--- acapy_agent/commands/tests/test_provision.py | 13 +++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/acapy_agent/commands/provision.py b/acapy_agent/commands/provision.py index 6d86d412b6..f0fb7cf561 100644 --- a/acapy_agent/commands/provision.py +++ b/acapy_agent/commands/provision.py @@ -70,7 +70,7 @@ async def provision(settings: dict): raise ProvisionError("Error during provisioning") from e -def execute_provision(argv: Sequence[str] = None): +def execute(argv: Sequence[str] = None): """Entrypoint.""" parser = arg.create_argument_parser(prog=PROG) parser.prog += " provision" @@ -87,5 +87,10 @@ def execute_provision(argv: Sequence[str] = None): loop.run_until_complete(provision(settings)) -if __name__ == "__main__": - execute_provision() +def main(): + """Execute the main line.""" + if __name__ == "__main__": + execute() + + +main() diff --git a/acapy_agent/commands/tests/test_provision.py b/acapy_agent/commands/tests/test_provision.py index 3fbeb00208..65d0d488bd 100644 --- a/acapy_agent/commands/tests/test_provision.py +++ b/acapy_agent/commands/tests/test_provision.py @@ -14,10 +14,10 @@ class TestProvision(IsolatedAsyncioTestCase): def test_bad_calls(self): with self.assertRaises(ArgsParseError): - test_module.execute_provision([]) + test_module.execute([]) with self.assertRaises(SystemExit): - test_module.execute_provision(["bad"]) + test_module.execute(["bad"]) async def test_provision_ledger_configured(self): profile = mock.MagicMock(close=mock.CoroutineMock()) @@ -43,14 +43,11 @@ async def test_provision_config_x(self): with self.assertRaises(test_module.ProvisionError): await test_module.provision({}) - def test_main_entry_point(self): - """Test that the execute_provision function is called when the module is run as main.""" + def test_main(self): with mock.patch.object(test_module, "__name__", "__main__"), mock.patch.object( - test_module, "execute_provision", mock.MagicMock() + test_module, "execute", mock.MagicMock() ) as mock_execute: - import importlib - - importlib.reload(test_module) # Reload the module to trigger the main guard + test_module.main() mock_execute.assert_called_once async def test_provision_should_store_provided_mediation_invite(self): From cfec6a67d97a4e6cee413575c156c97a0a22e775 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 13:55:19 +0200 Subject: [PATCH 33/72] :art: Signed-off-by: ff137 --- acapy_agent/core/conductor.py | 7 ++----- acapy_agent/core/plugin_registry.py | 2 +- acapy_agent/core/tests/test_conductor.py | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index 1384ff9e87..641a989cfe 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -42,10 +42,7 @@ from ..messaging.responder import BaseResponder from ..multitenant.base import BaseMultitenantManager from ..multitenant.manager_provider import MultitenantManagerProvider -from ..protocols.connections.v1_0.manager import ( - ConnectionManager, - ConnectionManagerError, -) +from ..protocols.connections.v1_0.manager import ConnectionManager, ConnectionManagerError from ..protocols.connections.v1_0.messages.connection_invitation import ( ConnectionInvitation, ) @@ -264,7 +261,7 @@ async def setup(self): RouteManager, RouteManagerProvider(self.root_profile) ) - # Bind oob message processor to be able to receive and process un-encrypted messages + # Bind OobMessageProcessor to be able to receive and process unencrypted messages LOGGER.debug("Binding OobMessageProcessor.") context.injector.bind_instance( OobMessageProcessor, diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index e1743afb0c..08f4edb2bd 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -422,7 +422,7 @@ def post_process_routes(self, app) -> None: continue if mod and hasattr(mod, "post_process_routes"): - LOGGER.debug("Post-processing routes from: %s", version_path) + LOGGER.debug("Post-processing routes for %s", plugin_name) mod.post_process_routes(app) def __repr__(self) -> str: diff --git a/acapy_agent/core/tests/test_conductor.py b/acapy_agent/core/tests/test_conductor.py index 9d4525e4e9..9f8e783491 100644 --- a/acapy_agent/core/tests/test_conductor.py +++ b/acapy_agent/core/tests/test_conductor.py @@ -1,4 +1,3 @@ -from io import StringIO from unittest import IsolatedAsyncioTestCase import pytest From 500e4b29b9c07c645a884e14105315e12f8986cd Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 14:15:39 +0200 Subject: [PATCH 34/72] :white_check_mark: Fix test by adding __name__ to mock object Signed-off-by: ff137 --- acapy_agent/core/tests/test_plugin_registry.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acapy_agent/core/tests/test_plugin_registry.py b/acapy_agent/core/tests/test_plugin_registry.py index b5727a4546..4e870fbdfb 100644 --- a/acapy_agent/core/tests/test_plugin_registry.py +++ b/acapy_agent/core/tests/test_plugin_registry.py @@ -537,6 +537,7 @@ async def test_load_protocols_load_mod(self): mock_mod = mock.MagicMock() mock_mod.MESSAGE_TYPES = mock.MagicMock() mock_mod.CONTROLLERS = mock.MagicMock() + mock_mod.__name__ = "test_mod" with mock.patch.object( ClassLoader, "load_module", mock.MagicMock() @@ -595,6 +596,7 @@ async def test_load_protocols_no_mod_def_message_types(self): mock_mod = mock.MagicMock() mock_mod.MESSAGE_TYPES = mock.MagicMock() mock_mod.CONTROLLERS = mock.MagicMock() + mock_mod.__name__ = "test_mod" with mock.patch.object( ClassLoader, "load_module", mock.MagicMock() From 5134d163c451ec839ec8d4b0e8057762c6a2a550 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 14:17:10 +0200 Subject: [PATCH 35/72] :art: Signed-off-by: ff137 --- acapy_agent/core/conductor.py | 13 ++++++------- acapy_agent/core/plugin_registry.py | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index 641a989cfe..f0ad8ff887 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -156,16 +156,14 @@ async def setup(self): LOGGER.debug("Root profile configured successfully") # Multiledger Setup - if ( - context.settings.get("ledger.ledger_config_list") - and len(context.settings.get("ledger.ledger_config_list")) > 0 - ): + ledger_config_list = context.settings.get("ledger.ledger_config_list") + if ledger_config_list and len(ledger_config_list) > 0: LOGGER.debug("Setting up multiledger manager") context.injector.bind_provider( BaseMultipleLedgerManager, MultiIndyLedgerManagerProvider(self.root_profile), ) - if not (context.settings.get("ledger.genesis_transactions")): + if not context.settings.get("ledger.genesis_transactions"): ledger = context.injector.inject(BaseLedger) LOGGER.debug( "Ledger backend: %s, Profile backend: %s", @@ -209,9 +207,10 @@ async def setup(self): ) # Configure the ledger - if not await ledger_config( + ledger_configured = await ledger_config( self.root_profile, self.setup_public_did and self.setup_public_did.did - ): + ) + if not ledger_configured: LOGGER.warning("No ledger configured.") else: LOGGER.debug("Ledger configured successfully.") diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 08f4edb2bd..cd4942ffa3 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -349,7 +349,7 @@ async def register_admin_routes(self, app) -> None: continue if mod and hasattr(mod, "register"): - LOGGER.debug("Registering routes from: %s", version_path) + LOGGER.debug("Registering routes for: %s", plugin_name) await mod.register(app) def register_protocol_events(self, context: InjectionContext) -> None: From aa0765a3d7a0681c85bb5bab27114cf67463ca4a Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 14:59:43 +0200 Subject: [PATCH 36/72] :sparkles: Add custom trace log level Signed-off-by: ff137 --- acapy_agent/config/logging/configurator.py | 5 ++ acapy_agent/config/logging/utils.py | 98 ++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 acapy_agent/config/logging/utils.py diff --git a/acapy_agent/config/logging/configurator.py b/acapy_agent/config/logging/configurator.py index 11763dca08..8843ed78e2 100644 --- a/acapy_agent/config/logging/configurator.py +++ b/acapy_agent/config/logging/configurator.py @@ -31,6 +31,11 @@ from .timed_rotating_file_multi_process_handler import ( TimedRotatingFileMultiProcessHandler, ) +from .utils import add_trace_level + + +# Add TRACE level to logging before any configuration +add_trace_level() def load_resource(path: str, encoding: Optional[str] = None): diff --git a/acapy_agent/config/logging/utils.py b/acapy_agent/config/logging/utils.py new file mode 100644 index 0000000000..20f76e00b7 --- /dev/null +++ b/acapy_agent/config/logging/utils.py @@ -0,0 +1,98 @@ +"""Logging utilities.""" + +import logging +from functools import partial, partialmethod +from typing import Optional + + +def add_logging_level( + level_name: str, level_num: int, method_name: Optional[str] = None +) -> None: + """Add a custom logging level to the `logging` module. + + Comprehensively adds a new logging level to the `logging` module and the + currently configured logging class. + + `level_name` becomes an attribute of the `logging` module with the value + `level_num`. + `methodName` becomes a convenience method for both `logging` itself + and the class returned by `logging.getLoggerClass()` (usually just + `logging.Logger`). + If `methodName` is not specified, `levelName.lower()` is used. + + To avoid accidental clobberings of existing attributes, this method will + raise an `AttributeError` if the level name is already an attribute of the + `logging` module or if the method name is already present + + Example: + ------- + >>> add_logging_level('TRACE', logging.DEBUG - 5) + >>> logging.getLogger(__name__).setLevel('TRACE') + >>> logging.getLogger(__name__).trace('that worked') + >>> logging.trace('so did this') + >>> logging.TRACE + 5 + + References: + - https://stackoverflow.com/a/35804945 + """ + if not method_name: + method_name = level_name.lower() + + if hasattr(logging, level_name): + raise AttributeError(f"{level_name} already defined in logging module") + if hasattr(logging, method_name): + raise AttributeError(f"{method_name} already defined in logging module") + if hasattr(logging.getLoggerClass(), method_name): + raise AttributeError(f"{method_name} already defined in logger class") + + # Add the new logging level + logging.addLevelName(level_num, level_name) + setattr(logging, level_name, level_num) + setattr( + logging.getLoggerClass(), + method_name, + partialmethod(logging.getLoggerClass().log, level_num), + ) + setattr(logging, method_name, partial(logging.log, level_num)) + + +def add_trace_level() -> None: + """Add the TRACE level to the logging module safely. + + This function adds a TRACE level to the logging module if it hasn't been added yet. + It handles the case where TRACE is already defined, avoiding duplicate additions. + + Returns: + None + """ + TRACE_LEVEL_NUM = logging.DEBUG - 5 + TRACE_LEVEL_NAME = "TRACE" + TRACE_METHOD_NAME = "trace" + + # Check if TRACE level is already defined + level_exists = ( + hasattr(logging, TRACE_LEVEL_NAME) + and getattr(logging, TRACE_LEVEL_NAME) == TRACE_LEVEL_NUM + ) + + method_exists = hasattr(logging, TRACE_METHOD_NAME) and callable( + getattr(logging, TRACE_METHOD_NAME) + ) + + if not level_exists or not method_exists: + try: + add_logging_level(TRACE_LEVEL_NAME, TRACE_LEVEL_NUM, TRACE_METHOD_NAME) + logging.getLogger(__name__).debug( + f"{TRACE_LEVEL_NAME} level added to logging module." + ) + except AttributeError as e: + # Log a warning if TRACE level already exists + logging.getLogger(__name__).warning( + f"{TRACE_LEVEL_NAME} level already exists: {e}" + ) + else: + # Optionally, you can log that TRACE level is already present + logging.getLogger(__name__).debug( + f"{TRACE_LEVEL_NAME} level is already present in the logging module." + ) From 190cc281626552eefa435d8fe1733062d65ce71f Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 15:00:11 +0200 Subject: [PATCH 37/72] :art: Ensure trace level can only be added once Signed-off-by: ff137 --- acapy_agent/config/logging/utils.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/acapy_agent/config/logging/utils.py b/acapy_agent/config/logging/utils.py index 20f76e00b7..e6527aa852 100644 --- a/acapy_agent/config/logging/utils.py +++ b/acapy_agent/config/logging/utils.py @@ -3,6 +3,7 @@ import logging from functools import partial, partialmethod from typing import Optional +_TRACE_LEVEL_ADDED = False def add_logging_level( @@ -66,6 +67,11 @@ def add_trace_level() -> None: Returns: None """ + global _TRACE_LEVEL_ADDED + + if _TRACE_LEVEL_ADDED: + return + TRACE_LEVEL_NUM = logging.DEBUG - 5 TRACE_LEVEL_NAME = "TRACE" TRACE_METHOD_NAME = "trace" @@ -96,3 +102,5 @@ def add_trace_level() -> None: logging.getLogger(__name__).debug( f"{TRACE_LEVEL_NAME} level is already present in the logging module." ) + + _TRACE_LEVEL_ADDED = True From 63ca170e35ca7261db16c9b6bade6a96cacddd3c Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 15:00:22 +0200 Subject: [PATCH 38/72] :art: Add Logger Signed-off-by: ff137 --- acapy_agent/config/logging/utils.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/acapy_agent/config/logging/utils.py b/acapy_agent/config/logging/utils.py index e6527aa852..5ee6108607 100644 --- a/acapy_agent/config/logging/utils.py +++ b/acapy_agent/config/logging/utils.py @@ -3,6 +3,8 @@ import logging from functools import partial, partialmethod from typing import Optional + +LOGGER = logging.getLogger(__name__) _TRACE_LEVEL_ADDED = False @@ -89,18 +91,14 @@ def add_trace_level() -> None: if not level_exists or not method_exists: try: add_logging_level(TRACE_LEVEL_NAME, TRACE_LEVEL_NUM, TRACE_METHOD_NAME) - logging.getLogger(__name__).debug( - f"{TRACE_LEVEL_NAME} level added to logging module." - ) + LOGGER.debug("%s level added to logging module.", TRACE_LEVEL_NAME) except AttributeError as e: # Log a warning if TRACE level already exists - logging.getLogger(__name__).warning( - f"{TRACE_LEVEL_NAME} level already exists: {e}" - ) + LOGGER.warning("%s level already exists: %s", TRACE_LEVEL_NAME, e) else: # Optionally, you can log that TRACE level is already present - logging.getLogger(__name__).debug( - f"{TRACE_LEVEL_NAME} level is already present in the logging module." + LOGGER.debug( + "%s level is already present in the logging module.", TRACE_LEVEL_NAME ) _TRACE_LEVEL_ADDED = True From 3641e2fd26e8cc4d65032361114b4c3a3d895fc4 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 15:08:53 +0200 Subject: [PATCH 39/72] :art: Update newly added logs to be trace level instead of debug Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 78 +++++++++++++++-------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index cd4942ffa3..f86495291e 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -6,6 +6,7 @@ from typing import Optional, Sequence, Set from ..config.injection_context import InjectionContext +from ..config.logging.utils import add_trace_level from ..core.event_bus import EventBus from ..utils.classloader import ClassLoader, ModuleLoadError from .error import ProtocolDefinitionValidationError @@ -13,6 +14,7 @@ from .protocol_registry import ProtocolRegistry LOGGER = logging.getLogger(__name__) +add_trace_level() # Allow trace logs from this module class PluginRegistry: @@ -130,7 +132,7 @@ def register_plugin(self, module_name: str) -> Optional[ModuleType]: if self._is_valid_plugin(mod, module_name): self._plugins[module_name] = mod - LOGGER.debug("Registered plugin: %s", module_name) + LOGGER.trace("Registered plugin: %s", module_name) return mod LOGGER.debug("Failed to register plugin: %s", module_name) @@ -139,7 +141,7 @@ def register_plugin(self, module_name: str) -> Optional[ModuleType]: def _is_already_registered(self, module_name: str) -> bool: """Check if the plugin is already registered.""" if module_name in self._plugins: - LOGGER.debug("Plugin %s is already registered.", module_name) + LOGGER.trace("Plugin %s is already registered.", module_name) return True return False @@ -163,7 +165,7 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: """Validate the plugin based on various criteria.""" # Check if the plugin has a 'setup' method if hasattr(mod, "setup"): - LOGGER.debug("Plugin %s has a 'setup' method.", module_name) + LOGGER.trace("Plugin %s has a 'setup' method.", module_name) return True # Check for 'routes' or 'message_types' modules @@ -172,7 +174,7 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: routes = ClassLoader.load_module("routes", module_name) message_types = ClassLoader.load_module("message_types", module_name) if routes or message_types: - LOGGER.debug("Plugin %s has 'routes' or 'message_types'.", module_name) + LOGGER.trace("Plugin %s has 'routes' or 'message_types'.", module_name) return True # Check for 'definition' module with 'versions' attribute @@ -194,7 +196,7 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: # Validate the 'versions' attribute try: self.validate_version(definition.versions, module_name) - LOGGER.debug("Plugin %s has valid versions.", module_name) + LOGGER.trace("Plugin %s has valid versions.", module_name) return True except ProtocolDefinitionValidationError as e: LOGGER.error( @@ -206,7 +208,7 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: def register_package(self, package_name: str) -> Sequence[ModuleType]: """Register all modules (sub-packages) under a given package name.""" - LOGGER.debug("Registering package: %s", package_name) + LOGGER.trace("Registering package: %s", package_name) try: module_names = ClassLoader.scan_subpackages(package_name) except ModuleLoadError: @@ -217,28 +219,28 @@ def register_package(self, package_name: str) -> Sequence[ModuleType]: for module_name in module_names: # Skip any module whose last segment is 'tests' if module_name.split(".")[-1] == "tests": - LOGGER.debug("Skipping test module: %s", module_name) + LOGGER.trace("Skipping test module: %s", module_name) continue plugin = self.register_plugin(module_name) if plugin: registered_plugins.append(plugin) else: - LOGGER.debug("Failed to register %s under %s", module_name, package_name) + LOGGER.trace("Failed to register %s under %s", module_name, package_name) return registered_plugins async def init_context(self, context: InjectionContext) -> None: """Call plugin setup methods on the current context.""" - LOGGER.debug("Initializing plugin context for %d plugins", len(self._plugins)) + LOGGER.trace("Initializing plugin context for %d plugins", len(self._plugins)) for plugin in self._plugins.values(): plugin_name = plugin.__name__ if hasattr(plugin, "setup"): - LOGGER.debug("Running setup for plugin: %s", plugin_name) + LOGGER.trace("Running setup for plugin: %s", plugin_name) await plugin.setup(context) else: - LOGGER.debug( + LOGGER.trace( "Loading protocols for plugin without setup: %s", plugin_name ) await self.load_protocols(context, plugin) @@ -257,55 +259,55 @@ async def load_protocol_version( goal_code_registry = context.inject(GoalCodeRegistry) module_name = mod.__name__ - LOGGER.debug("Loading protocol version for module: %s", module_name) + LOGGER.trace("Loading protocol version for module: %s", module_name) if hasattr(mod, "MESSAGE_TYPES"): - LOGGER.debug("Registering message types for: %s", module_name) + LOGGER.trace("Registering message types for: %s", module_name) protocol_registry.register_message_types( mod.MESSAGE_TYPES, version_definition=version_definition ) if hasattr(mod, "CONTROLLERS"): - LOGGER.debug("Registering controllers for: %s", module_name) + LOGGER.trace("Registering controllers for: %s", module_name) protocol_registry.register_controllers(mod.CONTROLLERS) goal_code_registry.register_controllers(mod.CONTROLLERS) async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> None: """For modules that don't implement setup, register protocols manually.""" plugin_name = plugin.__name__ - LOGGER.debug("Loading protocols for plugin: %s", plugin_name) + LOGGER.trace("Loading protocols for plugin: %s", plugin_name) # If this module contains message_types, then assume that # this is a valid module of the old style (not versioned) try: message_types_path = f"{plugin_name}.message_types" - LOGGER.debug("Attempting to load message types from: %s", message_types_path) + LOGGER.trace("Attempting to load message types from: %s", message_types_path) mod = ClassLoader.load_module(message_types_path) except ModuleLoadError as e: LOGGER.error("Error loading plugin module message types: %s", e) return if mod: - LOGGER.debug("Found non-versioned message types for: %s", plugin_name) + LOGGER.trace("Found non-versioned message types for: %s", plugin_name) await self.load_protocol_version(context, mod) else: # Otherwise, try check for definition.py for versioned protocol packages try: definition_path = f"{plugin_name}.definition" - LOGGER.debug("Attempting to load definition from: %s", definition_path) + LOGGER.trace("Attempting to load definition from: %s", definition_path) definition = ClassLoader.load_module(definition_path) except ModuleLoadError as e: LOGGER.error("Error loading plugin definition module: %s", e) return if definition: - LOGGER.debug("Loading versioned protocols for: %s", plugin_name) + LOGGER.trace("Loading versioned protocols for: %s", plugin_name) for protocol_version in definition.versions: version_path = ( f"{plugin_name}.{protocol_version['path']}.message_types" ) try: - LOGGER.debug("Loading message types from: %s", version_path) + LOGGER.trace("Loading message types from: %s", version_path) mod = ClassLoader.load_module(version_path) await self.load_protocol_version(context, mod, protocol_version) except ModuleLoadError as e: @@ -318,20 +320,20 @@ async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> async def register_admin_routes(self, app) -> None: """Call route registration methods on the current context.""" - LOGGER.debug("Registering admin routes for %d plugins", len(self._plugins)) + LOGGER.trace("Registering admin routes for %d plugins", len(self._plugins)) for plugin in self._plugins.values(): plugin_name = plugin.__name__ - LOGGER.debug("Processing routes for plugin: %s", plugin_name) + LOGGER.trace("Processing routes for plugin: %s", plugin_name) mod = None definition = ClassLoader.load_module("definition", plugin_name) if definition: # Load plugin routes that are in a versioned package. - LOGGER.debug("Loading versioned routes for: %s", plugin_name) + LOGGER.trace("Loading versioned routes for: %s", plugin_name) for plugin_version in definition.versions: version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - LOGGER.debug("Loading routes from: %s", version_path) + LOGGER.trace("Loading routes from: %s", version_path) mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: LOGGER.error( @@ -342,19 +344,19 @@ async def register_admin_routes(self, app) -> None: # Load plugin routes that aren't in a versioned package. routes_path = f"{plugin_name}.routes" try: - LOGGER.debug("Loading non-versioned routes from: %s", routes_path) + LOGGER.trace("Loading non-versioned routes from: %s", routes_path) mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: LOGGER.error("Error loading admin routes from %s: %s", routes_path, e) continue if mod and hasattr(mod, "register"): - LOGGER.debug("Registering routes for: %s", plugin_name) + LOGGER.trace("Registering routes for: %s", plugin_name) await mod.register(app) def register_protocol_events(self, context: InjectionContext) -> None: """Call route register_events methods on the current context.""" - LOGGER.debug("Registering protocol events for %d plugins", len(self._plugins)) + LOGGER.trace("Registering protocol events for %d plugins", len(self._plugins)) event_bus = context.inject_or(EventBus) if not event_bus: @@ -363,16 +365,16 @@ def register_protocol_events(self, context: InjectionContext) -> None: for plugin in self._plugins.values(): plugin_name = plugin.__name__ - LOGGER.debug("Processing events for plugin: %s", plugin_name) + LOGGER.trace("Processing events for plugin: %s", plugin_name) mod = None definition = ClassLoader.load_module("definition", plugin_name) if definition: # Load plugin routes that are in a versioned package. - LOGGER.debug("Loading versioned events for: %s", plugin_name) + LOGGER.trace("Loading versioned events for: %s", plugin_name) for plugin_version in definition.versions: version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - LOGGER.debug("Loading events from: %s", version_path) + LOGGER.trace("Loading events from: %s", version_path) mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: LOGGER.error("Error loading events from %s: %s", version_path, e) @@ -381,32 +383,32 @@ def register_protocol_events(self, context: InjectionContext) -> None: # Load plugin routes that aren't in a versioned package. routes_path = f"{plugin_name}.routes" try: - LOGGER.debug("Loading non-versioned events from: %s", routes_path) + LOGGER.trace("Loading non-versioned events from: %s", routes_path) mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: LOGGER.error("Error loading events from %s: %s", routes_path, e) continue if mod and hasattr(mod, "register_events"): - LOGGER.debug("Registering events from: %s", version_path) + LOGGER.trace("Registering events from: %s", version_path) mod.register_events(event_bus) def post_process_routes(self, app) -> None: """Call route binary file response OpenAPI fixups if applicable.""" - LOGGER.debug("Post-processing routes for %d plugins", len(self._plugins)) + LOGGER.trace("Post-processing routes for %d plugins", len(self._plugins)) for plugin in self._plugins.values(): plugin_name = plugin.__name__ - LOGGER.debug("Post-processing routes for plugin: %s", plugin_name) + LOGGER.trace("Post-processing routes for plugin: %s", plugin_name) mod = None definition = ClassLoader.load_module("definition", plugin_name) if definition: # Set binary file responses for routes that are in a versioned package. - LOGGER.debug("Processing versioned routes for: %s", plugin_name) + LOGGER.trace("Processing versioned routes for: %s", plugin_name) for plugin_version in definition.versions: version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - LOGGER.debug("Loading routes from: %s", version_path) + LOGGER.trace("Loading routes from: %s", version_path) mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: LOGGER.error("Error loading routes from %s: %s", version_path, e) @@ -415,14 +417,14 @@ def post_process_routes(self, app) -> None: # Set binary file responses for routes not in a versioned package. routes_path = f"{plugin_name}.routes" try: - LOGGER.debug("Loading non-versioned routes from: %s", routes_path) + LOGGER.trace("Loading non-versioned routes from: %s", routes_path) mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: LOGGER.error("Error loading routes from %s: %s", routes_path, e) continue if mod and hasattr(mod, "post_process_routes"): - LOGGER.debug("Post-processing routes for %s", plugin_name) + LOGGER.trace("Post-processing routes for %s", plugin_name) mod.post_process_routes(app) def __repr__(self) -> str: From bf1295f076f4119786a52d78b0a8cb1379508202 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 15:14:10 +0200 Subject: [PATCH 40/72] :art: Update newly added logs to be trace level instead of debug Signed-off-by: ff137 --- acapy_agent/config/default_context.py | 20 +++++++------ acapy_agent/core/conductor.py | 41 +++++++++++++-------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index ed49ff175d..35ee02a184 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -5,6 +5,7 @@ from ..anoncreds.registry import AnonCredsRegistry from ..cache.base import BaseCache from ..cache.in_memory import InMemoryCache +from ..config.logging.utils import add_trace_level from ..core.event_bus import EventBus from ..core.goal_code_registry import GoalCodeRegistry from ..core.plugin_registry import PluginRegistry @@ -29,6 +30,7 @@ from .provider import CachedProvider, ClassProvider LOGGER = logging.getLogger(__name__) +add_trace_level() # Allow trace logs from this module class DefaultContextBuilder(ContextBuilder): @@ -36,14 +38,14 @@ class DefaultContextBuilder(ContextBuilder): async def build_context(self) -> InjectionContext: """Build the base injection context; set DIDComm prefix to emit.""" - LOGGER.debug("Building new injection context with settings: %s", self.settings) + LOGGER.trace("Building new injection context with settings: %s", self.settings) context = InjectionContext(settings=self.settings) context.settings.set_default("default_label", "Aries Cloud Agent") if context.settings.get("timing.enabled"): timing_log = context.settings.get("timing.log_file") - LOGGER.debug("Enabling timing collector with log file: %s", timing_log) + LOGGER.trace("Enabling timing collector with log file: %s", timing_log) collector = Collector(log_path=timing_log) context.injector.bind_instance(Collector, collector) @@ -85,13 +87,13 @@ async def build_context(self) -> InjectionContext: async def bind_providers(self, context: InjectionContext): """Bind various class providers.""" - LOGGER.debug("Begin binding providers to context") + LOGGER.trace("Begin binding providers to context") context.injector.bind_provider(ProfileManager, ProfileManagerProvider()) wallet_type = self.settings.get("wallet.type") if wallet_type == "askar-anoncreds": - LOGGER.debug("Using AnonCreds tails server") + LOGGER.trace("Using AnonCreds tails server") context.injector.bind_provider( BaseTailsServer, ClassProvider( @@ -99,7 +101,7 @@ async def bind_providers(self, context: InjectionContext): ), ) else: - LOGGER.debug("Using Indy tails server") + LOGGER.trace("Using Indy tails server") context.injector.bind_provider( BaseTailsServer, ClassProvider( @@ -122,7 +124,7 @@ async def bind_providers(self, context: InjectionContext): async def load_plugins(self, context: InjectionContext): """Set up plugin registry and load plugins.""" - LOGGER.debug("Initializing plugin registry") + LOGGER.trace("Initializing plugin registry") plugin_registry = PluginRegistry( blocklist=self.settings.get("blocked_plugins", []) ) @@ -162,7 +164,7 @@ async def load_plugins(self, context: InjectionContext): def register_plugins(plugins: list[str], plugin_type: str): """Register a group of plugins with logging.""" - LOGGER.debug("Registering %s plugins", plugin_type) + LOGGER.trace("Registering %s plugins", plugin_type) for plugin in plugins: plugin_registry.register_plugin(plugin) @@ -175,7 +177,7 @@ def register_anoncreds_plugins(): register_plugins(default_plugins, "default") if context.settings.get("multitenant.admin_enabled"): - LOGGER.debug("Multitenant admin enabled - registering additional plugins") + LOGGER.trace("Multitenant admin enabled - registering additional plugins") plugin_registry.register_plugin("acapy_agent.multitenant.admin") register_askar_plugins() register_anoncreds_plugins() @@ -187,7 +189,7 @@ def register_anoncreds_plugins(): # Register external plugins for plugin_path in self.settings.get("external_plugins", []): - LOGGER.debug("Registering external plugin: %s", plugin_path) + LOGGER.trace("Registering external plugin: %s", plugin_path) plugin_registry.register_plugin(plugin_path) # Register message protocols diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index f0ad8ff887..5d547bb935 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -124,7 +124,7 @@ async def setup(self): LOGGER.debug("Starting setup of the Conductor") context = await self.context_builder.build_context() - LOGGER.debug("Context built successfully") + LOGGER.trace("Context built successfully") if self.force_agent_anoncreds: LOGGER.debug( @@ -150,15 +150,15 @@ async def setup(self): await get_genesis_transactions(context.settings) # Configure the root profile - LOGGER.debug("Configuring the root profile and setting up public DID") + LOGGER.trace("Configuring the root profile and setting up public DID") self.root_profile, self.setup_public_did = await wallet_config(context) context = self.root_profile.context - LOGGER.debug("Root profile configured successfully") + LOGGER.trace("Root profile configured successfully") # Multiledger Setup ledger_config_list = context.settings.get("ledger.ledger_config_list") if ledger_config_list and len(ledger_config_list) > 0: - LOGGER.debug("Setting up multiledger manager") + LOGGER.trace("Setting up multiledger manager") context.injector.bind_provider( BaseMultipleLedgerManager, MultiIndyLedgerManagerProvider(self.root_profile), @@ -174,7 +174,7 @@ async def setup(self): self.root_profile.BACKEND_NAME == "askar" and ledger.BACKEND_NAME == "indy-vdr" ): - LOGGER.debug("Binding IndyCredxVerifier for 'askar' backend.") + LOGGER.trace("Binding IndyCredxVerifier for 'askar' backend.") context.injector.bind_provider( IndyVerifier, ClassProvider( @@ -186,7 +186,7 @@ async def setup(self): self.root_profile.BACKEND_NAME == "askar-anoncreds" and ledger.BACKEND_NAME == "indy-vdr" ): - LOGGER.debug( + LOGGER.trace( "Binding IndyCredxVerifier for 'askar-anoncreds' backend." ) context.injector.bind_provider( @@ -225,55 +225,54 @@ async def setup(self): context.injector.bind_instance( InboundTransportManager, self.inbound_transport_manager ) - LOGGER.debug("Inbound transports registered successfully.") + LOGGER.trace("Inbound transports registered successfully.") - if not context.settings.get("transport.disabled"): # Register all outbound transports - LOGGER.debug("Transport not disabled. Setting up outbound transports.") + LOGGER.debug("Setting up outbound transports.") self.outbound_transport_manager = OutboundTransportManager( self.root_profile, self.handle_not_delivered ) await self.outbound_transport_manager.setup() - LOGGER.debug("Outbound transports registered successfully.") + LOGGER.trace("Outbound transports registered successfully.") # Initialize dispatcher - LOGGER.debug("Initializing dispatcher.") + LOGGER.trace("Initializing dispatcher.") self.dispatcher = Dispatcher(self.root_profile) await self.dispatcher.setup() - LOGGER.debug("Dispatcher initialized successfully.") + LOGGER.trace("Dispatcher initialized successfully.") wire_format = context.inject_or(BaseWireFormat) if wire_format and hasattr(wire_format, "task_queue"): wire_format.task_queue = self.dispatcher.task_queue - LOGGER.debug("Wire format task queue bound to dispatcher.") + LOGGER.trace("Wire format task queue bound to dispatcher.") # Bind manager for multitenancy related tasks if context.settings.get("multitenant.enabled"): - LOGGER.debug("Multitenant is enabled. Binding MultitenantManagerProvider.") + LOGGER.trace("Multitenant is enabled. Binding MultitenantManagerProvider.") context.injector.bind_provider( BaseMultitenantManager, MultitenantManagerProvider(self.root_profile) ) # Bind route manager provider - LOGGER.debug("Binding RouteManagerProvider.") + LOGGER.trace("Binding RouteManagerProvider.") context.injector.bind_provider( RouteManager, RouteManagerProvider(self.root_profile) ) # Bind OobMessageProcessor to be able to receive and process unencrypted messages - LOGGER.debug("Binding OobMessageProcessor.") + LOGGER.trace("Binding OobMessageProcessor.") context.injector.bind_instance( OobMessageProcessor, OobMessageProcessor(inbound_message_router=self.inbound_message_router), ) # Bind default PyLD document loader - LOGGER.debug("Binding default DocumentLoader.") + LOGGER.trace("Binding default DocumentLoader.") context.injector.bind_instance(DocumentLoader, DocumentLoader(self.root_profile)) # Admin API if context.settings.get("admin.enabled"): - LOGGER.debug("Admin API is enabled. Attempting to register admin server.") + LOGGER.trace("Admin API is enabled. Attempting to register admin server.") try: admin_host = context.settings.get("admin.host", "0.0.0.0") admin_port = context.settings.get("admin.port", "80") @@ -289,7 +288,7 @@ async def setup(self): self.get_stats, ) context.injector.bind_instance(BaseAdminServer, self.admin_server) - LOGGER.debug("Admin server registered on %s:%s.", admin_host, admin_port) + LOGGER.debug("Admin server registered on %s:%s", admin_host, admin_port) except Exception: LOGGER.exception("Unable to register admin server.") raise @@ -297,7 +296,7 @@ async def setup(self): # Fetch stats collector, if any collector = context.inject_or(Collector) if collector: - LOGGER.debug("Stats collector found. Wrapping methods for collection.") + LOGGER.trace("Stats collector found. Wrapping methods for collection.") # add stats to our own methods collector.wrap( self, @@ -316,7 +315,7 @@ async def setup(self): "find_inbound_connection", ), ) - LOGGER.debug("Methods wrapped with stats collector.") + LOGGER.trace("Methods wrapped with stats collector.") async def start(self) -> None: """Start the agent.""" From 926eab19c923c68f0755159ace100b7368cf0bf1 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 15:22:01 +0200 Subject: [PATCH 41/72] :loud_sound: Expand logging for Conductor start and stop Signed-off-by: ff137 --- acapy_agent/core/conductor.py | 103 +++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 14 deletions(-) diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index 5d547bb935..5cf6bf1811 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -319,29 +319,36 @@ async def setup(self): async def start(self) -> None: """Start the agent.""" - + LOGGER.debug("Starting the Conductor agent.") context = self.root_profile.context await self.check_for_valid_wallet_type(self.root_profile) + LOGGER.trace("Wallet type validated.") if not context.settings.get("transport.disabled"): # Start up transports if enabled try: + LOGGER.trace("Transport not disabled. Starting inbound transports.") await self.inbound_transport_manager.start() + LOGGER.trace("Inbound transports started successfully.") except Exception: - LOGGER.exception("Unable to start inbound transports") + LOGGER.exception("Unable to start inbound transports.") raise try: + LOGGER.trace("Starting outbound transports.") await self.outbound_transport_manager.start() + LOGGER.trace("Outbound transports started successfully.") except Exception: - LOGGER.exception("Unable to start outbound transports") + LOGGER.exception("Unable to start outbound transports.") raise # Start up Admin server if self.admin_server: + LOGGER.trace("Admin server present. Starting admin server.") try: await self.admin_server.start() + LOGGER.debug("Admin server started successfully.") except Exception: - LOGGER.exception("Unable to start administration API") + LOGGER.exception("Unable to start administration API.") # Make admin responder available during message parsing # This allows webhooks to be called when a connection is marked active, # for example @@ -350,9 +357,11 @@ async def start(self) -> None: self.admin_server.outbound_message_router, ) context.injector.bind_instance(BaseResponder, responder) + LOGGER.trace("Admin responder bound to injector.") # Get agent label default_label = context.settings.get("default_label") + LOGGER.debug("Agent label: %s", default_label) if context.settings.get("transport.disabled"): LoggingConfigurator.print_banner( @@ -377,6 +386,7 @@ async def start(self) -> None: from_version_storage = None from_version = None agent_version = f"v{__version__}" + LOGGER.trace("Recording ACA-Py version in wallet if needed.") async with self.root_profile.session() as session: storage: BaseStorage = session.context.inject(BaseStorage) try: @@ -391,10 +401,16 @@ async def start(self) -> None: ) except StorageNotFoundError: LOGGER.warning("Wallet version storage record not found.") + from_version_config = self.root_profile.settings.get("upgrade.from_version") force_upgrade_flag = ( self.root_profile.settings.get("upgrade.force_upgrade") or False ) + LOGGER.trace( + "Force upgrade flag: %s, From version config: %s", + force_upgrade_flag, + from_version_config, + ) if force_upgrade_flag and from_version_config: if from_version_storage: @@ -406,8 +422,13 @@ async def start(self) -> None: from_version = from_version_storage else: from_version = from_version_config + LOGGER.trace( + "Determined from_version based on force_upgrade: %s", from_version + ) else: from_version = from_version_storage or from_version_config + LOGGER.trace("Determined from_version: %s", from_version) + if not from_version: LOGGER.warning( ( @@ -418,17 +439,27 @@ async def start(self) -> None: ) from_version = DEFAULT_ACAPY_VERSION self.root_profile.settings.set_value("upgrade.from_version", from_version) + LOGGER.trace("Set upgrade.from_version to default: %s", from_version) + config_available_list = get_upgrade_version_list( config_path=self.root_profile.settings.get("upgrade.config_path"), from_version=from_version, ) + LOGGER.trace("Available upgrade versions: %s", config_available_list) + if len(config_available_list) >= 1: + LOGGER.info("Upgrade configurations available. Initiating upgrade.") await upgrade(profile=self.root_profile) elif not (from_version_storage and from_version_storage == agent_version): + LOGGER.debug("No upgrades needed. Adding version record.") await add_version_record(profile=self.root_profile, version=agent_version) # Create a static connection for use by the test-suite if context.settings.get("debug.test_suite_endpoint"): + LOGGER.debug( + "Test suite endpoint configured. " + "Creating static connection for test suite." + ) mgr = ConnectionManager(self.root_profile) their_endpoint = context.settings["debug.test_suite_endpoint"] test_conn = await mgr.create_static_connection( @@ -444,26 +475,31 @@ async def start(self) -> None: f" - Their endpoint: {their_endpoint}\n" ) del mgr + LOGGER.debug("Static connection for test suite created and manager deleted.") # Clear default mediator if context.settings.get("mediation.clear"): + LOGGER.debug("Mediation clear flag set. Clearing default mediator.") mediation_mgr = MediationManager(self.root_profile) await mediation_mgr.clear_default_mediator() LOGGER.info("Default mediator cleared.") - # Clear default mediator # Set default mediator by id default_mediator_id = context.settings.get("mediation.default_id") if default_mediator_id: + LOGGER.debug("Setting default mediator to ID: %s", default_mediator_id) mediation_mgr = MediationManager(self.root_profile) try: await mediation_mgr.set_default_mediator_by_id(default_mediator_id) LOGGER.info(f"Default mediator set to {default_mediator_id}") except Exception: - LOGGER.exception("Error updating default mediator") + LOGGER.exception("Error updating default mediator.") # Print an invitation to the terminal if context.settings.get("debug.print_invitation"): + LOGGER.debug( + "Debug flag for printing invitation is set. Creating invitation." + ) try: mgr = OutOfBandManager(self.root_profile) invi_rec = await mgr.create_invitation( @@ -482,11 +518,16 @@ async def start(self) -> None: qr.add_data(invite_url) qr.print_ascii(invert=True) del mgr + LOGGER.trace("Invitation created and QR code printed.") except Exception: - LOGGER.exception("Error creating invitation") + LOGGER.exception("Error creating invitation.") # Print connections protocol invitation to the terminal if context.settings.get("debug.print_connections_invitation"): + LOGGER.debug( + "Debug flag for printing connections invitation is set. " + "Creating connections invitation." + ) try: mgr = ConnectionManager(self.root_profile) _record, invite = await mgr.create_invitation( @@ -504,11 +545,15 @@ async def start(self) -> None: qr.add_data(invite_url) qr.print_ascii(invert=True) del mgr + LOGGER.trace( + "Connections protocol invitation created and QR code printed." + ) except Exception: - LOGGER.exception("Error creating invitation") + LOGGER.exception("Error creating connections protocol invitation.") # mediation connection establishment provided_invite: str = context.settings.get("mediation.invite") + LOGGER.debug("Mediation invite provided: %s", provided_invite) try: async with self.root_profile.session() as session: @@ -516,16 +561,24 @@ async def start(self) -> None: mediation_invite_record = await invite_store.get_mediation_invite_record( provided_invite ) + LOGGER.debug("Mediation invite record retrieved successfully.") except Exception: - LOGGER.exception("Error retrieving mediator invitation") + LOGGER.exception("Error retrieving mediator invitation.") mediation_invite_record = None # Accept mediation invitation if one was specified or stored if mediation_invite_record is not None: + LOGGER.debug( + "Mediation invite record found. " + "Attempting to accept mediation invitation." + ) try: mediation_connections_invite = context.settings.get( "mediation.connections_invite", False ) + LOGGER.trace( + "Mediation connections invite flag: %s", mediation_connections_invite + ) invitation_handler = ( ConnectionInvitation if mediation_connections_invite @@ -533,8 +586,11 @@ async def start(self) -> None: ) if not mediation_invite_record.used: - # clear previous mediator configuration before establishing a - # new one + # clear previous mediator configuration before establishing a new one + LOGGER.trace( + "Mediation invite not used. " + "Clearing default mediator before accepting new invite." + ) await MediationManager(self.root_profile).clear_default_mediator() mgr = ( @@ -542,6 +598,7 @@ async def start(self) -> None: if mediation_connections_invite else OutOfBandManager(self.root_profile) ) + LOGGER.debug("Receiving mediation invitation.") record = await mgr.receive_invitation( invitation=invitation_handler.from_url( mediation_invite_record.invite @@ -552,6 +609,7 @@ async def start(self) -> None: await MediationInviteStore( session.context.inject(BaseStorage) ).mark_default_invite_as_used() + LOGGER.trace("Marked mediation invite as used.") await record.metadata_set( session, MediationManager.SEND_REQ_AFTER_CONNECTION, True @@ -559,48 +617,65 @@ async def start(self) -> None: await record.metadata_set( session, MediationManager.SET_TO_DEFAULT_ON_GRANTED, True ) + LOGGER.trace("Set mediation metadata after connection.") LOGGER.info("Attempting to connect to mediator...") del mgr + LOGGER.trace("Mediation manager deleted after setting up mediator.") except Exception: - LOGGER.exception("Error accepting mediation invitation") + LOGGER.exception("Error accepting mediation invitation.") try: + LOGGER.debug("Checking for wallet upgrades in progress.") await self.check_for_wallet_upgrades_in_progress() + LOGGER.debug("Wallet upgrades check completed.") except Exception: LOGGER.exception( - "An exception was caught while checking for wallet upgrades in progress" + "An exception was caught while checking for wallet upgrades in progress." ) # notify protocols of startup status + LOGGER.trace("Notifying protocols of startup status.") await self.root_profile.notify(STARTUP_EVENT_TOPIC, {}) + LOGGER.debug("Startup notification sent.") async def stop(self, timeout=1.0): """Stop the agent.""" + LOGGER.info("Stopping the Conductor agent.") # notify protocols that we are shutting down if self.root_profile: + LOGGER.debug("Notifying protocols of shutdown.") await self.root_profile.notify(SHUTDOWN_EVENT_TOPIC, {}) + LOGGER.debug("Shutdown notification sent.") shutdown = TaskQueue() if self.dispatcher: + LOGGER.trace("Initiating shutdown of dispatcher.") shutdown.run(self.dispatcher.complete()) if self.admin_server: + LOGGER.trace("Initiating shutdown of admin server.") shutdown.run(self.admin_server.stop()) if self.inbound_transport_manager: + LOGGER.trace("Initiating shutdown of inbound transport manager.") shutdown.run(self.inbound_transport_manager.stop()) if self.outbound_transport_manager: + LOGGER.trace("Initiating shutdown of outbound transport manager.") shutdown.run(self.outbound_transport_manager.stop()) if self.root_profile: # close multitenant profiles multitenant_mgr = self.context.inject_or(BaseMultitenantManager) if multitenant_mgr: + LOGGER.debug("Closing multitenant profiles.") for profile in multitenant_mgr.open_profiles: + LOGGER.trace("Closing profile: %s", profile.name) shutdown.run(profile.close()) - + LOGGER.debug("Closing root profile.") shutdown.run(self.root_profile.close()) + LOGGER.trace("Waiting for shutdown tasks to complete with timeout=%f.", timeout) await shutdown.complete(timeout) + LOGGER.info("Conductor agent stopped successfully.") def inbound_message_router( self, From 32bb6b4c8bdfbc92689f073e4df9faba18d5d339 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 16:03:20 +0200 Subject: [PATCH 42/72] :white_check_mark: Add unit tests for adding trace level functionality Signed-off-by: ff137 --- acapy_agent/config/tests/test_logging.py | 115 +++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/acapy_agent/config/tests/test_logging.py b/acapy_agent/config/tests/test_logging.py index cf23074568..5eb2294faa 100644 --- a/acapy_agent/config/tests/test_logging.py +++ b/acapy_agent/config/tests/test_logging.py @@ -1,9 +1,11 @@ import contextlib +import logging from io import BufferedReader, StringIO, TextIOWrapper from tempfile import NamedTemporaryFile from unittest import IsolatedAsyncioTestCase, mock from ..logging import configurator as test_module +from ..logging import utils class TestLoggingConfigurator(IsolatedAsyncioTestCase): @@ -162,3 +164,116 @@ def test_load_resource(self): mock_files.return_value.joinpath.assert_called_once_with("def") mock_resource_path.open.assert_called_once_with("rb") assert result == mock_resource_handle # Verify the returned binary stream + + +class TestLoggingUtils(IsolatedAsyncioTestCase): + def setUp(self): + # Backup existing logging attributes to restore after tests + self.original_levels = { + attr: getattr(logging, attr) for attr in dir(logging) if attr.isupper() + } + self.original_logger_methods = { + attr: getattr(logging.getLoggerClass(), attr, None) + for attr in dir(logging.getLoggerClass()) + if not attr.startswith("_") + } + # Reset TRACE level if it exists + if hasattr(logging, "TRACE"): + delattr(logging, "TRACE") + if hasattr(logging.getLoggerClass(), "trace"): + delattr(logging.getLoggerClass(), "trace") + # Ensure _TRACE_LEVEL_ADDED is False before each test + self._trace_level_added_patcher = mock.patch( + "acapy_agent.config.logging.utils._TRACE_LEVEL_ADDED", False + ) + self.mock_trace_level_added = self._trace_level_added_patcher.start() + + def tearDown(self): + # Restore original logging levels + for attr, value in self.original_levels.items(): + setattr(logging, attr, value) + # Restore original logger methods + for attr, method in self.original_logger_methods.items(): + if method is not None: + setattr(logging.getLoggerClass(), attr, method) + elif hasattr(logging.getLoggerClass(), attr): + delattr(logging.getLoggerClass(), attr) + # Remove TRACE if it was added during tests + if hasattr(logging, "TRACE"): + delattr(logging, "TRACE") + if hasattr(logging.getLoggerClass(), "trace"): + delattr(logging.getLoggerClass(), "trace") + # Stop patching _TRACE_LEVEL_ADDED + self._trace_level_added_patcher.stop() + + @mock.patch("acapy_agent.config.logging.utils.LOGGER") + @mock.patch("acapy_agent.config.logging.utils.logging.addLevelName") + def test_add_logging_level_success(self, mock_addLevelName, mock_logger): + utils.add_logging_level("CUSTOM", 2) + + mock_addLevelName.assert_called_once_with(2, "CUSTOM") + self.assertTrue(hasattr(logging, "CUSTOM")) + self.assertEqual(logging.CUSTOM, 2) + + logger = logging.getLogger(__name__) + self.assertTrue(hasattr(logger, "custom")) + self.assertTrue(callable(logger.custom)) + + self.assertTrue(hasattr(logging, "custom")) + self.assertTrue(callable(logging.custom)) + + def test_add_logging_level_existing_level_name(self): + # Add a level named 'DEBUG' which already exists + with self.assertRaises(AttributeError) as context: + utils.add_logging_level("DEBUG", 15) + self.assertIn("DEBUG already defined in logging module", str(context.exception)) + + def test_add_logging_level_existing_method_name(self): + # Add a logging method that already exists ('debug') + with self.assertRaises(AttributeError) as context: + utils.add_logging_level("CUSTOM", 25, method_name="debug") + self.assertIn("debug already defined in logging module", str(context.exception)) + + @mock.patch("acapy_agent.config.logging.utils.add_logging_level") + @mock.patch("acapy_agent.config.logging.utils.LOGGER") + def test_add_trace_level_new(self, mock_logger, mock_add_logging_level): + # Ensure _TRACE_LEVEL_ADDED is False + utils.add_trace_level() + + mock_add_logging_level.assert_called_once_with( + "TRACE", logging.DEBUG - 5, "trace" + ) + + # Verify logger.debug was called + mock_logger.debug.assert_called_with("%s level added to logging module.", "TRACE") + + # Check that _TRACE_LEVEL_ADDED is now True + self.assertTrue(utils._TRACE_LEVEL_ADDED) + + @mock.patch("acapy_agent.config.logging.utils.LOGGER") + @mock.patch( + "acapy_agent.config.logging.utils.add_logging_level", + side_effect=AttributeError("TRACE already exists"), + ) + def test_add_trace_level_already_exists_exception( + self, mock_add_logging_level, mock_logger + ): + utils.add_trace_level() + + # Verify logger.warning was called + mock_logger.warning.assert_called_with( + "%s level already exists: %s", "TRACE", mock_add_logging_level.side_effect + ) + + @mock.patch("acapy_agent.config.logging.utils.LOGGER") + @mock.patch("acapy_agent.config.logging.utils.add_logging_level") + def test_add_trace_level_already_present(self, mock_add_logging_level, mock_logger): + # Manually set _TRACE_LEVEL_ADDED to True to simulate already added TRACE level + with mock.patch("acapy_agent.config.logging.utils._TRACE_LEVEL_ADDED", True): + utils.add_trace_level() + + # add_logging_level should not be called since TRACE level is already added + mock_add_logging_level.assert_not_called() + + # Verify logger.debug was not called + mock_logger.debug.assert_not_called() From 9d0275adaf80cebc849693aa7015b4926445eb99 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 17:06:32 +0200 Subject: [PATCH 43/72] :white_check_mark: Reset the logging states before and after TestLoggingUtils is run Signed-off-by: ff137 --- acapy_agent/config/tests/test_logging.py | 53 +++++++++++++++--------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/acapy_agent/config/tests/test_logging.py b/acapy_agent/config/tests/test_logging.py index 5eb2294faa..9effb41c16 100644 --- a/acapy_agent/config/tests/test_logging.py +++ b/acapy_agent/config/tests/test_logging.py @@ -168,43 +168,58 @@ def test_load_resource(self): class TestLoggingUtils(IsolatedAsyncioTestCase): def setUp(self): - # Backup existing logging attributes to restore after tests + """Set up test environment by backing up logging states and resetting TRACE level.""" + # Backup existing logging attributes (e.g., DEBUG, INFO) self.original_levels = { attr: getattr(logging, attr) for attr in dir(logging) if attr.isupper() } + + # Backup existing logger class methods (e.g., debug, info) self.original_logger_methods = { attr: getattr(logging.getLoggerClass(), attr, None) for attr in dir(logging.getLoggerClass()) if not attr.startswith("_") } - # Reset TRACE level if it exists + + # Remove TRACE level and 'trace' method if they exist if hasattr(logging, "TRACE"): delattr(logging, "TRACE") if hasattr(logging.getLoggerClass(), "trace"): delattr(logging.getLoggerClass(), "trace") - # Ensure _TRACE_LEVEL_ADDED is False before each test - self._trace_level_added_patcher = mock.patch( + + # Patch the TRACE_LEVEL_ADDED flag to False before each test + self.trace_level_added_patcher = mock.patch( "acapy_agent.config.logging.utils._TRACE_LEVEL_ADDED", False ) - self.mock_trace_level_added = self._trace_level_added_patcher.start() + self.mock_trace_level_added = self.trace_level_added_patcher.start() def tearDown(self): - # Restore original logging levels + """Restore original logging states after each test.""" + # Stop patching TRACE_LEVEL_ADDED + self.trace_level_added_patcher.stop() + + # Restore original logging level attributes for attr, value in self.original_levels.items(): setattr(logging, attr, value) - # Restore original logger methods - for attr, method in self.original_logger_methods.items(): - if method is not None: - setattr(logging.getLoggerClass(), attr, method) - elif hasattr(logging.getLoggerClass(), attr): - delattr(logging.getLoggerClass(), attr) - # Remove TRACE if it was added during tests - if hasattr(logging, "TRACE"): - delattr(logging, "TRACE") - if hasattr(logging.getLoggerClass(), "trace"): - delattr(logging.getLoggerClass(), "trace") - # Stop patching _TRACE_LEVEL_ADDED - self._trace_level_added_patcher.stop() + + # Identify and remove any new uppercase attributes added during tests (e.g., TRACE) + current_levels = {attr for attr in dir(logging) if attr.isupper()} + for attr in current_levels - set(self.original_levels.keys()): + delattr(logging, attr) + + # Restore original logger class methods + LoggerClass = logging.getLoggerClass() + for attr, value in self.original_logger_methods.items(): + if value is not None: + setattr(LoggerClass, attr, value) + else: + if hasattr(LoggerClass, attr): + delattr(LoggerClass, attr) + + # Identify and remove any new logger methods added during tests (e.g., trace) + current_methods = {attr for attr in dir(LoggerClass) if not attr.startswith("_")} + for attr in current_methods - set(self.original_logger_methods.keys()): + delattr(LoggerClass, attr) @mock.patch("acapy_agent.config.logging.utils.LOGGER") @mock.patch("acapy_agent.config.logging.utils.logging.addLevelName") From a53b9492039c055e2936602d186f469b0f787719 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 17:17:42 +0200 Subject: [PATCH 44/72] :art: Signed-off-by: ff137 --- acapy_agent/commands/start.py | 2 +- acapy_agent/config/logging/utils.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/acapy_agent/commands/start.py b/acapy_agent/commands/start.py index ee256f1e4c..fb8652314c 100644 --- a/acapy_agent/commands/start.py +++ b/acapy_agent/commands/start.py @@ -31,7 +31,7 @@ async def start_app(conductor: Conductor): async def shutdown_app(conductor: Conductor): """Shut down.""" - LOGGER.warning("Shutting down") + LOGGER.info("Shutting down") await conductor.stop() diff --git a/acapy_agent/config/logging/utils.py b/acapy_agent/config/logging/utils.py index 5ee6108607..10092d261a 100644 --- a/acapy_agent/config/logging/utils.py +++ b/acapy_agent/config/logging/utils.py @@ -93,10 +93,8 @@ def add_trace_level() -> None: add_logging_level(TRACE_LEVEL_NAME, TRACE_LEVEL_NUM, TRACE_METHOD_NAME) LOGGER.debug("%s level added to logging module.", TRACE_LEVEL_NAME) except AttributeError as e: - # Log a warning if TRACE level already exists LOGGER.warning("%s level already exists: %s", TRACE_LEVEL_NAME, e) else: - # Optionally, you can log that TRACE level is already present LOGGER.debug( "%s level is already present in the logging module.", TRACE_LEVEL_NAME ) From e77cf3f764c0a935985b83e8cb206d06c7e57e7e Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 17:31:20 +0200 Subject: [PATCH 45/72] :test_tube: Debug log assertion test failing sporadically Filter the logs being read by module name, and add short sleep to allow log handlers to flush Signed-off-by: ff137 --- acapy_agent/core/tests/test_conductor.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acapy_agent/core/tests/test_conductor.py b/acapy_agent/core/tests/test_conductor.py index 9f8e783491..199e946060 100644 --- a/acapy_agent/core/tests/test_conductor.py +++ b/acapy_agent/core/tests/test_conductor.py @@ -1,3 +1,4 @@ +import asyncio from unittest import IsolatedAsyncioTestCase import pytest @@ -1209,7 +1210,9 @@ async def test_print_invite_connection(self): test_profile, DIDInfo("did", "verkey", metadata={}, method=SOV, key_type=ED25519), ), - ), self.assertLogs(level="INFO") as captured, mock.patch.object( + ), self.assertLogs( + "acapy_agent.core.conductor", level="INFO" + ) as captured, mock.patch.object( test_module, "OutboundTransportManager", autospec=True ) as mock_outbound_mgr: mock_outbound_mgr.return_value.registered_transports = { @@ -1219,6 +1222,7 @@ async def test_print_invite_connection(self): await conductor.start() await conductor.stop() + await asyncio.sleep(0.1) # Allow log handlers to flush value = captured.output assert any("http://localhost?oob=" in msg for msg in value) assert any("http://localhost?c_i=" in msg for msg in value) From 4f632404c486f1e1ee08738801b015b6d9785785 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 18:37:06 +0200 Subject: [PATCH 46/72] :white_check_mark: Modify log assertion to be more robust Signed-off-by: ff137 --- acapy_agent/core/tests/test_conductor.py | 45 +++++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/acapy_agent/core/tests/test_conductor.py b/acapy_agent/core/tests/test_conductor.py index 199e946060..e6e95a0cf8 100644 --- a/acapy_agent/core/tests/test_conductor.py +++ b/acapy_agent/core/tests/test_conductor.py @@ -1,5 +1,5 @@ -import asyncio from unittest import IsolatedAsyncioTestCase +from unittest.mock import call import pytest @@ -1203,6 +1203,18 @@ async def test_print_invite_connection(self): test_profile = await create_test_profile(None, await builder.build_context()) + # Define expected invitation URLs + expected_oob_url = "http://localhost?oob=test_oob_invite" + expected_ci_url = "http://localhost?c_i=test_ci_invite" + + # Mock the InvitationRecord returned by create_invitation for OOB + mock_oob_invitation = mock.MagicMock() + mock_oob_invitation.invitation.to_url.return_value = expected_oob_url + + # Mock the InvitationRecord returned by create_invitation for Connections Protocol + mock_ci_invitation = mock.MagicMock() + mock_ci_invitation.to_url.return_value = expected_ci_url + with mock.patch.object( test_module, "wallet_config", @@ -1210,22 +1222,37 @@ async def test_print_invite_connection(self): test_profile, DIDInfo("did", "verkey", metadata={}, method=SOV, key_type=ED25519), ), - ), self.assertLogs( - "acapy_agent.core.conductor", level="INFO" - ) as captured, mock.patch.object( + ), mock.patch.object( test_module, "OutboundTransportManager", autospec=True - ) as mock_outbound_mgr: + ) as mock_outbound_mgr, mock.patch.object( + test_module, "OutOfBandManager" + ) as oob_mgr, mock.patch.object( + test_module, "ConnectionManager" + ) as conn_mgr, mock.patch.object(test_module.LOGGER, "info") as mock_logger_info: mock_outbound_mgr.return_value.registered_transports = { "test": mock.MagicMock(schemes=["http"]) } + + # Configure create_invitation to return the mocked invitations + oob_mgr.return_value.create_invitation = mock.CoroutineMock( + return_value=mock_oob_invitation + ) + conn_mgr.return_value.create_invitation = mock.CoroutineMock( + return_value=(None, mock_ci_invitation) + ) + + # Execute the conductor lifecycle await conductor.setup() await conductor.start() await conductor.stop() - await asyncio.sleep(0.1) # Allow log handlers to flush - value = captured.output - assert any("http://localhost?oob=" in msg for msg in value) - assert any("http://localhost?c_i=" in msg for msg in value) + + # Assert that LOGGER.info was called twice with the expected URLs + expected_calls = [ + call(f"Invitation URL:\n{expected_oob_url}"), + call(f"Invitation URL (Connections protocol):\n{expected_ci_url}"), + ] + mock_logger_info.assert_has_calls(expected_calls, any_order=True) async def test_clear_default_mediator(self): builder: ContextBuilder = StubContextBuilder(self.test_settings) From 0ff9da49bd231fd788587a126e55b6205d39ec74 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 20:15:18 +0200 Subject: [PATCH 47/72] :art: Signed-off-by: ff137 --- acapy_agent/config/tests/test_logging.py | 4 ++-- acapy_agent/config/wallet.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/acapy_agent/config/tests/test_logging.py b/acapy_agent/config/tests/test_logging.py index 9effb41c16..446395003d 100644 --- a/acapy_agent/config/tests/test_logging.py +++ b/acapy_agent/config/tests/test_logging.py @@ -223,10 +223,10 @@ def tearDown(self): @mock.patch("acapy_agent.config.logging.utils.LOGGER") @mock.patch("acapy_agent.config.logging.utils.logging.addLevelName") - def test_add_logging_level_success(self, mock_addLevelName, mock_logger): + def test_add_logging_level_success(self, mock_add_level_name, mock_logger): utils.add_logging_level("CUSTOM", 2) - mock_addLevelName.assert_called_once_with(2, "CUSTOM") + mock_add_level_name.assert_called_once_with(2, "CUSTOM") self.assertTrue(hasattr(logging, "CUSTOM")) self.assertEqual(logging.CUSTOM, 2) diff --git a/acapy_agent/config/wallet.py b/acapy_agent/config/wallet.py index 89bfdad681..b19e202aa2 100644 --- a/acapy_agent/config/wallet.py +++ b/acapy_agent/config/wallet.py @@ -64,8 +64,8 @@ async def wallet_config( LOGGER.info("Created new profile") else: LOGGER.info("Opened existing profile") - LOGGER.info("Profile backend:", profile.backend) - LOGGER.info("Profile name:", profile.name) + LOGGER.info("Profile backend: %s", profile.backend) + LOGGER.info("Profile name: %s", profile.name) wallet_seed = context.settings.get("wallet.seed") wallet_local_did = context.settings.get("wallet.local_did") From 9058784f95b9ff905670f984fa351ef623b710ac Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 20:58:12 +0200 Subject: [PATCH 48/72] :bug: Handle case that load_module return type is Optional Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 6 +++++- acapy_agent/utils/classloader.py | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index f86495291e..47617a047d 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -309,7 +309,6 @@ async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> try: LOGGER.trace("Loading message types from: %s", version_path) mod = ClassLoader.load_module(version_path) - await self.load_protocol_version(context, mod, protocol_version) except ModuleLoadError as e: LOGGER.error( "Error loading plugin module message types from %s: %s", @@ -318,6 +317,11 @@ async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> ) return + if mod: + await self.load_protocol_version(context, mod, protocol_version) + else: + LOGGER.debug("Failed to load %s", version_path) + async def register_admin_routes(self, app) -> None: """Call route registration methods on the current context.""" LOGGER.trace("Registering admin routes for %d plugins", len(self._plugins)) diff --git a/acapy_agent/utils/classloader.py b/acapy_agent/utils/classloader.py index 29fd81bc4d..1eda57efbb 100644 --- a/acapy_agent/utils/classloader.py +++ b/acapy_agent/utils/classloader.py @@ -22,7 +22,9 @@ class ClassLoader: """Class used to load classes from modules dynamically.""" @classmethod - def load_module(cls, mod_path: str, package: Optional[str] = None) -> ModuleType: + def load_module( + cls, mod_path: str, package: Optional[str] = None + ) -> Optional[ModuleType]: """Load a module by its absolute path. Args: From ebfbaafe71f5772eadd120f3fcf1619ea0a2fb01 Mon Sep 17 00:00:00 2001 From: ff137 Date: Thu, 7 Nov 2024 21:37:52 +0200 Subject: [PATCH 49/72] :loud_sound: Expand logging for ClassLoader Signed-off-by: ff137 --- acapy_agent/utils/classloader.py | 88 ++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/acapy_agent/utils/classloader.py b/acapy_agent/utils/classloader.py index 1eda57efbb..1a6684fdcb 100644 --- a/acapy_agent/utils/classloader.py +++ b/acapy_agent/utils/classloader.py @@ -1,6 +1,7 @@ """The classloader provides utilities to dynamically load classes and modules.""" import inspect +import logging import sys from importlib import import_module, resources from importlib.util import find_spec, resolve_name @@ -9,6 +10,8 @@ from ..core.error import BaseError +LOGGER = logging.getLogger(__name__) + class ModuleLoadError(BaseError): """Module load error.""" @@ -38,36 +41,52 @@ def load_module( ModuleLoadError: If there was an error loading the module """ + LOGGER.trace("Attempting to load module: %s with package: %s", mod_path, package) + if package: + LOGGER.trace("Preloading parent package: %s", package) # preload parent package if not cls.load_module(package): + LOGGER.trace("Failed to preload parent package: %s", package) return None # must treat as a relative import if not mod_path.startswith("."): mod_path = f".{mod_path}" + LOGGER.trace("Adjusted mod_path for relative import: %s", mod_path) full_path = resolve_name(mod_path, package) + LOGGER.trace("Resolved full module path: %s", full_path) + if full_path in sys.modules: + LOGGER.trace("Module %s is already loaded", full_path) return sys.modules[full_path] if "." in mod_path: parent_mod_path, mod_name = mod_path.rsplit(".", 1) + LOGGER.trace( + "Parent module path: %s, Module name: %s", parent_mod_path, mod_name + ) if parent_mod_path and parent_mod_path[-1] != ".": parent_mod = cls.load_module(parent_mod_path, package) if not parent_mod: + LOGGER.trace("Failed to load parent module: %s", parent_mod_path) return None package = parent_mod.__name__ mod_path = f".{mod_name}" + LOGGER.trace("Adjusted mod_path after loading parent: %s", mod_path) # Load the module spec first - # this means that a later ModuleNotFoundError indicates a code issue + LOGGER.trace("Finding spec for module: %s with package: %s", mod_path, package) spec = find_spec(mod_path, package) if not spec: + LOGGER.trace("Module spec not found for: %s", mod_path) return None try: + LOGGER.trace("Importing module: %s with package: %s", mod_path, package) return import_module(mod_path, package) except ModuleNotFoundError as e: + LOGGER.warning("Module %s not found during import", full_path) raise ModuleLoadError(f"Unable to import module {full_path}: {str(e)}") from e @classmethod @@ -93,29 +112,53 @@ def load_class( """ + LOGGER.trace( + "Attempting to load class: %s with default_module: %s and package: %s", + class_name, + default_module, + package, + ) + if "." in class_name: # import module and find class mod_path, class_name = class_name.rsplit(".", 1) + LOGGER.trace( + "Extracted module path: %s, class name: %s from full class path", + mod_path, + class_name, + ) elif default_module: mod_path = default_module + LOGGER.trace("No module in class name, using default_module: %s", mod_path) else: + LOGGER.warning( + "Cannot resolve class name %s with no default module", class_name + ) raise ClassNotFoundError( f"Cannot resolve class name with no default module: {class_name}" ) mod = cls.load_module(mod_path, package) if not mod: - raise ClassNotFoundError(f"Module '{mod_path}' not found") + LOGGER.warning( + "Module %s not found when loading class %s", mod_path, class_name + ) + raise ClassNotFoundError(f"Module {mod_path} not found") resolved = getattr(mod, class_name, None) if not resolved: + LOGGER.warning("Class %s not found in module %s", class_name, mod_path) raise ClassNotFoundError( f"Class '{class_name}' not defined in module: {mod_path}" ) if not isinstance(resolved, type): + LOGGER.warning( + "Resolved attribute %s in module %s is not a class", class_name, mod_path + ) raise ClassNotFoundError( f"Resolved value is not a class: {mod_path}.{class_name}" ) + LOGGER.trace("Successfully loaded class %s from module %s", class_name, mod_path) return resolved @classmethod @@ -138,18 +181,45 @@ def load_subclass_of( """ + LOGGER.trace( + "Attempting to load subclass of %s from module %s with package %s", + base_class.__name__, + mod_path, + package, + ) + mod = cls.load_module(mod_path, package) if not mod: + LOGGER.warning( + "Module %s not found when loading subclass of %s", + mod_path, + base_class.__name__, + ) raise ClassNotFoundError(f"Module '{mod_path}' not found") - # Find an the first declared class that inherits from + # Find the first declared class that inherits from the base_class try: + LOGGER.trace( + "Inspecting classes in module %s for subclasses of %s", + mod_path, + base_class.__name__, + ) imported_class = next( obj for name, obj in inspect.getmembers(mod, inspect.isclass) if issubclass(obj, base_class) and obj is not base_class ) + LOGGER.trace( + "Found subclass %s of base class %s", + imported_class.__name__, + base_class.__name__, + ) except StopIteration: + LOGGER.trace( + "No subclass of %s found in module %s", + base_class.__name__, + mod_path, + ) raise ClassNotFoundError( f"Could not resolve a class that inherits from {base_class}" ) from None @@ -158,25 +228,35 @@ def load_subclass_of( @classmethod def scan_subpackages(cls, package: str) -> Sequence[str]: """Return a list of sub-packages defined under a named package.""" + LOGGER.debug("Scanning subpackages under package %s", package) if "." in package: package, sub_pkg = package.split(".", 1) + LOGGER.trace("Extracted main package: %s, sub-package: %s", package, sub_pkg) else: sub_pkg = "." + LOGGER.trace("No sub-package provided, defaulting to %s", sub_pkg) try: package_path = resources.files(package) + LOGGER.trace("Found package path: %s", package_path) except FileNotFoundError: + LOGGER.warning("Package %s not found during subpackage scan", package) raise ModuleLoadError(f"Undefined package {package}") if not (package_path / sub_pkg).is_dir(): + LOGGER.warning("Sub-package %s is not a directory under %s", sub_pkg, package) raise ModuleLoadError(f"Undefined package {package}") found = [] joiner = "" if sub_pkg == "." else f"{sub_pkg}." sub_path = package_path / sub_pkg + LOGGER.trace("Iterating over items in sub-package path: %s", sub_path) for item in sub_path.iterdir(): if (item / "__init__.py").exists(): - found.append(f"{package}.{joiner}{item.name}") + subpackage = f"{package}.{joiner}{item.name}" + found.append(subpackage) + LOGGER.trace("Found sub-package: %s", subpackage) + LOGGER.debug("Total sub-packages found under %s: %s", package, found) return found From 431290535434b61fd6b86ade364ebdf9603605d6 Mon Sep 17 00:00:00 2001 From: ff137 Date: Mon, 11 Nov 2024 10:22:16 +0200 Subject: [PATCH 50/72] :loud_sound: Log a warning if resource not found, instead of passing Signed-off-by: ff137 --- acapy_agent/config/logging/configurator.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acapy_agent/config/logging/configurator.py b/acapy_agent/config/logging/configurator.py index 8843ed78e2..5eec80999c 100644 --- a/acapy_agent/config/logging/configurator.py +++ b/acapy_agent/config/logging/configurator.py @@ -34,6 +34,8 @@ from .utils import add_trace_level +LOGGER = logging.getLogger(__name__) + # Add TRACE level to logging before any configuration add_trace_level() @@ -62,7 +64,8 @@ def load_resource(path: str, encoding: Optional[str] = None): return io.TextIOWrapper(bstream, encoding=encoding) return bstream except IOError: - pass + LOGGER.warning("Resource not found: %s", path) + return None def dictConfig(config, new_file_path=None): From 9d347bb6a314de259dbfeff7e1c0bc33c7234f43 Mon Sep 17 00:00:00 2001 From: ff137 Date: Mon, 11 Nov 2024 10:22:45 +0200 Subject: [PATCH 51/72] :art: Signed-off-by: ff137 --- acapy_agent/config/logging/configurator.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/acapy_agent/config/logging/configurator.py b/acapy_agent/config/logging/configurator.py index 5eec80999c..fb9e2cb347 100644 --- a/acapy_agent/config/logging/configurator.py +++ b/acapy_agent/config/logging/configurator.py @@ -103,18 +103,7 @@ def fileConfig( raise RuntimeError(f"{fname} is invalid: {e}") if new_file_path and cp.has_section("handler_timed_file_handler"): - cp.set( - "handler_timed_file_handler", - "args", - str( - ( - f"{new_file_path}", - "d", - 7, - 1, - ) - ), - ) + cp.set("handler_timed_file_handler", "args", str((new_file_path, "d", 7, 1))) formatters = _create_formatters(cp) with logging._lock: From 06ceea91b75c50e05854089d70449ccfbf4bf7c4 Mon Sep 17 00:00:00 2001 From: ff137 Date: Mon, 11 Nov 2024 10:53:30 +0200 Subject: [PATCH 52/72] :art: Enable trace logs for remaining modules Signed-off-by: ff137 --- acapy_agent/core/conductor.py | 3 +++ acapy_agent/utils/classloader.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index 5cf6bf1811..c949cca782 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -27,6 +27,7 @@ load_multiple_genesis_transactions_from_config, ) from ..config.logging import LoggingConfigurator +from ..config.logging.utils import add_trace_level from ..config.provider import ClassProvider from ..config.wallet import wallet_config from ..core.profile import Profile @@ -82,6 +83,8 @@ from .util import SHUTDOWN_EVENT_TOPIC, STARTUP_EVENT_TOPIC LOGGER = logging.getLogger(__name__) +add_trace_level() # Allow trace logs from this module + # Refer ACA-Py issue #2197 # When the from version is not found DEFAULT_ACAPY_VERSION = "v0.7.5" diff --git a/acapy_agent/utils/classloader.py b/acapy_agent/utils/classloader.py index 1a6684fdcb..e257abdb3a 100644 --- a/acapy_agent/utils/classloader.py +++ b/acapy_agent/utils/classloader.py @@ -8,9 +8,11 @@ from types import ModuleType from typing import Optional, Sequence, Type +from ..config.logging.utils import add_trace_level from ..core.error import BaseError LOGGER = logging.getLogger(__name__) +add_trace_level() # Allow trace logs from this module class ModuleLoadError(BaseError): From 838adcdb9c7ee29940df6f43400bbb459c09ec53 Mon Sep 17 00:00:00 2001 From: ff137 Date: Tue, 12 Nov 2024 11:04:16 +0200 Subject: [PATCH 53/72] :bug: Fix registering and loading of modules Signed-off-by: ff137 --- acapy_agent/core/plugin_registry.py | 30 ++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 47617a047d..542203c819 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -344,6 +344,10 @@ async def register_admin_routes(self, app) -> None: "Error loading admin routes from %s: %s", version_path, e ) continue + + if mod and hasattr(mod, "register"): + LOGGER.trace("Registering routes for: %s", plugin_name) + await mod.register(app) else: # Load plugin routes that aren't in a versioned package. routes_path = f"{plugin_name}.routes" @@ -354,9 +358,9 @@ async def register_admin_routes(self, app) -> None: LOGGER.error("Error loading admin routes from %s: %s", routes_path, e) continue - if mod and hasattr(mod, "register"): - LOGGER.trace("Registering routes for: %s", plugin_name) - await mod.register(app) + if mod and hasattr(mod, "register"): + LOGGER.trace("Registering routes for: %s", plugin_name) + await mod.register(app) def register_protocol_events(self, context: InjectionContext) -> None: """Call route register_events methods on the current context.""" @@ -383,6 +387,10 @@ def register_protocol_events(self, context: InjectionContext) -> None: except ModuleLoadError as e: LOGGER.error("Error loading events from %s: %s", version_path, e) continue + + if mod and hasattr(mod, "register_events"): + LOGGER.trace("Registering events from: %s", version_path) + mod.register_events(event_bus) else: # Load plugin routes that aren't in a versioned package. routes_path = f"{plugin_name}.routes" @@ -393,9 +401,9 @@ def register_protocol_events(self, context: InjectionContext) -> None: LOGGER.error("Error loading events from %s: %s", routes_path, e) continue - if mod and hasattr(mod, "register_events"): - LOGGER.trace("Registering events from: %s", version_path) - mod.register_events(event_bus) + if mod and hasattr(mod, "register_events"): + LOGGER.trace("Registering events from: %s", version_path) + mod.register_events(event_bus) def post_process_routes(self, app) -> None: """Call route binary file response OpenAPI fixups if applicable.""" @@ -417,6 +425,10 @@ def post_process_routes(self, app) -> None: except ModuleLoadError as e: LOGGER.error("Error loading routes from %s: %s", version_path, e) continue + + if mod and hasattr(mod, "post_process_routes"): + LOGGER.trace("Post-processing routes for %s", plugin_name) + mod.post_process_routes(app) else: # Set binary file responses for routes not in a versioned package. routes_path = f"{plugin_name}.routes" @@ -427,9 +439,9 @@ def post_process_routes(self, app) -> None: LOGGER.error("Error loading routes from %s: %s", routes_path, e) continue - if mod and hasattr(mod, "post_process_routes"): - LOGGER.trace("Post-processing routes for %s", plugin_name) - mod.post_process_routes(app) + if mod and hasattr(mod, "post_process_routes"): + LOGGER.trace("Post-processing routes for %s", plugin_name) + mod.post_process_routes(app) def __repr__(self) -> str: """Return a string representation for this class.""" From f34264676ad5e6bc09467b05f37f67166d0d58ae Mon Sep 17 00:00:00 2001 From: ff137 Date: Tue, 12 Nov 2024 13:01:19 +0200 Subject: [PATCH 54/72] :loud_sound: Expand logging for Ledger Configuration Signed-off-by: ff137 --- acapy_agent/config/ledger.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/acapy_agent/config/ledger.py b/acapy_agent/config/ledger.py index 7d7acb1e7e..ab335913b9 100644 --- a/acapy_agent/config/ledger.py +++ b/acapy_agent/config/ledger.py @@ -34,14 +34,18 @@ async def fetch_genesis_transactions(genesis_url: str) -> str: # https://github.com/openwallet-foundation/acapy/issues/1745 return await fetch(genesis_url, headers=headers, max_attempts=20) except FetchError as e: + LOGGER.error("Error retrieving genesis transactions from %s: %s", genesis_url, e) raise ConfigError("Error retrieving ledger genesis transactions") from e async def get_genesis_transactions(settings: Settings) -> str: """Fetch genesis transactions if necessary.""" + LOGGER.debug("Getting genesis transactions from settings") txns = settings.get("ledger.genesis_transactions") + LOGGER.debug("Genesis transactions from settings: %s", "found" if txns else "absent") if not txns: + LOGGER.debug("No genesis transactions found in settings") if settings.get("ledger.genesis_url"): txns = await fetch_genesis_transactions(settings["ledger.genesis_url"]) elif settings.get("ledger.genesis_file"): @@ -51,8 +55,10 @@ async def get_genesis_transactions(settings: Settings) -> str: with open(genesis_path, "r") as genesis_file: txns = genesis_file.read() except IOError as e: + LOGGER.error("Failed to read genesis file: %s", str(e)) raise ConfigError("Error reading ledger genesis transactions") from e if txns: + LOGGER.debug("Storing genesis transactions in settings") settings["ledger.genesis_transactions"] = txns return txns @@ -63,6 +69,8 @@ async def load_multiple_genesis_transactions_from_config(settings: Settings): ledger_config_list = settings.get("ledger.ledger_config_list") ledger_txns_list = [] write_ledger_set = False + LOGGER.debug("Processing %d ledger configs", len(ledger_config_list)) + for config in ledger_config_list: txns = None if "genesis_transactions" in config: @@ -74,11 +82,12 @@ async def load_multiple_genesis_transactions_from_config(settings: Settings): try: genesis_path = config.get("genesis_file") LOGGER.info( - "Reading ledger genesis transactions from: %s", genesis_path + "Reading ledger genesis transactions from file: %s", genesis_path ) with open(genesis_path, "r") as genesis_file: txns = genesis_file.read() except IOError as e: + LOGGER.error("Failed to read genesis file: %s", str(e)) raise ConfigError("Error reading ledger genesis transactions") from e is_write_ledger = ( False if config.get("is_write") is None else config.get("is_write") @@ -119,6 +128,7 @@ async def load_multiple_genesis_transactions_from_config(settings: Settings): " genesis_file and genesis_transactions provided." ) settings["ledger.ledger_config_list"] = ledger_txns_list + LOGGER.debug("Processed %d ledger configs successfully", len(ledger_txns_list)) async def ledger_config( @@ -126,6 +136,10 @@ async def ledger_config( ) -> bool: """Perform Indy ledger configuration.""" + LOGGER.debug( + "Configuring ledger for profile %s and public_did %s", profile.name, public_did + ) + session = await profile.session() ledger = session.inject_or(BaseLedger) @@ -136,32 +150,46 @@ async def ledger_config( async with ledger: # Check transaction author agreement acceptance if not ledger.read_only: + LOGGER.debug("Checking transaction author agreement") taa_info = await ledger.get_txn_author_agreement() if taa_info["taa_required"] and public_did: + LOGGER.debug("TAA acceptance required") taa_accepted = await ledger.get_latest_txn_author_acceptance() if ( not taa_accepted or taa_info["taa_record"]["digest"] != taa_accepted["digest"] ): + LOGGER.info("TAA acceptance needed - performing acceptance") if not await accept_taa(ledger, profile, taa_info, provision): + LOGGER.warning("TAA acceptance failed") return False + LOGGER.info("TAA acceptance completed") # Publish endpoints if necessary - skipped if TAA is required but not accepted endpoint = session.settings.get("default_endpoint") if public_did: wallet = session.inject(BaseWallet) try: + LOGGER.debug("Setting DID endpoint to: %s", endpoint) await wallet.set_did_endpoint(public_did, endpoint, ledger) except LedgerError as x_ledger: + LOGGER.error("Error setting DID endpoint: %s", x_ledger.message) raise ConfigError(x_ledger.message) from x_ledger # e.g., read-only # Publish profile endpoint if ledger is NOT read-only profile_endpoint = session.settings.get("profile_endpoint") if profile_endpoint and not ledger.read_only: + LOGGER.debug( + "Publishing profile endpoint: %s for DID: %s", + profile_endpoint, + public_did, + ) await ledger.update_endpoint_for_did( public_did, profile_endpoint, EndpointType.PROFILE ) + LOGGER.info("Profile endpoint published successfully") + LOGGER.info("Ledger configuration complete") return True From 5ec73ac6dd99215f29c9b77ac700657f1a5a932c Mon Sep 17 00:00:00 2001 From: jamshale Date: Thu, 21 Nov 2024 19:18:54 +0000 Subject: [PATCH 55/72] Fix tails upload for anoncreds multitenancy Signed-off-by: jamshale --- acapy_agent/anoncreds/revocation.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/acapy_agent/anoncreds/revocation.py b/acapy_agent/anoncreds/revocation.py index 56b19d222d..96d2795246 100644 --- a/acapy_agent/anoncreds/revocation.py +++ b/acapy_agent/anoncreds/revocation.py @@ -32,6 +32,8 @@ from ..core.error import BaseError from ..core.event_bus import Event, EventBus from ..core.profile import Profile, ProfileSession +from ..multitenant.base import BaseMultitenantManager +from ..tails.anoncreds_tails_server import AnonCredsTailsServer from ..tails.base import BaseTailsServer from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG from .events import RevListFinishedEvent, RevRegDefFinishedEvent @@ -694,7 +696,12 @@ def get_local_tails_path(self, rev_reg_def: RevRegDef) -> str: async def upload_tails_file(self, rev_reg_def: RevRegDef): """Upload the local tails file to the tails server.""" - tails_server = self.profile.inject_or(BaseTailsServer) + multitenant_mgr = self.profile.inject_or(BaseMultitenantManager) + if multitenant_mgr: + tails_server = AnonCredsTailsServer() + else: + tails_server = self.profile.inject_or(BaseTailsServer) + if not tails_server: raise AnonCredsRevocationError("Tails server not configured") if not Path(self.get_local_tails_path(rev_reg_def)).is_file(): From 8a3ad2e6e63827cae0dc83cfa0272135336f090b Mon Sep 17 00:00:00 2001 From: jamshale Date: Thu, 21 Nov 2024 20:35:26 +0000 Subject: [PATCH 56/72] Update unit test Signed-off-by: jamshale --- .../anoncreds/tests/test_revocation.py | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/acapy_agent/anoncreds/tests/test_revocation.py b/acapy_agent/anoncreds/tests/test_revocation.py index 5de4ef368e..4faf33429f 100644 --- a/acapy_agent/anoncreds/tests/test_revocation.py +++ b/acapy_agent/anoncreds/tests/test_revocation.py @@ -836,21 +836,40 @@ def test_generate_public_tails_uri(self): async def test_upload_tails_file(self): self.profile.inject_or = mock.Mock( - return_value=mock.MagicMock( - upload_tails_file=mock.CoroutineMock( - side_effect=[ - (True, "http://tails-server.com"), - (None, "http://tails-server.com"), - (True, "not-http://tails-server.com"), - ] - ) - ) + side_effect=[ + None, + mock.MagicMock( + upload_tails_file=mock.CoroutineMock( + return_value=(True, "http://tails-server.com") + ) + ), + ] ) # valid await self.revocation.upload_tails_file(rev_reg_def) # upload fails + self.profile.inject_or = mock.Mock( + side_effect=[ + None, + mock.MagicMock( + upload_tails_file=mock.CoroutineMock( + return_value=(None, "http://tails-server.com"), + ) + ), + ] + ) with self.assertRaises(test_module.AnonCredsRevocationError): await self.revocation.upload_tails_file(rev_reg_def) + self.profile.inject_or = mock.Mock( + side_effect=[ + None, + mock.MagicMock( + upload_tails_file=mock.CoroutineMock( + return_value=(True, "not-http://tails-server.com"), + ) + ), + ] + ) # tails location does not match with self.assertRaises(test_module.AnonCredsRevocationError): await self.revocation.upload_tails_file(rev_reg_def) From 8e704bbe7de4d987ed69cb818ee4654a6d10c2b8 Mon Sep 17 00:00:00 2001 From: jamshale Date: Thu, 21 Nov 2024 21:49:26 +0000 Subject: [PATCH 57/72] Make sonarcloud happy with https in test Signed-off-by: jamshale --- acapy_agent/anoncreds/tests/test_revocation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acapy_agent/anoncreds/tests/test_revocation.py b/acapy_agent/anoncreds/tests/test_revocation.py index 4faf33429f..ff9ed6d09f 100644 --- a/acapy_agent/anoncreds/tests/test_revocation.py +++ b/acapy_agent/anoncreds/tests/test_revocation.py @@ -48,7 +48,7 @@ "accum_key": {"z": "1 0BB...386"}, }, tails_hash="58NNWYnVxVFzAfUztwGSNBL4551XNq6nXk56pCiKJxxt", - tails_location="http://tails-server.com", + tails_location="https://tails-server.com", ), issuer_id="CsQY9MGeD3CQP4EyuVFo5m", type="CL_ACCUM", @@ -840,7 +840,7 @@ async def test_upload_tails_file(self): None, mock.MagicMock( upload_tails_file=mock.CoroutineMock( - return_value=(True, "http://tails-server.com") + return_value=(True, "https://tails-server.com") ) ), ] @@ -853,7 +853,7 @@ async def test_upload_tails_file(self): None, mock.MagicMock( upload_tails_file=mock.CoroutineMock( - return_value=(None, "http://tails-server.com"), + return_value=(None, "https://tails-server.com"), ) ), ] From a00b5f5c98a13dfa756500141f164a14d0d17217 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:11:42 -0800 Subject: [PATCH 58/72] Add anoncreds issuance and presentation format (#3331) * Add anoncreds issuance and presentation formats Signed-off-by: jamshale * Fix unit tests Signed-off-by: jamshale * Fix error in _formats_attach Signed-off-by: jamshale * Fix AnoncredsDID validation pattern Signed-off-by: jamshale * Fix name Signed-off-by: jamshale * Fix scenario test Signed-off-by: jamshale * Update demo with anoncreds format Signed-off-by: jamshale * Fix the scenario test and add better description Signed-off-by: jamshale * Add service_healthy check for indy agent Signed-off-by: jamshale * Fix/update BDD tests Signed-off-by: jamshale * Add issuer askar to holder anoncreds support Signed-off-by: jamshale * Update BDD tests Signed-off-by: jamshale * Remove commented code Signed-off-by: jamshale * Expand scenario test Signed-off-by: jamshale * Add better comments for format compatibilty imports Signed-off-by: jamshale * Add anocnreds compatibilty bdd test to PR workflow Signed-off-by: jamshale --------- Signed-off-by: jamshale --- acapy_agent/anoncreds/base.py | 6 +- .../anoncreds/default/did_indy/registry.py | 6 +- .../anoncreds/default/did_web/registry.py | 6 +- .../anoncreds/default/legacy_indy/recover.py | 2 +- .../anoncreds/default/legacy_indy/registry.py | 6 +- .../default/legacy_indy/tests/test_recover.py | 5 +- .../legacy_indy/tests/test_registry.py | 34 +- acapy_agent/anoncreds/events.py | 2 +- acapy_agent/anoncreds/holder.py | 4 +- acapy_agent/anoncreds/issuer.py | 4 +- acapy_agent/anoncreds/models/credential.py | 167 ++++ ...s_cred_def.py => credential_definition.py} | 14 +- .../anoncreds/models/credential_offer.py | 149 ++++ .../anoncreds/models/credential_proposal.py | 58 ++ .../anoncreds/models/credential_request.py | 81 ++ .../anoncreds/models/non_rev_interval.py | 78 ++ acapy_agent/anoncreds/models/predicate.py | 82 ++ .../anoncreds/models/presentation_request.py | 306 +++++++ acapy_agent/anoncreds/models/proof.py | 749 ++++++++++++++++++ .../anoncreds/models/requested_credentials.py | 47 ++ ...{anoncreds_revocation.py => revocation.py} | 29 +- .../models/{anoncreds_schema.py => schema.py} | 14 +- acapy_agent/anoncreds/models/utils.py | 99 +++ acapy_agent/anoncreds/registry.py | 6 +- acapy_agent/anoncreds/revocation.py | 5 +- acapy_agent/anoncreds/routes.py | 47 +- acapy_agent/anoncreds/tests/test_holder.py | 4 +- acapy_agent/anoncreds/tests/test_issuer.py | 4 +- .../anoncreds/tests/test_revocation.py | 6 +- .../anoncreds/tests/test_revocation_setup.py | 2 +- acapy_agent/anoncreds/tests/test_routes.py | 2 +- acapy_agent/anoncreds/tests/test_verifier.py | 6 +- acapy_agent/anoncreds/verifier.py | 16 +- acapy_agent/connections/models/conn_record.py | 8 +- .../connections/models/connection_target.py | 16 +- acapy_agent/indy/models/cred_def.py | 8 +- acapy_agent/indy/models/pres_preview.py | 8 +- acapy_agent/indy/models/proof_request.py | 16 +- acapy_agent/indy/models/revocation.py | 12 +- acapy_agent/indy/models/schema.py | 15 +- acapy_agent/ledger/routes.py | 12 +- .../messaging/credential_definitions/util.py | 11 +- .../messaging/decorators/attach_decorator.py | 8 +- .../messaging/decorators/service_decorator.py | 13 +- .../decorators/signature_decorator.py | 12 +- .../messaging/decorators/timing_decorator.py | 22 +- acapy_agent/messaging/models/base_record.py | 10 +- acapy_agent/messaging/schemas/routes.py | 11 +- acapy_agent/messaging/schemas/util.py | 11 +- acapy_agent/messaging/tests/test_valid.py | 56 +- acapy_agent/messaging/valid.py | 116 ++- .../v1_0/messages/basicmessage.py | 8 +- .../v1_0/messages/connection_invitation.py | 12 +- .../protocols/connections/v1_0/routes.py | 24 +- .../v1_0/messages/credential_proposal.py | 8 +- .../protocols/issue_credential/v1_0/routes.py | 18 +- .../v2_0/formats/anoncreds/handler.py | 171 ++-- .../formats/anoncreds/tests/test_handler.py | 161 ++-- .../v2_0/formats/indy/handler.py | 98 +-- .../ld_proof/models/cred_detail_options.py | 8 +- .../v2_0/formats/vc_di/tests/test_handler.py | 4 +- .../issue_credential/v2_0/manager.py | 10 +- .../issue_credential/v2_0/message_types.py | 4 + .../v2_0/messages/cred_format.py | 30 +- .../v2_0/models/detail/anoncreds.py | 131 +++ .../protocols/issue_credential/v2_0/routes.py | 71 +- .../v2_0/tests/test_routes.py | 24 +- .../anoncreds/pres_exch_handler.py | 40 +- .../present_proof/indy/pres_exch_handler.py | 7 + .../present_proof/v1_0/tests/test_routes.py | 6 +- .../v2_0/formats/anoncreds/handler.py | 98 ++- .../present_proof/v2_0/formats/handler.py | 2 +- .../v2_0/formats/indy/handler.py | 23 +- .../present_proof/v2_0/message_types.py | 3 + .../v2_0/messages/pres_format.py | 20 +- .../protocols/present_proof/v2_0/routes.py | 64 +- .../v2_0/tests/test_manager_anoncreds.py | 446 ++++++----- .../present_proof/v2_0/tests/test_routes.py | 6 +- .../v2_0/tests/test_routes_anoncreds.py | 6 +- acapy_agent/revocation_anoncreds/routes.py | 2 +- .../revocation_anoncreds/tests/test_routes.py | 2 +- .../vc/vc_ld/models/linked_data_proof.py | 8 +- acapy_agent/vc/vc_ld/models/options.py | 8 +- acapy_agent/wallet/anoncreds_upgrade.py | 6 +- acapy_agent/wallet/routes.py | 15 +- demo/bdd_support/agent_backchannel_client.py | 4 + demo/features/0453-issue-credential.feature | 2 +- demo/features/steps/0453-issue-credential.py | 5 +- demo/features/steps/0454-present-proof.py | 11 +- demo/features/steps/0586-sign-transaction.py | 34 +- demo/features/upgrade.feature | 3 - demo/runners/agent_container.py | 132 ++- demo/runners/faber.py | 109 ++- demo/runners/support/agent.py | 3 +- .../docker-compose.yml | 61 +- .../example.py | 647 +++++++++++++-- 96 files changed, 3917 insertions(+), 1049 deletions(-) create mode 100644 acapy_agent/anoncreds/models/credential.py rename acapy_agent/anoncreds/models/{anoncreds_cred_def.py => credential_definition.py} (97%) create mode 100644 acapy_agent/anoncreds/models/credential_offer.py create mode 100644 acapy_agent/anoncreds/models/credential_proposal.py create mode 100644 acapy_agent/anoncreds/models/credential_request.py create mode 100644 acapy_agent/anoncreds/models/non_rev_interval.py create mode 100644 acapy_agent/anoncreds/models/predicate.py create mode 100644 acapy_agent/anoncreds/models/presentation_request.py create mode 100644 acapy_agent/anoncreds/models/proof.py create mode 100644 acapy_agent/anoncreds/models/requested_credentials.py rename acapy_agent/anoncreds/models/{anoncreds_revocation.py => revocation.py} (96%) rename acapy_agent/anoncreds/models/{anoncreds_schema.py => schema.py} (95%) create mode 100644 acapy_agent/anoncreds/models/utils.py create mode 100644 acapy_agent/protocols/issue_credential/v2_0/models/detail/anoncreds.py diff --git a/acapy_agent/anoncreds/base.py b/acapy_agent/anoncreds/base.py index 6cb5940bb2..32c0a1c1f1 100644 --- a/acapy_agent/anoncreds/base.py +++ b/acapy_agent/anoncreds/base.py @@ -6,8 +6,8 @@ from ..config.injection_context import InjectionContext from ..core.error import BaseError from ..core.profile import Profile -from .models.anoncreds_cred_def import CredDef, CredDefResult, GetCredDefResult -from .models.anoncreds_revocation import ( +from .models.credential_definition import CredDef, CredDefResult, GetCredDefResult +from .models.revocation import ( GetRevListResult, GetRevRegDefResult, RevList, @@ -15,7 +15,7 @@ RevRegDef, RevRegDefResult, ) -from .models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult +from .models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult T = TypeVar("T") diff --git a/acapy_agent/anoncreds/default/did_indy/registry.py b/acapy_agent/anoncreds/default/did_indy/registry.py index 567d90ccce..dcaafe4c06 100644 --- a/acapy_agent/anoncreds/default/did_indy/registry.py +++ b/acapy_agent/anoncreds/default/did_indy/registry.py @@ -7,8 +7,8 @@ from ....config.injection_context import InjectionContext from ....core.profile import Profile from ...base import BaseAnonCredsRegistrar, BaseAnonCredsResolver -from ...models.anoncreds_cred_def import CredDef, CredDefResult, GetCredDefResult -from ...models.anoncreds_revocation import ( +from ...models.credential_definition import CredDef, CredDefResult, GetCredDefResult +from ...models.revocation import ( GetRevListResult, GetRevRegDefResult, RevList, @@ -16,7 +16,7 @@ RevRegDef, RevRegDefResult, ) -from ...models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult +from ...models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult LOGGER = logging.getLogger(__name__) diff --git a/acapy_agent/anoncreds/default/did_web/registry.py b/acapy_agent/anoncreds/default/did_web/registry.py index 63382f3606..f97ba88fb8 100644 --- a/acapy_agent/anoncreds/default/did_web/registry.py +++ b/acapy_agent/anoncreds/default/did_web/registry.py @@ -6,8 +6,8 @@ from ....config.injection_context import InjectionContext from ....core.profile import Profile from ...base import BaseAnonCredsRegistrar, BaseAnonCredsResolver -from ...models.anoncreds_cred_def import CredDef, CredDefResult, GetCredDefResult -from ...models.anoncreds_revocation import ( +from ...models.credential_definition import CredDef, CredDefResult, GetCredDefResult +from ...models.revocation import ( GetRevListResult, GetRevRegDefResult, RevList, @@ -15,7 +15,7 @@ RevRegDef, RevRegDefResult, ) -from ...models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult +from ...models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult class DIDWebRegistry(BaseAnonCredsResolver, BaseAnonCredsRegistrar): diff --git a/acapy_agent/anoncreds/default/legacy_indy/recover.py b/acapy_agent/anoncreds/default/legacy_indy/recover.py index cd183adf15..4c3eaf0517 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/recover.py +++ b/acapy_agent/anoncreds/default/legacy_indy/recover.py @@ -9,7 +9,7 @@ import indy_vdr from anoncreds import RevocationRegistry, RevocationRegistryDefinition -from ...models.anoncreds_revocation import RevList +from ...models.revocation import RevList LOGGER = logging.getLogger(__name__) diff --git a/acapy_agent/anoncreds/default/legacy_indy/registry.py b/acapy_agent/anoncreds/default/legacy_indy/registry.py index e173bbde32..aff1040616 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/registry.py +++ b/acapy_agent/anoncreds/default/legacy_indy/registry.py @@ -56,14 +56,14 @@ ) from ...events import RevListFinishedEvent from ...issuer import CATEGORY_CRED_DEF, AnonCredsIssuer, AnonCredsIssuerError -from ...models.anoncreds_cred_def import ( +from ...models.credential_definition import ( CredDef, CredDefResult, CredDefState, CredDefValue, GetCredDefResult, ) -from ...models.anoncreds_revocation import ( +from ...models.revocation import ( GetRevListResult, GetRevRegDefResult, RevList, @@ -74,7 +74,7 @@ RevRegDefState, RevRegDefValue, ) -from ...models.anoncreds_schema import ( +from ...models.schema import ( AnonCredsSchema, GetSchemaResult, SchemaResult, diff --git a/acapy_agent/anoncreds/default/legacy_indy/tests/test_recover.py b/acapy_agent/anoncreds/default/legacy_indy/tests/test_recover.py index 61c0a90f40..b504690c5e 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/tests/test_recover.py +++ b/acapy_agent/anoncreds/default/legacy_indy/tests/test_recover.py @@ -9,9 +9,8 @@ import pytest from anoncreds import RevocationRegistryDefinition -from acapy_agent.tests import mock - -from ....models.anoncreds_revocation import RevList, RevRegDef, RevRegDefValue +from .....tests import mock +from ....models.revocation import RevList, RevRegDef, RevRegDefValue from ..recover import ( RevocRecoveryException, _check_tails_hash_for_inconsistency, diff --git a/acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py b/acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py index 2b6b6c0b76..c41eb80797 100644 --- a/acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py +++ b/acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py @@ -16,25 +16,6 @@ from .....anoncreds.base import AnonCredsSchemaAlreadyExists from .....anoncreds.default.legacy_indy import registry as test_module from .....anoncreds.issuer import AnonCredsIssuer -from .....anoncreds.models.anoncreds_cred_def import ( - CredDef, - CredDefResult, - CredDefValue, - CredDefValuePrimary, -) -from .....anoncreds.models.anoncreds_revocation import ( - RevList, - RevListResult, - RevRegDef, - RevRegDefResult, - RevRegDefState, - RevRegDefValue, -) -from .....anoncreds.models.anoncreds_schema import ( - AnonCredsSchema, - GetSchemaResult, - SchemaResult, -) from .....askar.profile_anon import ( AskarAnoncredsProfileSession, ) @@ -55,6 +36,21 @@ ) from .....tests import mock from .....utils.testing import create_test_profile +from ....models.credential_definition import ( + CredDef, + CredDefResult, + CredDefValue, + CredDefValuePrimary, +) +from ....models.revocation import ( + RevList, + RevListResult, + RevRegDef, + RevRegDefResult, + RevRegDefState, + RevRegDefValue, +) +from ....models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult B58 = alphabet if isinstance(alphabet, str) else alphabet.decode("ascii") INDY_DID = rf"^(did:sov:)?[{B58}]{{21,22}}$" diff --git a/acapy_agent/anoncreds/events.py b/acapy_agent/anoncreds/events.py index 4511b546f7..98477bf4e1 100644 --- a/acapy_agent/anoncreds/events.py +++ b/acapy_agent/anoncreds/events.py @@ -4,7 +4,7 @@ from typing import NamedTuple, Optional from ..core.event_bus import Event -from .models.anoncreds_revocation import RevRegDef +from .models.revocation import RevRegDef CRED_DEF_FINISHED_EVENT = "anoncreds::credential-definition::finished" REV_REG_DEF_FINISHED_EVENT = "anoncreds::revocation-registry-definition::finished" diff --git a/acapy_agent/anoncreds/holder.py b/acapy_agent/anoncreds/holder.py index 04a1a16fac..f8dd4445f7 100644 --- a/acapy_agent/anoncreds/holder.py +++ b/acapy_agent/anoncreds/holder.py @@ -23,7 +23,6 @@ from pyld.jsonld import JsonLdProcessor from uuid_utils import uuid4 -from ..anoncreds.models.anoncreds_schema import AnonCredsSchema from ..askar.profile_anon import AskarAnoncredsProfile from ..core.error import BaseError from ..core.profile import Profile @@ -33,7 +32,8 @@ from ..vc.vc_ld import VerifiableCredential from ..wallet.error import WalletNotFoundError from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG -from .models.anoncreds_cred_def import CredDef +from .models.credential_definition import CredDef +from .models.schema import AnonCredsSchema from .registry import AnonCredsRegistry LOGGER = logging.getLogger(__name__) diff --git a/acapy_agent/anoncreds/issuer.py b/acapy_agent/anoncreds/issuer.py index ad79173e16..6dc3fababa 100644 --- a/acapy_agent/anoncreds/issuer.py +++ b/acapy_agent/anoncreds/issuer.py @@ -24,8 +24,8 @@ from .base import AnonCredsSchemaAlreadyExists, BaseAnonCredsError from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG from .events import CredDefFinishedEvent -from .models.anoncreds_cred_def import CredDef, CredDefResult -from .models.anoncreds_schema import AnonCredsSchema, SchemaResult, SchemaState +from .models.credential_definition import CredDef, CredDefResult +from .models.schema import AnonCredsSchema, SchemaResult, SchemaState from .registry import AnonCredsRegistry LOGGER = logging.getLogger(__name__) diff --git a/acapy_agent/anoncreds/models/credential.py b/acapy_agent/anoncreds/models/credential.py new file mode 100644 index 0000000000..c008fc16c7 --- /dev/null +++ b/acapy_agent/anoncreds/models/credential.py @@ -0,0 +1,167 @@ +"""Credential artifacts.""" + +from typing import Mapping, Optional + +from marshmallow import EXCLUDE, ValidationError, fields + +from ...messaging.models.base import BaseModel, BaseModelSchema +from ...messaging.valid import ( + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_CRED_DEF_ID_VALIDATE, + ANONCREDS_REV_REG_ID_EXAMPLE, + ANONCREDS_REV_REG_ID_VALIDATE, + ANONCREDS_SCHEMA_ID_EXAMPLE, + ANONCREDS_SCHEMA_ID_VALIDATE, + NUM_STR_ANY_EXAMPLE, + NUM_STR_ANY_VALIDATE, +) + + +class AnoncredsAttrValue(BaseModel): + """Anoncreds attribute value.""" + + class Meta: + """Anoncreds attribute value.""" + + schema_class = "AnoncredsAttrValueSchema" + + def __init__( + self, raw: Optional[str] = None, encoded: Optional[str] = None, **kwargs + ): + """Initialize anoncreds (credential) attribute value.""" + super().__init__(**kwargs) + self.raw = raw + self.encoded = encoded + + +class AnoncredsAttrValueSchema(BaseModelSchema): + """Anoncreds attribute value schema.""" + + class Meta: + """Anoncreds attribute value schema metadata.""" + + model_class = AnoncredsAttrValue + unknown = EXCLUDE + + raw = fields.Str(required=True, metadata={"description": "Attribute raw value"}) + encoded = fields.Str( + required=True, + validate=NUM_STR_ANY_VALIDATE, + metadata={ + "description": "Attribute encoded value", + "example": NUM_STR_ANY_EXAMPLE, + }, + ) + + +class DictWithAnoncredsAttrValueSchema(fields.Dict): + """Dict with anoncreds attribute value schema.""" + + def __init__(self, **kwargs): + """Initialize the custom schema for a dictionary with AnoncredsAttrValue.""" + super().__init__( + keys=fields.Str(metadata={"description": "Attribute name"}), + values=fields.Nested(AnoncredsAttrValueSchema()), + **kwargs, + ) + + def _deserialize(self, value, attr, data, **kwargs): + """Deserialize dict with anoncreds attribute value.""" + if not isinstance(value, dict): + raise ValidationError("Value must be a dict.") + + errors = {} + anoncreds_attr_value_schema = AnoncredsAttrValueSchema() + + for k, v in value.items(): + if isinstance(v, dict): + validation_errors = anoncreds_attr_value_schema.validate(v) + if validation_errors: + errors[k] = validation_errors + + if errors: + raise ValidationError(errors) + + return value + + +class AnoncredsCredential(BaseModel): + """Anoncreds credential.""" + + class Meta: + """Anoncreds credential metadata.""" + + schema_class = "AnoncredsCredentialSchema" + + def __init__( + self, + schema_id: Optional[str] = None, + cred_def_id: Optional[str] = None, + rev_reg_id: Optional[str] = None, + values: Mapping[str, AnoncredsAttrValue] = None, + signature: Optional[Mapping] = None, + signature_correctness_proof: Optional[Mapping] = None, + rev_reg: Optional[Mapping] = None, + witness: Optional[Mapping] = None, + ): + """Initialize anoncreds credential.""" + self.schema_id = schema_id + self.cred_def_id = cred_def_id + self.rev_reg_id = rev_reg_id + self.values = values + self.signature = signature + self.signature_correctness_proof = signature_correctness_proof + self.rev_reg = rev_reg + self.witness = witness + + +class AnoncredsCredentialSchema(BaseModelSchema): + """Anoncreds credential schema.""" + + class Meta: + """Anoncreds credential schemametadata.""" + + model_class = AnoncredsCredential + unknown = EXCLUDE + + schema_id = fields.Str( + required=True, + validate=ANONCREDS_SCHEMA_ID_VALIDATE, + metadata={ + "description": "Schema identifier", + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, + }, + ) + cred_def_id = fields.Str( + required=True, + validate=ANONCREDS_CRED_DEF_ID_VALIDATE, + metadata={ + "description": "Credential definition identifier", + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, + }, + ) + rev_reg_id = fields.Str( + allow_none=True, + validate=ANONCREDS_REV_REG_ID_VALIDATE, + metadata={ + "description": "Revocation registry identifier", + "example": ANONCREDS_REV_REG_ID_EXAMPLE, + }, + ) + values = DictWithAnoncredsAttrValueSchema( + required=True, + metadata={"description": "Credential attributes"}, + ) + signature = fields.Dict( + required=True, metadata={"description": "Credential signature"} + ) + signature_correctness_proof = fields.Dict( + required=True, + metadata={"description": "Credential signature correctness proof"}, + ) + rev_reg = fields.Dict( + allow_none=True, metadata={"description": "Revocation registry state"} + ) + witness = fields.Dict( + allow_none=True, metadata={"description": "Witness for revocation proof"} + ) diff --git a/acapy_agent/anoncreds/models/anoncreds_cred_def.py b/acapy_agent/anoncreds/models/credential_definition.py similarity index 97% rename from acapy_agent/anoncreds/models/anoncreds_cred_def.py rename to acapy_agent/anoncreds/models/credential_definition.py index 17d41098e7..4e543eaf57 100644 --- a/acapy_agent/anoncreds/models/anoncreds_cred_def.py +++ b/acapy_agent/anoncreds/models/credential_definition.py @@ -9,9 +9,9 @@ from ...messaging.models.base import BaseModel, BaseModelSchema from ...messaging.valid import ( - INDY_CRED_DEF_ID_EXAMPLE, - INDY_OR_KEY_DID_EXAMPLE, - INDY_SCHEMA_ID_EXAMPLE, + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_DID_EXAMPLE, + ANONCREDS_SCHEMA_ID_EXAMPLE, NUM_STR_WHOLE_EXAMPLE, NUM_STR_WHOLE_VALIDATE, ) @@ -256,7 +256,7 @@ class Meta: issuer_id = fields.Str( metadata={ "description": "Issuer Identifier of the credential definition or schema", - "example": INDY_OR_KEY_DID_EXAMPLE, + "example": ANONCREDS_DID_EXAMPLE, }, data_key="issuerId", ) @@ -264,7 +264,7 @@ class Meta: data_key="schemaId", metadata={ "description": "Schema identifier", - "example": INDY_SCHEMA_ID_EXAMPLE, + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, }, ) type = fields.Str(validate=OneOf(["CL"])) @@ -333,7 +333,7 @@ class Meta: credential_definition_id = fields.Str( metadata={ "description": "credential definition id", - "example": INDY_CRED_DEF_ID_EXAMPLE, + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, }, allow_none=True, ) @@ -434,7 +434,7 @@ class Meta: credential_definition_id = fields.Str( metadata={ "description": "credential definition id", - "example": INDY_CRED_DEF_ID_EXAMPLE, + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, }, ) credential_definition = fields.Nested( diff --git a/acapy_agent/anoncreds/models/credential_offer.py b/acapy_agent/anoncreds/models/credential_offer.py new file mode 100644 index 0000000000..c77419eba3 --- /dev/null +++ b/acapy_agent/anoncreds/models/credential_offer.py @@ -0,0 +1,149 @@ +"""Anoncreds Credential Offer format for v2.0 of the issue-credential protocol.""" + +from typing import Optional, Sequence + +from marshmallow import EXCLUDE, fields + +from ...messaging.models.base import BaseModel, BaseModelSchema +from ...messaging.valid import ( + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_CRED_DEF_ID_VALIDATE, + ANONCREDS_SCHEMA_ID_EXAMPLE, + ANONCREDS_SCHEMA_ID_VALIDATE, + NUM_STR_WHOLE_EXAMPLE, + NUM_STR_WHOLE_VALIDATE, +) + + +class AnoncredsKeyCorrectnessProof(BaseModel): + """Anoncreds key correctness proof.""" + + class Meta: + """AnoncredsKeyCorrectnessProof metadata.""" + + schema_class = "AnoncredsKeyCorrectnessProofSchema" + + def __init__( + self, + c: Optional[str] = None, + xz_cap: Optional[str] = None, + xr_cap: Sequence[Sequence[str]] = None, + **kwargs, + ): + """Initialize XR cap for anoncreds key correctness proof.""" + super().__init__(**kwargs) + + self.c = c + self.xz_cap = xz_cap + self.xr_cap = xr_cap + + +class AnoncredsCorrectnessProofSchema(BaseModelSchema): + """Anoncreds key correctness proof schema.""" + + class Meta: + """Anoncreds key correctness proof schema metadata.""" + + model_class = AnoncredsKeyCorrectnessProof + unknown = EXCLUDE + + c = fields.Str( + required=True, + validate=NUM_STR_WHOLE_VALIDATE, + metadata={ + "description": "c in key correctness proof", + "example": NUM_STR_WHOLE_EXAMPLE, + }, + ) + xz_cap = fields.Str( + required=True, + validate=NUM_STR_WHOLE_VALIDATE, + metadata={ + "description": "xz_cap in key correctness proof", + "example": NUM_STR_WHOLE_EXAMPLE, + }, + ) + xr_cap = fields.List( + fields.List( + fields.Str( + required=True, + metadata={ + "description": "xr_cap component values in key correctness proof" + }, + ), + required=True, + metadata={ + "description": "xr_cap components in key correctness proof", + "many": True, + }, + ), + required=True, + metadata={"description": "xr_cap in key correctness proof", "many": True}, + ) + + +class AnoncredsCredentialOffer(BaseModel): + """Anoncreds Credential Offer.""" + + class Meta: + """AnoncredsCredentialOffer metadata.""" + + schema_class = "AnoncredsCredentialOfferSchema" + + def __init__( + self, + schema_id: Optional[str] = None, + cred_def_id: Optional[str] = None, + nonce: Optional[str] = None, + key_correctness_proof: Optional[str] = None, + **kwargs, + ): + """Initialize values .""" + super().__init__(**kwargs) + self.schema_id = schema_id + self.cred_def_id = cred_def_id + self.nonce = nonce + self.key_correctness_proof = key_correctness_proof + + +class AnoncredsCredentialOfferSchema(BaseModelSchema): + """Anoncreds Credential Offer Schema.""" + + class Meta: + """AnoncredsCredentialOffer schema metadata.""" + + model_class = AnoncredsCredentialOffer + unknown = EXCLUDE + + schema_id = fields.Str( + required=True, + validate=ANONCREDS_SCHEMA_ID_VALIDATE, + metadata={ + "description": "Schema identifier", + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, + }, + ) + + cred_def_id = fields.Str( + required=True, + validate=ANONCREDS_CRED_DEF_ID_VALIDATE, + metadata={ + "description": "Credential definition identifier", + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, + }, + ) + + nonce = fields.Str( + required=True, + validate=NUM_STR_WHOLE_VALIDATE, + metadata={ + "description": "Nonce in credential abstract", + "example": NUM_STR_WHOLE_EXAMPLE, + }, + ) + + key_correctness_proof = fields.Nested( + AnoncredsCorrectnessProofSchema(), + required=True, + metadata={"description": "Key correctness proof"}, + ) diff --git a/acapy_agent/anoncreds/models/credential_proposal.py b/acapy_agent/anoncreds/models/credential_proposal.py new file mode 100644 index 0000000000..3d41d08747 --- /dev/null +++ b/acapy_agent/anoncreds/models/credential_proposal.py @@ -0,0 +1,58 @@ +"""Anoncreds credential definition proposal.""" + +import re + +from marshmallow import fields + +from ...core.profile import Profile +from ...messaging.models.openapi import OpenAPISchema +from ...messaging.valid import ( + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_CRED_DEF_ID_VALIDATE, + ANONCREDS_DID_EXAMPLE, + ANONCREDS_DID_VALIDATE, + ANONCREDS_SCHEMA_ID_EXAMPLE, + ANONCREDS_SCHEMA_ID_VALIDATE, +) + + +class AnoncredsCredentialDefinitionProposal(OpenAPISchema): + """Query string parameters for credential definition searches.""" + + schema_id = fields.Str( + required=False, + validate=ANONCREDS_SCHEMA_ID_VALIDATE, + metadata={ + "description": "Schema identifier", + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, + }, + ) + issuer_id = fields.Str( + required=False, + validate=ANONCREDS_DID_VALIDATE, + metadata={"description": "Issuer DID", "example": ANONCREDS_DID_EXAMPLE}, + ) + cred_def_id = fields.Str( + required=False, + validate=ANONCREDS_CRED_DEF_ID_VALIDATE, + metadata={ + "description": "Credential definition id", + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, + }, + ) + + +CRED_DEF_TAGS = list( + vars(AnoncredsCredentialDefinitionProposal).get("_declared_fields", []) +) + +CRED_DEF_EVENT_PREFIX = "acapy::CRED_DEF::" +EVENT_LISTENER_PATTERN = re.compile(f"^{CRED_DEF_EVENT_PREFIX}(.*)?$") + + +async def notify_cred_def_event(profile: Profile, cred_def_id: str, meta_data: dict): + """Send notification for a cred def post-process event.""" + await profile.notify( + CRED_DEF_EVENT_PREFIX + cred_def_id, + meta_data, + ) diff --git a/acapy_agent/anoncreds/models/credential_request.py b/acapy_agent/anoncreds/models/credential_request.py new file mode 100644 index 0000000000..49fd58e996 --- /dev/null +++ b/acapy_agent/anoncreds/models/credential_request.py @@ -0,0 +1,81 @@ +"""Cred request artifacts to attach to RFC 453 messages.""" + +from typing import Mapping, Optional + +from marshmallow import EXCLUDE, fields + +from ...messaging.models.base import BaseModel, BaseModelSchema +from ...messaging.valid import ( + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_CRED_DEF_ID_VALIDATE, + NUM_STR_WHOLE_EXAMPLE, + NUM_STR_WHOLE_VALIDATE, + UUID4_EXAMPLE, +) + + +class AnoncredsCredRequest(BaseModel): + """Anoncreds credential request.""" + + class Meta: + """Anoncreds credential request metadata.""" + + schema_class = "AnoncredsCredRequestSchema" + + def __init__( + self, + prover_did: Optional[str] = None, + cred_def_id: Optional[str] = None, + blinded_ms: Optional[Mapping] = None, + blinded_ms_correctness_proof: Optional[Mapping] = None, + nonce: Optional[str] = None, + **kwargs, + ): + """Initialize anoncreds credential request.""" + super().__init__(**kwargs) + self.prover_did = prover_did + self.cred_def_id = cred_def_id + self.blinded_ms = blinded_ms + self.blinded_ms_correctness_proof = blinded_ms_correctness_proof + self.nonce = nonce + + +class AnoncredsCredRequestSchema(BaseModelSchema): + """Anoncreds credential request schema.""" + + class Meta: + """Anoncreds credential request schema metadata.""" + + model_class = AnoncredsCredRequest + unknown = EXCLUDE + + prover_did = fields.Str( + required=True, + metadata={ + "description": "Prover DID/Random String/UUID", + "example": UUID4_EXAMPLE, + }, + ) + cred_def_id = fields.Str( + required=True, + validate=ANONCREDS_CRED_DEF_ID_VALIDATE, + metadata={ + "description": "Credential definition identifier", + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, + }, + ) + blinded_ms = fields.Dict( + required=True, metadata={"description": "Blinded master secret"} + ) + blinded_ms_correctness_proof = fields.Dict( + required=True, + metadata={"description": "Blinded master secret correctness proof"}, + ) + nonce = fields.Str( + required=True, + validate=NUM_STR_WHOLE_VALIDATE, + metadata={ + "description": "Nonce in credential request", + "example": NUM_STR_WHOLE_EXAMPLE, + }, + ) diff --git a/acapy_agent/anoncreds/models/non_rev_interval.py b/acapy_agent/anoncreds/models/non_rev_interval.py new file mode 100644 index 0000000000..a224891189 --- /dev/null +++ b/acapy_agent/anoncreds/models/non_rev_interval.py @@ -0,0 +1,78 @@ +"""Anoncreds non-revocation interval.""" + +from time import time +from typing import Optional + +from marshmallow import EXCLUDE, fields + +from ...messaging.models.base import BaseModel, BaseModelSchema +from ...messaging.valid import INT_EPOCH_EXAMPLE, INT_EPOCH_VALIDATE + + +class AnoncredsNonRevocationInterval(BaseModel): + """Anoncreds non-revocation interval.""" + + class Meta: + """NonRevocationInterval metadata.""" + + schema_class = "AnoncredsNonRevocationIntervalSchema" + + def __init__(self, fro: Optional[int] = None, to: Optional[int] = None, **kwargs): + """Initialize non-revocation interval. + + Args: + fro: earliest time of interest + to: latest time of interest + kwargs: additional attributes + + """ + super().__init__(**kwargs) + self.fro = fro + self.to = to + + def covers(self, timestamp: Optional[int] = None) -> bool: + """Whether input timestamp (default now) lies within non-revocation interval. + + Args: + timestamp: time of interest + + Returns: + whether input time satisfies non-revocation interval + + """ + timestamp = timestamp or int(time()) + return (self.fro or 0) <= timestamp <= (self.to or timestamp) + + def timestamp(self) -> bool: + """Return a timestamp that the non-revocation interval covers.""" + return self.to or self.fro or int(time()) + + +class AnoncredsNonRevocationIntervalSchema(BaseModelSchema): + """Schema to allow serialization/deserialization of non-revocation intervals.""" + + class Meta: + """AnoncredsNonRevocationIntervalSchema metadata.""" + + model_class = AnoncredsNonRevocationInterval + unknown = EXCLUDE + + fro = fields.Int( + required=False, + data_key="from", + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": "Earliest time of interest in non-revocation interval", + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ) + to = fields.Int( + required=False, + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": "Latest time of interest in non-revocation interval", + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ) diff --git a/acapy_agent/anoncreds/models/predicate.py b/acapy_agent/anoncreds/models/predicate.py new file mode 100644 index 0000000000..9810a7bb78 --- /dev/null +++ b/acapy_agent/anoncreds/models/predicate.py @@ -0,0 +1,82 @@ +"""Utilities for dealing with predicates.""" + +from collections import namedtuple +from enum import Enum +from typing import Any + +Relation = namedtuple("Relation", "fortran wql math yes no") + + +class Predicate(Enum): + """Enum for predicate types that anoncreds-sdk supports.""" + + LT = Relation( + "LT", + "$lt", + "<", + lambda x, y: Predicate.to_int(x) < Predicate.to_int(y), + lambda x, y: Predicate.to_int(x) >= Predicate.to_int(y), + ) + LE = Relation( + "LE", + "$lte", + "<=", + lambda x, y: Predicate.to_int(x) <= Predicate.to_int(y), + lambda x, y: Predicate.to_int(x) > Predicate.to_int(y), + ) + GE = Relation( + "GE", + "$gte", + ">=", + lambda x, y: Predicate.to_int(x) >= Predicate.to_int(y), + lambda x, y: Predicate.to_int(x) < Predicate.to_int(y), + ) + GT = Relation( + "GT", + "$gt", + ">", + lambda x, y: Predicate.to_int(x) > Predicate.to_int(y), + lambda x, y: Predicate.to_int(x) <= Predicate.to_int(y), + ) + + @property + def fortran(self) -> str: + """Fortran nomenclature.""" + return self.value.fortran + + @property + def wql(self) -> str: + """WQL nomenclature.""" + return self.value.wql + + @property + def math(self) -> str: + """Mathematical nomenclature.""" + return self.value.math + + @staticmethod + def get(relation: str) -> "Predicate": + """Return enum instance corresponding to input relation string.""" + + for pred in Predicate: + if relation.upper() in ( + pred.value.fortran, + pred.value.wql.upper(), + pred.value.math, + ): + return pred + return None + + @staticmethod + def to_int(value: Any) -> int: + """Cast a value as its equivalent int for anoncreds predicate argument. + + Raise ValueError for any input but int, stringified int, or boolean. + + Args: + value: value to coerce + """ + + if isinstance(value, (bool, int)): + return int(value) + return int(str(value)) # kick out floats diff --git a/acapy_agent/anoncreds/models/presentation_request.py b/acapy_agent/anoncreds/models/presentation_request.py new file mode 100644 index 0000000000..05881dfdc8 --- /dev/null +++ b/acapy_agent/anoncreds/models/presentation_request.py @@ -0,0 +1,306 @@ +"""Classes to represent anoncreds presentation request.""" + +from typing import Mapping, Optional + +from marshmallow import ( + EXCLUDE, + Schema, + ValidationError, + fields, + validate, + validates_schema, +) + +from ...messaging.models.base import BaseModel, BaseModelSchema +from ...messaging.models.openapi import OpenAPISchema +from ...messaging.valid import ( + ANONCREDS_CRED_DEF_ID_EXAMPLE, + INT_EPOCH_EXAMPLE, + INT_EPOCH_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, + NUM_STR_NATURAL_EXAMPLE, + NUM_STR_NATURAL_VALIDATE, + PREDICATE_EXAMPLE, + PREDICATE_VALIDATE, +) + + +class AnoncredsPresentationReqPredSpecSchema(OpenAPISchema): + """Schema for predicate specification in anoncreds proof request.""" + + name = fields.Str( + required=True, metadata={"example": "index", "description": "Attribute name"} + ) + p_type = fields.Str( + required=True, + validate=PREDICATE_VALIDATE, + metadata={ + "description": "Predicate type ('<', '<=', '>=', or '>')", + "example": PREDICATE_EXAMPLE, + }, + ) + p_value = fields.Int( + required=True, metadata={"description": "Threshold value", "strict": True} + ) + restrictions = fields.List( + fields.Dict( + keys=fields.Str( + validate=validate.Regexp( + "^schema_id|schema_issuer_did|schema_name|schema_version|issuer_did|" + "cred_def_id|attr::.+::value$" + ), + metadata={"example": "cred_def_id"}, + ), + values=fields.Str(metadata={"example": ANONCREDS_CRED_DEF_ID_EXAMPLE}), + ), + required=False, + metadata={ + "description": ( + "If present, credential must satisfy one of given restrictions: specify" + " schema_id, schema_issuer_did, schema_name, schema_version," + " issuer_did, cred_def_id, and/or attr::::value where" + " represents a credential attribute name" + ) + }, + ) + non_revoked = fields.Nested( + Schema.from_dict( + { + "from": fields.Int( + required=False, + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": ( + "Earliest time of interest in non-revocation interval" + ), + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ), + "to": fields.Int( + required=False, + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": ( + "Latest time of interest in non-revocation interval" + ), + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ), + }, + name="AnoncredsPresentationReqPredSpecNonRevokedSchema", + ), + allow_none=True, + required=False, + ) + + +class AnoncredsPresentationReqAttrSpecSchema(OpenAPISchema): + """Schema for attribute specification in anoncreds proof request.""" + + name = fields.Str( + required=False, + metadata={"example": "favouriteDrink", "description": "Attribute name"}, + ) + names = fields.List( + fields.Str(metadata={"example": "age"}), + required=False, + metadata={"description": "Attribute name group"}, + ) + restrictions = fields.List( + fields.Dict( + keys=fields.Str( + validate=validate.Regexp( + "^schema_id|schema_issuer_did|schema_name|schema_version|issuer_did|" + "cred_def_id|attr::.+::value$" + ), + metadata={"example": "cred_def_id"}, + ), + values=fields.Str(metadata={"example": ANONCREDS_CRED_DEF_ID_EXAMPLE}), + ), + required=False, + metadata={ + "description": ( + "If present, credential must satisfy one of given restrictions: specify" + " schema_id, schema_issuer_did, schema_name, schema_version," + " issuer_did, cred_def_id, and/or attr::::value where" + " represents a credential attribute name" + ) + }, + ) + non_revoked = fields.Nested( + Schema.from_dict( + { + "from": fields.Int( + required=False, + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": ( + "Earliest time of interest in non-revocation interval" + ), + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ), + "to": fields.Int( + required=False, + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": ( + "Latest time of interest in non-revocation interval" + ), + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ), + }, + name="AnoncredsPresentationReqAttrSpecNonRevokedSchema", + ), + allow_none=True, + required=False, + ) + + @validates_schema + def validate_fields(self, data, **kwargs): + """Validate schema fields. + + Data must have exactly one of name or names; if names then restrictions are + mandatory. + + Args: + data: The data to validate + kwargs: Additional keyword arguments + + Raises: + ValidationError: if data has both or neither of name and names + + """ + if ("name" in data) == ("names" in data): + raise ValidationError( + "Attribute specification must have either name or names but not both" + ) + restrictions = data.get("restrictions") + if ("names" in data) and (not restrictions or all(not r for r in restrictions)): + raise ValidationError( + "Attribute specification on 'names' must have non-empty restrictions" + ) + + +class AnoncredsPresentationRequest(BaseModel): + """anoncreds proof request.""" + + class Meta: + """Anoncreds proof request metadata.""" + + schema_class = "AnoncredsPresentationRequestSchema" + + def __init__( + self, + nonce: Optional[str] = None, + name: Optional[str] = None, + version: Optional[str] = None, + requested_attributes: Optional[Mapping] = None, + requested_predicates: Optional[Mapping] = None, + non_revoked: Optional[Mapping] = None, + **kwargs, + ): + """Initialize anoncreds cred abstract object. + + Args: + nonce (str): The nonce value. + name (str): The name of the proof request. + version (str): The version of the proof request. + requested_attributes (Mapping): A mapping of attribute names to attribute + constraints. + requested_predicates (Mapping): A mapping of predicate names to predicate + constraints. + non_revoked (Mapping): A mapping of non-revocation timestamps. + kwargs: Keyword arguments for BaseModel + + """ + super().__init__(**kwargs) + self.nonce = nonce + self.name = name + self.version = version + self.requested_attributes = requested_attributes + self.requested_predicates = requested_predicates + self.non_revoked = non_revoked + + +class AnoncredsPresentationRequestSchema(BaseModelSchema): + """Schema for anoncreds proof request.""" + + class Meta: + """Anoncreds proof request schema metadata.""" + + model_class = AnoncredsPresentationRequest + unknown = EXCLUDE + + nonce = fields.Str( + required=False, + validate=NUM_STR_NATURAL_VALIDATE, + metadata={"description": "Nonce", "example": NUM_STR_NATURAL_EXAMPLE}, + ) + name = fields.Str( + required=False, + dump_default="Proof request", + metadata={"description": "Proof request name", "example": "Proof request"}, + ) + version = fields.Str( + required=False, + dump_default="1.0", + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Proof request version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, + ) + requested_attributes = fields.Dict( + required=True, + keys=fields.Str( + metadata={"decription": "Attribute referent", "example": "0_legalname_uuid"} + ), + values=fields.Nested(AnoncredsPresentationReqAttrSpecSchema()), + metadata={"description": "Requested attribute specifications of proof request"}, + ) + requested_predicates = fields.Dict( + required=True, + keys=fields.Str( + metadata={"description": "Predicate referent", "example": "0_age_GE_uuid"} + ), + values=fields.Nested(AnoncredsPresentationReqPredSpecSchema()), + metadata={"description": "Requested predicate specifications of proof request"}, + ) + non_revoked = fields.Nested( + Schema.from_dict( + { + "from": fields.Int( + required=False, + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": ( + "Earliest time of interest in non-revocation interval" + ), + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ), + "to": fields.Int( + required=False, + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": ( + "Latest time of interest in non-revocation interval" + ), + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ), + }, + name="AnoncredPresentationRequestNonRevokedSchema", + ), + allow_none=True, + required=False, + ) diff --git a/acapy_agent/anoncreds/models/proof.py b/acapy_agent/anoncreds/models/proof.py new file mode 100644 index 0000000000..817b947cc5 --- /dev/null +++ b/acapy_agent/anoncreds/models/proof.py @@ -0,0 +1,749 @@ +"""Marshmallow bindings for anoncreds proofs.""" + +from typing import Mapping, Optional, Sequence + +from marshmallow import EXCLUDE, fields, validate + +from ...messaging.models.base import BaseModel, BaseModelSchema +from ...messaging.valid import ( + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_CRED_DEF_ID_VALIDATE, + ANONCREDS_REV_REG_ID_EXAMPLE, + ANONCREDS_REV_REG_ID_VALIDATE, + ANONCREDS_SCHEMA_ID_EXAMPLE, + ANONCREDS_SCHEMA_ID_VALIDATE, + INT_EPOCH_EXAMPLE, + INT_EPOCH_VALIDATE, + NUM_STR_ANY_EXAMPLE, + NUM_STR_ANY_VALIDATE, + NUM_STR_WHOLE_EXAMPLE, + NUM_STR_WHOLE_VALIDATE, +) +from ...utils.tracing import AdminAPIMessageTracingSchema +from .predicate import Predicate +from .requested_credentials import ( + AnoncredsRequestedCredsRequestedAttrSchema, + AnoncredsRequestedCredsRequestedPredSchema, +) + + +class AnoncredsEQProof(BaseModel): + """Equality proof for anoncreds primary proof.""" + + class Meta: + """Equality proof metadata.""" + + schema_class = "AnoncredsEQProofMeta" + + def __init__( + self, + revealed_attrs: Mapping[str, str] = None, + a_prime: Optional[str] = None, + e: Optional[str] = None, + v: Optional[str] = None, + m: Mapping[str, str] = None, + m2: Optional[str] = None, + **kwargs, + ): + """Initialize equality proof object.""" + super().__init__(**kwargs) + self.revealed_attrs = revealed_attrs + self.a_prime = a_prime + self.e = e + self.v = v + self.m = m + self.m2 = m2 + + +class AnoncredsEQProofSchema(BaseModelSchema): + """Anoncreds equality proof schema.""" + + class Meta: + """Anoncreds equality proof metadata.""" + + model_class = AnoncredsEQProof + unknown = EXCLUDE + + revealed_attrs = fields.Dict( + keys=fields.Str(metadata={"example": "preference"}), + values=fields.Str( + validate=NUM_STR_ANY_VALIDATE, metadata={"example": NUM_STR_ANY_EXAMPLE} + ), + ) + a_prime = fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ) + e = fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ) + v = fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ) + m = fields.Dict( + keys=fields.Str(metadata={"example": "master_secret"}), + values=fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ), + ) + m2 = fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ) + + +class AnoncredsGEProofPred(BaseModel): + """Anoncreds GE proof predicate.""" + + class Meta: + """Anoncreds GE proof predicate metadata.""" + + schema_class = "AnoncredsGEProofPredSchema" + + def __init__( + self, + attr_name: Optional[str] = None, + p_type: Optional[str] = None, + value: Optional[int] = None, + **kwargs, + ): + """Initialize anoncreds GE proof predicate.""" + super().__init__(**kwargs) + self.attr_name = attr_name + self.p_type = p_type + self.value = value + + +class AnoncredsGEProofPredSchema(BaseModelSchema): + """Anoncreds GE proof predicate schema.""" + + class Meta: + """Anoncreds GE proof predicate metadata.""" + + model_class = AnoncredsGEProofPred + unknown = EXCLUDE + + attr_name = fields.Str( + metadata={"description": "Attribute name, anoncreds-canonicalized"} + ) + p_type = fields.Str( + validate=validate.OneOf([p.fortran for p in Predicate]), + metadata={"description": "Predicate type"}, + ) + value = fields.Integer( + metadata={"strict": True, "description": "Predicate threshold value"} + ) + + +class AnoncredsGEProof(BaseModel): + """Greater-than-or-equal-to proof for anoncreds primary proof.""" + + class Meta: + """GE proof metadata.""" + + schema_class = "AnoncredsGEProofMeta" + + def __init__( + self, + u: Mapping[str, str] = None, + r: Mapping[str, str] = None, + mj: Optional[str] = None, + alpha: Optional[str] = None, + t: Mapping[str, str] = None, + predicate: Optional[AnoncredsGEProofPred] = None, + **kwargs, + ): + """Initialize GE proof object.""" + super().__init__(**kwargs) + self.u = u + self.r = r + self.mj = mj + self.alpha = alpha + self.t = t + self.predicate = predicate + + +class AnoncredsGEProofSchema(BaseModelSchema): + """Anoncreds GE proof schema.""" + + class Meta: + """Anoncreds GE proof schema metadata.""" + + model_class = AnoncredsGEProof + unknown = EXCLUDE + + u = fields.Dict( + keys=fields.Str(), + values=fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ), + ) + r = fields.Dict( + keys=fields.Str(), + values=fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ), + ) + mj = fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ) + alpha = fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ) + t = fields.Dict( + keys=fields.Str(), + values=fields.Str( + validate=NUM_STR_WHOLE_VALIDATE, metadata={"example": NUM_STR_WHOLE_EXAMPLE} + ), + ) + predicate = fields.Nested(AnoncredsGEProofPredSchema) + + +class AnoncredsPrimaryProof(BaseModel): + """Anoncreds primary proof.""" + + class Meta: + """Anoncreds primary proof metadata.""" + + schema_class = "AnoncredsPrimaryProofSchema" + + def __init__( + self, + eq_proof: Optional[AnoncredsEQProof] = None, + ge_proofs: Sequence[AnoncredsGEProof] = None, + **kwargs, + ): + """Initialize anoncreds primary proof.""" + super().__init__(**kwargs) + self.eq_proof = eq_proof + self.ge_proofs = ge_proofs + + +class AnoncredsPrimaryProofSchema(BaseModelSchema): + """Anoncreds primary proof schema.""" + + class Meta: + """Anoncreds primary proof schema metadata.""" + + model_class = AnoncredsPrimaryProof + unknown = EXCLUDE + + eq_proof = fields.Nested( + AnoncredsEQProofSchema, + allow_none=True, + metadata={"description": "Anoncreds equality proof"}, + ) + ge_proofs = fields.Nested( + AnoncredsGEProofSchema, + many=True, + allow_none=True, + metadata={"description": "Anoncreds GE proofs"}, + ) + + +class AnoncredsNonRevocProof(BaseModel): + """Anoncreds non-revocation proof.""" + + class Meta: + """Anoncreds non-revocation proof metadata.""" + + schema_class = "AnoncredsNonRevocProofSchema" + + def __init__( + self, + x_list: Optional[Mapping] = None, + c_list: Optional[Mapping] = None, + **kwargs, + ): + """Initialize anoncreds non-revocation proof.""" + super().__init__(**kwargs) + self.x_list = x_list + self.c_list = c_list + + +class AnoncredsNonRevocProofSchema(BaseModelSchema): + """Anoncreds non-revocation proof schema.""" + + class Meta: + """Anoncreds non-revocation proof schema metadata.""" + + model_class = AnoncredsNonRevocProof + unknown = EXCLUDE + + x_list = fields.Dict(keys=fields.Str(), values=fields.Str()) + c_list = fields.Dict(keys=fields.Str(), values=fields.Str()) + + +class AnoncredsProofProofProofsProof(BaseModel): + """Anoncreds proof.proof.proofs constituent proof.""" + + class Meta: + """Anoncreds proof.proof.proofs constituent proof schema.""" + + schema_class = "AnoncredsProofProofProofsProofSchema" + + def __init__( + self, + primary_proof: Optional[AnoncredsPrimaryProof] = None, + non_revoc_proof: Optional[AnoncredsNonRevocProof] = None, + **kwargs, + ): + """Initialize proof.proof.proofs constituent proof.""" + super().__init__(**kwargs) + self.primary_proof = primary_proof + self.non_revoc_proof = non_revoc_proof + + +class AnoncredsProofProofProofsProofSchema(BaseModelSchema): + """Anoncreds proof.proof.proofs constituent proof schema.""" + + class Meta: + """Anoncreds proof.proof.proofs constituent proof schema metadata.""" + + model_class = AnoncredsProofProofProofsProof + unknown = EXCLUDE + + primary_proof = fields.Nested( + AnoncredsPrimaryProofSchema, metadata={"description": "Anoncreds primary proof"} + ) + non_revoc_proof = fields.Nested( + AnoncredsNonRevocProofSchema, + allow_none=True, + metadata={"description": "Anoncreds non-revocation proof"}, + ) + + +class AnoncredsProofProofAggregatedProof(BaseModel): + """Anoncreds proof.proof aggregated proof.""" + + class Meta: + """Anoncreds proof.proof aggregated proof metadata.""" + + schema_class = "AnoncredsProofProofAggregatedProofSchema" + + def __init__( + self, + c_hash: Optional[str] = None, + c_list: Sequence[Sequence[int]] = None, + **kwargs, + ): + """Initialize anoncreds proof.proof agreggated proof.""" + super().__init__(**kwargs) + self.c_hash = c_hash + self.c_list = c_list + + +class AnoncredsProofProofAggregatedProofSchema(BaseModelSchema): + """Anoncreds proof.proof aggregated proof schema.""" + + class Meta: + """Anoncreds proof.proof aggregated proof schema metadata.""" + + model_class = AnoncredsProofProofAggregatedProof + unknown = EXCLUDE + + c_hash = fields.Str(metadata={"description": "c_hash value"}) + c_list = fields.List( + fields.List(fields.Int(metadata={"strict": True})), + metadata={"description": "c_list value"}, + ) + + +class AnoncredsProofProof(BaseModel): + """Anoncreds proof.proof content.""" + + class Meta: + """Anoncreds proof.proof content metadata.""" + + schema_class = "AnoncredsProofProofSchema" + + def __init__( + self, + proofs: Sequence[AnoncredsProofProofProofsProof] = None, + aggregated_proof: Optional[AnoncredsProofProofAggregatedProof] = None, + **kwargs, + ): + """Initialize anoncreds proof.proof content.""" + super().__init__(**kwargs) + self.proofs = proofs + self.aggregated_proof = aggregated_proof + + +class AnoncredsProofProofSchema(BaseModelSchema): + """Anoncreds proof.proof content schema.""" + + class Meta: + """Anoncreds proof.proof content schema metadata.""" + + model_class = AnoncredsProofProof + unknown = EXCLUDE + + proofs = fields.Nested( + AnoncredsProofProofProofsProofSchema, + many=True, + metadata={"description": "Anoncreds proof proofs"}, + ) + aggregated_proof = fields.Nested( + AnoncredsProofProofAggregatedProofSchema, + metadata={"description": "Anoncreds proof aggregated proof"}, + ) + + +class RawEncoded(BaseModel): + """Raw and encoded attribute values.""" + + class Meta: + """Raw and encoded attribute values metadata.""" + + schema_class = "RawEncodedSchema" + + def __init__( + self, + raw: Optional[str] = None, + encoded: Optional[str] = None, + **kwargs, + ): + """Initialize raw and encoded attribute values.""" + super().__init__(**kwargs) + self.raw = raw + self.encoded = encoded + + +class RawEncodedSchema(BaseModelSchema): + """Raw and encoded attribute values schema.""" + + class Meta: + """Raw and encoded attribute values schema metadata.""" + + model_class = RawEncoded + unknown = EXCLUDE + + raw = fields.Str(metadata={"description": "Raw value"}) + encoded = fields.Str( + validate=NUM_STR_ANY_VALIDATE, + metadata={"description": "Encoded value", "example": NUM_STR_ANY_EXAMPLE}, + ) + + +class AnoncredsProofRequestedProofRevealedAttr(RawEncoded): + """Anoncreds proof requested proof revealed attr.""" + + class Meta: + """Anoncreds proof requested proof revealed attr metadata.""" + + schema_class = "AnoncredsProofRequestedProofRevealedAttrSchema" + + def __init__( + self, + sub_proof_index: Optional[int] = None, + **kwargs, + ): + """Initialize anoncreds proof requested proof revealed attr.""" + super().__init__(**kwargs) + self.sub_proof_index = sub_proof_index + + +class AnoncredsProofRequestedProofRevealedAttrSchema(RawEncodedSchema): + """Anoncreds proof requested proof revealed attr schema.""" + + class Meta: + """Anoncreds proof requested proof revealed attr schema metadata.""" + + model_class = AnoncredsProofRequestedProofRevealedAttr + unknown = EXCLUDE + + sub_proof_index = fields.Int( + metadata={"strict": True, "description": "Sub-proof index"} + ) + + +class AnoncredsProofRequestedProofRevealedAttrGroup(BaseModel): + """Anoncreds proof requested proof revealed attr group.""" + + class Meta: + """Anoncreds proof requested proof revealed attr group metadata.""" + + schema_class = "AnoncredsProofRequestedProofRevealedAttrGroupSchema" + + def __init__( + self, + sub_proof_index: Optional[int] = None, + values: Mapping[str, RawEncoded] = None, + **kwargs, + ): + """Initialize anoncreds proof requested proof revealed attr.""" + super().__init__(**kwargs) + self.sub_proof_index = sub_proof_index + self.values = values + + +class AnoncredsProofRequestedProofRevealedAttrGroupSchema(BaseModelSchema): + """Anoncreds proof requested proof revealed attr group schema.""" + + class Meta: + """Anoncreds proof requested proof revealed attr group schema metadata.""" + + model_class = AnoncredsProofRequestedProofRevealedAttrGroup + unknown = EXCLUDE + + sub_proof_index = fields.Int( + metadata={"strict": True, "description": "Sub-proof index"} + ) + values = fields.Dict( + keys=fields.Str(), + values=fields.Nested(RawEncodedSchema), + metadata={ + "description": "Anoncreds proof requested proof revealed attr groups group value" # noqa: E501 + }, + ) + + +class AnoncredsProofRequestedProofPredicate(BaseModel): + """Anoncreds proof requested proof predicate.""" + + class Meta: + """Anoncreds proof requested proof requested proof predicate metadata.""" + + schema_class = "AnoncredsProofRequestedProofPredicateSchema" + + def __init__( + self, + sub_proof_index: Optional[int] = None, + **kwargs, + ): + """Initialize anoncreds proof requested proof predicate.""" + super().__init__(**kwargs) + self.sub_proof_index = sub_proof_index + + +class AnoncredsProofRequestedProofPredicateSchema(BaseModelSchema): + """Anoncreds proof requested prrof predicate schema.""" + + class Meta: + """Anoncreds proof requested proof requested proof predicate schema metadata.""" + + model_class = AnoncredsProofRequestedProofPredicate + unknown = EXCLUDE + + sub_proof_index = fields.Int( + metadata={"strict": True, "description": "Sub-proof index"} + ) + + +class AnoncredsProofRequestedProof(BaseModel): + """Anoncreds proof.requested_proof content.""" + + class Meta: + """Anoncreds proof.requested_proof content metadata.""" + + schema_class = "AnoncredsProofRequestedProofSchema" + + def __init__( + self, + revealed_attrs: Mapping[str, AnoncredsProofRequestedProofRevealedAttr] = None, + revealed_attr_groups: Mapping[ + str, + AnoncredsProofRequestedProofRevealedAttrGroup, + ] = None, + self_attested_attrs: Optional[Mapping] = None, + unrevealed_attrs: Optional[Mapping] = None, + predicates: Mapping[str, AnoncredsProofRequestedProofPredicate] = None, + **kwargs, + ): + """Initialize anoncreds proof requested proof.""" + super().__init__(**kwargs) + self.revealed_attrs = revealed_attrs + self.revealed_attr_groups = revealed_attr_groups + self.self_attested_attrs = self_attested_attrs + self.unrevealed_attrs = unrevealed_attrs + self.predicates = predicates + + +class AnoncredsProofRequestedProofSchema(BaseModelSchema): + """Anoncreds proof requested proof schema.""" + + class Meta: + """Anoncreds proof requested proof schema metadata.""" + + model_class = AnoncredsProofRequestedProof + unknown = EXCLUDE + + revealed_attrs = fields.Dict( + keys=fields.Str(), + values=fields.Nested(AnoncredsProofRequestedProofRevealedAttrSchema), + allow_none=True, + metadata={"description": "Proof requested proof revealed attributes"}, + ) + revealed_attr_groups = fields.Dict( + keys=fields.Str(), + values=fields.Nested(AnoncredsProofRequestedProofRevealedAttrGroupSchema), + allow_none=True, + metadata={"description": "Proof requested proof revealed attribute groups"}, + ) + self_attested_attrs = fields.Dict( + metadata={"description": "Proof requested proof self-attested attributes"} + ) + unrevealed_attrs = fields.Dict(metadata={"description": "Unrevealed attributes"}) + predicates = fields.Dict( + keys=fields.Str(), + values=fields.Nested(AnoncredsProofRequestedProofPredicateSchema), + metadata={"description": "Proof requested proof predicates."}, + ) + + +class AnoncredsProofIdentifier(BaseModel): + """Anoncreds proof identifier.""" + + class Meta: + """Anoncreds proof identifier metadata.""" + + schema_class = "AnoncredsProofIdentifierSchema" + + def __init__( + self, + schema_id: Optional[str] = None, + cred_def_id: Optional[str] = None, + rev_reg_id: Optional[str] = None, + timestamp: Optional[int] = None, + **kwargs, + ): + """Initialize anoncreds proof identifier.""" + super().__init__(**kwargs) + self.schema_id = schema_id + self.cred_def_id = cred_def_id + self.rev_reg_id = rev_reg_id + self.timestamp = timestamp + + +class AnoncredsProofIdentifierSchema(BaseModelSchema): + """Anoncreds proof identifier schema.""" + + class Meta: + """Anoncreds proof identifier schema metadata.""" + + model_class = AnoncredsProofIdentifier + unknown = EXCLUDE + + schema_id = fields.Str( + validate=ANONCREDS_SCHEMA_ID_VALIDATE, + metadata={ + "description": "Schema identifier", + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, + }, + ) + cred_def_id = fields.Str( + validate=ANONCREDS_CRED_DEF_ID_VALIDATE, + metadata={ + "description": "Credential definition identifier", + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, + }, + ) + rev_reg_id = fields.Str( + allow_none=True, + validate=ANONCREDS_REV_REG_ID_VALIDATE, + metadata={ + "description": "Revocation registry identifier", + "example": ANONCREDS_REV_REG_ID_EXAMPLE, + }, + ) + timestamp = fields.Int( + allow_none=True, + validate=INT_EPOCH_VALIDATE, + metadata={ + "strict": True, + "description": "Timestamp epoch", + "example": INT_EPOCH_EXAMPLE, + }, + ) + + +class AnoncredsProof(BaseModel): + """Anoncreds proof.""" + + class Meta: + """Anoncreds proof metadata.""" + + schema_class = "AnoncredsProofSchema" + + def __init__( + self, + proof: Optional[AnoncredsProofProof] = None, + requested_proof: Optional[AnoncredsProofRequestedProof] = None, + identifiers: Sequence[AnoncredsProofIdentifier] = None, + **kwargs, + ): + """Initialize anoncreds proof.""" + super().__init__(**kwargs) + self.proof = proof + self.requested_proof = requested_proof + self.identifiers = identifiers + + +class AnoncredsProofSchema(BaseModelSchema): + """Anoncreds proof schema.""" + + class Meta: + """Anoncreds proof schema metadata.""" + + model_class = AnoncredsProof + unknown = EXCLUDE + + proof = fields.Nested( + AnoncredsProofProofSchema, + metadata={"description": "Anoncreds proof.proof content"}, + ) + requested_proof = fields.Nested( + AnoncredsProofRequestedProofSchema, + metadata={"description": "Anoncreds proof.requested_proof content"}, + ) + identifiers = fields.Nested( + AnoncredsProofIdentifierSchema, + many=True, + metadata={"description": "Anoncreds proof.identifiers content"}, + ) + + +class AnoncredsPresSpecSchema(AdminAPIMessageTracingSchema): + """Request schema for anoncreds proof specification to send as presentation.""" + + self_attested_attributes = fields.Dict( + required=True, + keys=fields.Str(metadata={"example": "attr_name"}), + values=fields.Str( + metadata={ + "example": "self_attested_value", + "description": ( + "Self-attested attribute values to use in requested-credentials" + " structure for proof construction" + ), + } + ), + metadata={"description": "Self-attested attributes to build into proof"}, + ) + requested_attributes = fields.Dict( + required=True, + keys=fields.Str(metadata={"example": "attr_referent"}), + values=fields.Nested(AnoncredsRequestedCredsRequestedAttrSchema), + metadata={ + "description": ( + "Nested object mapping proof request attribute referents to" + " requested-attribute specifiers" + ) + }, + ) + requested_predicates = fields.Dict( + required=True, + keys=fields.Str(metadata={"example": "pred_referent"}), + values=fields.Nested(AnoncredsRequestedCredsRequestedPredSchema), + metadata={ + "description": ( + "Nested object mapping proof request predicate referents to" + " requested-predicate specifiers" + ) + }, + ) + trace = fields.Bool( + required=False, + metadata={ + "description": "Whether to trace event (default false)", + "example": False, + }, + ) diff --git a/acapy_agent/anoncreds/models/requested_credentials.py b/acapy_agent/anoncreds/models/requested_credentials.py new file mode 100644 index 0000000000..ac0fcf3d33 --- /dev/null +++ b/acapy_agent/anoncreds/models/requested_credentials.py @@ -0,0 +1,47 @@ +"""Admin routes for presentations.""" + +from marshmallow import fields + +from ...messaging.models.openapi import OpenAPISchema +from ...messaging.valid import INT_EPOCH_EXAMPLE, INT_EPOCH_VALIDATE + + +class AnoncredsRequestedCredsRequestedAttrSchema(OpenAPISchema): + """Schema for requested attributes within anoncreds requested creds structure.""" + + cred_id = fields.Str( + required=True, + metadata={ + "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "description": ( + "Wallet credential identifier (typically but not necessarily a UUID)" + ), + }, + ) + revealed = fields.Bool( + dump_default=True, + metadata={"description": "Whether to reveal attribute in proof (default true)"}, + ) + + +class AnoncredsRequestedCredsRequestedPredSchema(OpenAPISchema): + """Schema for requested predicates within anoncreds requested creds structure.""" + + cred_id = fields.Str( + required=True, + metadata={ + "description": ( + "Wallet credential identifier (typically but not necessarily a UUID)" + ), + "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + }, + ) + timestamp = fields.Int( + required=False, + validate=INT_EPOCH_VALIDATE, + metadata={ + "description": "Epoch timestamp of interest for non-revocation proof", + "strict": True, + "example": INT_EPOCH_EXAMPLE, + }, + ) diff --git a/acapy_agent/anoncreds/models/anoncreds_revocation.py b/acapy_agent/anoncreds/models/revocation.py similarity index 96% rename from acapy_agent/anoncreds/models/anoncreds_revocation.py rename to acapy_agent/anoncreds/models/revocation.py index cc90469eac..94c75a525a 100644 --- a/acapy_agent/anoncreds/models/anoncreds_revocation.py +++ b/acapy_agent/anoncreds/models/revocation.py @@ -7,15 +7,14 @@ from marshmallow.validate import OneOf from typing_extensions import Literal -from acapy_agent.messaging.valid import ( - INDY_CRED_DEF_ID_EXAMPLE, - INDY_ISO8601_DATETIME_EXAMPLE, - INDY_OR_KEY_DID_EXAMPLE, - INDY_RAW_PUBLIC_KEY_EXAMPLE, - INDY_REV_REG_ID_EXAMPLE, -) - from ...messaging.models.base import BaseModel, BaseModelSchema +from ...messaging.valid import ( + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_DID_EXAMPLE, + ANONCREDS_REV_REG_ID_EXAMPLE, + ISO8601_DATETIME_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, +) class RevRegDefValue(BaseModel): @@ -60,7 +59,7 @@ class Meta: unknown = EXCLUDE public_keys = fields.Dict( - data_key="publicKeys", metadata={"example": INDY_RAW_PUBLIC_KEY_EXAMPLE} + data_key="publicKeys", metadata={"example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE} ) max_cred_num = fields.Int(data_key="maxCredNum", metadata={"example": 777}) tails_location = fields.Str( @@ -131,7 +130,7 @@ class Meta: issuer_id = fields.Str( metadata={ "description": "Issuer Identifier of the credential definition or schema", - "example": INDY_OR_KEY_DID_EXAMPLE, + "example": ANONCREDS_DID_EXAMPLE, }, data_key="issuerId", ) @@ -139,7 +138,7 @@ class Meta: cred_def_id = fields.Str( metadata={ "description": "Credential definition identifier", - "example": INDY_CRED_DEF_ID_EXAMPLE, + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, }, data_key="credDefId", ) @@ -209,7 +208,7 @@ class Meta: revocation_registry_definition_id = fields.Str( metadata={ "description": "revocation registry definition id", - "example": INDY_REV_REG_ID_EXAMPLE, + "example": ANONCREDS_REV_REG_ID_EXAMPLE, } ) revocation_registry_definition = fields.Nested( @@ -380,14 +379,14 @@ class Meta: issuer_id = fields.Str( metadata={ "description": "Issuer Identifier of the credential definition or schema", - "example": INDY_OR_KEY_DID_EXAMPLE, + "example": ANONCREDS_DID_EXAMPLE, }, data_key="issuerId", ) rev_reg_def_id = fields.Str( metadata={ "description": "The ID of the revocation registry definition", - "example": INDY_REV_REG_ID_EXAMPLE, + "example": ANONCREDS_REV_REG_ID_EXAMPLE, }, data_key="revRegDefId", ) @@ -409,7 +408,7 @@ class Meta: timestamp = fields.Int( metadata={ "description": "Timestamp at which revocation list is applicable", - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, required=False, ) diff --git a/acapy_agent/anoncreds/models/anoncreds_schema.py b/acapy_agent/anoncreds/models/schema.py similarity index 95% rename from acapy_agent/anoncreds/models/anoncreds_schema.py rename to acapy_agent/anoncreds/models/schema.py index b2383ff60f..6a3f56bc03 100644 --- a/acapy_agent/anoncreds/models/anoncreds_schema.py +++ b/acapy_agent/anoncreds/models/schema.py @@ -7,7 +7,10 @@ from marshmallow.validate import OneOf from ...messaging.models.base import BaseModel, BaseModelSchema -from ...messaging.valid import INDY_OR_KEY_DID_EXAMPLE, INDY_SCHEMA_ID_EXAMPLE +from ...messaging.valid import ( + ANONCREDS_DID_EXAMPLE, + ANONCREDS_SCHEMA_ID_EXAMPLE, +) class AnonCredsSchema(BaseModel): @@ -58,7 +61,7 @@ class Meta: issuer_id = fields.Str( metadata={ "description": "Issuer Identifier of the credential definition or schema", - "example": INDY_OR_KEY_DID_EXAMPLE, + "example": ANONCREDS_DID_EXAMPLE, }, data_key="issuerId", ) @@ -129,7 +132,10 @@ class Meta: schema_value = fields.Nested(AnonCredsSchemaSchema(), data_key="schema") schema_id = fields.Str( - metadata={"description": "Schema identifier", "example": INDY_SCHEMA_ID_EXAMPLE} + metadata={ + "description": "Schema identifier", + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, + } ) resolution_metadata = fields.Dict() schema_metadata = fields.Dict() @@ -185,7 +191,7 @@ class Meta: schema_id = fields.Str( metadata={ "description": "Schema identifier", - "example": INDY_SCHEMA_ID_EXAMPLE, + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, } ) schema_value = fields.Nested(AnonCredsSchemaSchema(), data_key="schema") diff --git a/acapy_agent/anoncreds/models/utils.py b/acapy_agent/anoncreds/models/utils.py new file mode 100644 index 0000000000..51f140844f --- /dev/null +++ b/acapy_agent/anoncreds/models/utils.py @@ -0,0 +1,99 @@ +"""Utilities to deal with anoncreds objects.""" + +from ..holder import AnonCredsHolder + + +def _get_value_error_msg(proof_request: dict, referent: str) -> str: + return ( + "Could not automatically construct presentation for " + + f"presentation request {proof_request['name']}" + + f":{proof_request['version']} because referent " + + f"{referent} did not produce any credentials." + ) + + +async def get_requested_creds_from_proof_request_preview( + proof_request: dict, + *, + holder: AnonCredsHolder, +): + """Build anoncreds requested-credentials structure. + + Given input proof request and presentation preview, use credentials in + holder's wallet to build anoncreds requested credentials structure for input + to proof creation. + + Args: + proof_request: anoncreds proof request + preview: preview from presentation proposal, if applicable + holder: holder injected into current context + + """ + req_creds = { + "self_attested_attributes": {}, + "requested_attributes": {}, + "requested_predicates": {}, + } + + for referent, _ in proof_request["requested_attributes"].items(): + credentials = await holder.get_credentials_for_presentation_request_by_referent( + presentation_request=proof_request, + referents=(referent,), + start=0, + count=100, + ) + if not credentials: + raise ValueError(_get_value_error_msg(proof_request, referent)) + + cred_match = credentials[0] # holder sorts + + if "restrictions" in proof_request["requested_attributes"][referent]: + req_creds["requested_attributes"][referent] = { + "cred_id": cred_match["cred_info"]["referent"], + "revealed": True, + } + else: + req_creds["self_attested_attributes"][referent] = cred_match["cred_info"][ + "attrs" + ][proof_request["requested_attributes"][referent]["name"]] + + for referent in proof_request["requested_predicates"]: + credentials = await holder.get_credentials_for_presentation_request_by_referent( + presentation_request=proof_request, + referents=(referent,), + start=0, + count=100, + ) + if not credentials: + raise ValueError(_get_value_error_msg(proof_request, referent)) + + cred_match = credentials[0] # holder sorts + if "restrictions" in proof_request["requested_predicates"][referent]: + req_creds["requested_predicates"][referent] = { + "cred_id": cred_match["cred_info"]["referent"], + "revealed": True, + } + else: + req_creds["self_attested_attributes"][referent] = cred_match["cred_info"][ + "attrs" + ][proof_request["requested_predicates"][referent]["name"]] + + return req_creds + + +def extract_non_revocation_intervals_from_proof_request(proof_req: dict): + """Return non-revocation intervals by requested item referent in proof request.""" + non_revoc_intervals = {} + for req_item_type in ("requested_attributes", "requested_predicates"): + for reft, req_item in proof_req[req_item_type].items(): + interval = req_item.get( + "non_revoked", + proof_req.get("non_revoked"), + ) + if interval: + timestamp_from = interval.get("from") + timestamp_to = interval.get("to") + if (timestamp_to is not None) and timestamp_from == timestamp_to: + interval["from"] = 0 # accommodate verify=False if from=to + non_revoc_intervals[reft] = interval + return non_revoc_intervals diff --git a/acapy_agent/anoncreds/registry.py b/acapy_agent/anoncreds/registry.py index 79aba036cc..c355b447cd 100644 --- a/acapy_agent/anoncreds/registry.py +++ b/acapy_agent/anoncreds/registry.py @@ -11,8 +11,8 @@ BaseAnonCredsRegistrar, BaseAnonCredsResolver, ) -from .models.anoncreds_cred_def import CredDef, CredDefResult, GetCredDefResult -from .models.anoncreds_revocation import ( +from .models.credential_definition import CredDef, CredDefResult, GetCredDefResult +from .models.revocation import ( GetRevListResult, GetRevRegDefResult, RevList, @@ -20,7 +20,7 @@ RevRegDef, RevRegDefResult, ) -from .models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult +from .models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult LOGGER = logging.getLogger(__name__) diff --git a/acapy_agent/anoncreds/revocation.py b/acapy_agent/anoncreds/revocation.py index 96d2795246..e9cc88293f 100644 --- a/acapy_agent/anoncreds/revocation.py +++ b/acapy_agent/anoncreds/revocation.py @@ -26,8 +26,6 @@ from requests import RequestException, Session from uuid_utils import uuid4 -from acapy_agent.anoncreds.models.anoncreds_cred_def import CredDef - from ..askar.profile_anon import AskarAnoncredsProfile, AskarAnoncredsProfileSession from ..core.error import BaseError from ..core.event_bus import Event, EventBus @@ -43,7 +41,8 @@ STATE_FINISHED, AnonCredsIssuer, ) -from .models.anoncreds_revocation import ( +from .models.credential_definition import CredDef +from .models.revocation import ( RevList, RevListResult, RevListState, diff --git a/acapy_agent/anoncreds/routes.py b/acapy_agent/anoncreds/routes.py index 9cf1d6ad98..9a8fe04669 100644 --- a/acapy_agent/anoncreds/routes.py +++ b/acapy_agent/anoncreds/routes.py @@ -16,13 +16,12 @@ from ..admin.decorators.auth import tenant_authentication from ..admin.request_context import AdminRequestContext from ..core.event_bus import EventBus -from ..ledger.error import LedgerError from ..messaging.models.openapi import OpenAPISchema from ..messaging.valid import ( - INDY_CRED_DEF_ID_EXAMPLE, - INDY_OR_KEY_DID_EXAMPLE, - INDY_REV_REG_ID_EXAMPLE, - INDY_SCHEMA_ID_EXAMPLE, + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_DID_EXAMPLE, + ANONCREDS_REV_REG_ID_EXAMPLE, + ANONCREDS_SCHEMA_ID_EXAMPLE, UUIDFour, ) from ..revocation.error import RevocationNotSupportedError @@ -35,9 +34,9 @@ AnonCredsResolutionError, ) from .issuer import AnonCredsIssuer, AnonCredsIssuerError -from .models.anoncreds_cred_def import CredDefResultSchema, GetCredDefResultSchema -from .models.anoncreds_revocation import RevListResultSchema, RevRegDefResultSchema -from .models.anoncreds_schema import ( +from .models.credential_definition import CredDefResultSchema, GetCredDefResultSchema +from .models.revocation import RevListResultSchema, RevRegDefResultSchema +from .models.schema import ( AnonCredsSchemaSchema, GetSchemaResultSchema, SchemaResultSchema, @@ -69,7 +68,7 @@ class SchemaIdMatchInfo(OpenAPISchema): schema_id = fields.Str( metadata={ "description": "Schema identifier", - "example": INDY_SCHEMA_ID_EXAMPLE, + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, } ) @@ -112,7 +111,7 @@ class SchemasQueryStringSchema(OpenAPISchema): schema_issuer_id = fields.Str( metadata={ "description": "Schema issuer identifier", - "example": INDY_OR_KEY_DID_EXAMPLE, + "example": ANONCREDS_DID_EXAMPLE, } ) @@ -124,7 +123,7 @@ class GetSchemasResponseSchema(OpenAPISchema): fields.Str( metadata={ "description": "Schema identifiers", - "example": INDY_SCHEMA_ID_EXAMPLE, + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, } ) ) @@ -137,7 +136,7 @@ class SchemaPostRequestSchema(OpenAPISchema): options = fields.Nested(SchemaPostOptionSchema()) -@docs(tags=["anoncreds - schemas"], summary="Create a schema on the connected ledger") +@docs(tags=["anoncreds - schemas"], summary="Create a schema on the connected datastore") @request_schema(SchemaPostRequestSchema()) @response_schema(SchemaResultSchema(), 200, description="") @tenant_authentication @@ -278,7 +277,7 @@ class CredIdMatchInfo(OpenAPISchema): cred_def_id = fields.Str( metadata={ "description": "Credential definition identifier", - "example": INDY_CRED_DEF_ID_EXAMPLE, + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, }, required=True, ) @@ -297,7 +296,7 @@ class InnerCredDefSchema(OpenAPISchema): schema_id = fields.Str( metadata={ "description": "Schema identifier", - "example": INDY_SCHEMA_ID_EXAMPLE, + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, }, required=True, data_key="schemaId", @@ -305,7 +304,7 @@ class InnerCredDefSchema(OpenAPISchema): issuer_id = fields.Str( metadata={ "description": "Issuer Identifier of the credential definition", - "example": INDY_OR_KEY_DID_EXAMPLE, + "example": ANONCREDS_DID_EXAMPLE, }, required=True, data_key="issuerId", @@ -357,13 +356,13 @@ class CredDefsQueryStringSchema(OpenAPISchema): issuer_id = fields.Str( metadata={ "description": "Issuer Identifier of the credential definition", - "example": INDY_OR_KEY_DID_EXAMPLE, + "example": ANONCREDS_DID_EXAMPLE, } ) schema_id = fields.Str( metadata={ "description": "Schema identifier", - "example": INDY_SCHEMA_ID_EXAMPLE, + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, } ) schema_name = fields.Str( @@ -382,7 +381,7 @@ class CredDefsQueryStringSchema(OpenAPISchema): @docs( tags=["anoncreds - credential definitions"], - summary="Create a credential definition on the connected ledger", + summary="Create a credential definition on the connected datastore", ) @request_schema(CredDefPostRequestSchema()) @response_schema(CredDefResultSchema(), 200, description="") @@ -522,14 +521,14 @@ class InnerRevRegDefSchema(OpenAPISchema): issuer_id = fields.Str( metadata={ "description": "Issuer Identifier of the credential definition or schema", - "example": INDY_OR_KEY_DID_EXAMPLE, + "example": ANONCREDS_DID_EXAMPLE, }, data_key="issuerId", ) cred_def_id = fields.Str( metadata={ "description": "Credential definition identifier", - "example": INDY_SCHEMA_ID_EXAMPLE, + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, }, data_key="credDefId", ) @@ -573,7 +572,7 @@ class RevRegCreateRequestSchemaAnoncreds(OpenAPISchema): @docs( tags=["anoncreds - revocation"], - summary="Create and publish a registration revocation on the connected ledger", + summary="Create and publish a registration revocation on the connected datastore", ) @request_schema(RevRegCreateRequestSchemaAnoncreds()) @response_schema(RevRegDefResultSchema(), 200, description="") @@ -649,7 +648,7 @@ class RevListCreateRequestSchema(OpenAPISchema): rev_reg_def_id = fields.Str( metadata={ "description": "Revocation registry definition identifier", - "example": INDY_REV_REG_ID_EXAMPLE, + "example": ANONCREDS_REV_REG_ID_EXAMPLE, } ) options = fields.Nested(RevListOptionsSchema) @@ -657,7 +656,7 @@ class RevListCreateRequestSchema(OpenAPISchema): @docs( tags=["anoncreds - revocation"], - summary="Create and publish a revocation status list on the connected ledger", + summary="Create and publish a revocation status list on the connected datastore", ) @request_schema(RevListCreateRequestSchema()) @response_schema(RevListResultSchema(), 200, description="") @@ -687,7 +686,7 @@ async def rev_list_post(request: web.BaseRequest): handle_value_error(e) except StorageNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err - except (AnonCredsRevocationError, LedgerError) as err: + except AnonCredsRevocationError as err: raise web.HTTPBadRequest(reason=err.roll_up) from err diff --git a/acapy_agent/anoncreds/tests/test_holder.py b/acapy_agent/anoncreds/tests/test_holder.py index ba69a7ebd7..34d23ef75f 100644 --- a/acapy_agent/anoncreds/tests/test_holder.py +++ b/acapy_agent/anoncreds/tests/test_holder.py @@ -45,8 +45,8 @@ from ...wallet.error import WalletNotFoundError from .. import holder as test_module from ..holder import CATEGORY_CREDENTIAL, AnonCredsHolder, AnonCredsHolderError -from ..models.anoncreds_cred_def import CredDef, CredDefValue, CredDefValuePrimary -from ..models.anoncreds_revocation import GetRevListResult, RevList +from ..models.credential_definition import CredDef, CredDefValue, CredDefValuePrimary +from ..models.revocation import GetRevListResult, RevList from ..registry import AnonCredsRegistry diff --git a/acapy_agent/anoncreds/tests/test_issuer.py b/acapy_agent/anoncreds/tests/test_issuer.py index f165f178d6..7442ffd2ae 100644 --- a/acapy_agent/anoncreds/tests/test_issuer.py +++ b/acapy_agent/anoncreds/tests/test_issuer.py @@ -10,7 +10,7 @@ AnonCredsObjectAlreadyExists, AnonCredsSchemaAlreadyExists, ) -from ...anoncreds.models.anoncreds_cred_def import ( +from ...anoncreds.models.credential_definition import ( CredDef, CredDefResult, CredDefState, @@ -19,7 +19,7 @@ CredDefValueRevocation, GetCredDefResult, ) -from ...anoncreds.models.anoncreds_schema import ( +from ...anoncreds.models.schema import ( AnonCredsSchema, GetSchemaResult, SchemaResult, diff --git a/acapy_agent/anoncreds/tests/test_revocation.py b/acapy_agent/anoncreds/tests/test_revocation.py index ff9ed6d09f..2d9bc62e15 100644 --- a/acapy_agent/anoncreds/tests/test_revocation.py +++ b/acapy_agent/anoncreds/tests/test_revocation.py @@ -16,8 +16,8 @@ from requests import RequestException, Session from ...anoncreds.issuer import AnonCredsIssuer -from ...anoncreds.models.anoncreds_cred_def import CredDef -from ...anoncreds.models.anoncreds_revocation import ( +from ...anoncreds.models.credential_definition import CredDef +from ...anoncreds.models.revocation import ( RevList, RevListResult, RevListState, @@ -26,7 +26,7 @@ RevRegDefState, RevRegDefValue, ) -from ...anoncreds.models.anoncreds_schema import ( +from ...anoncreds.models.schema import ( AnonCredsSchema, GetSchemaResult, ) diff --git a/acapy_agent/anoncreds/tests/test_revocation_setup.py b/acapy_agent/anoncreds/tests/test_revocation_setup.py index e56291efeb..357899f4c9 100644 --- a/acapy_agent/anoncreds/tests/test_revocation_setup.py +++ b/acapy_agent/anoncreds/tests/test_revocation_setup.py @@ -11,7 +11,7 @@ RevRegDefFinishedEvent, RevRegDefFinishedPayload, ) -from ..models.anoncreds_revocation import RevRegDef, RevRegDefValue +from ..models.revocation import RevRegDef, RevRegDefValue from ..revocation import AnonCredsRevocation diff --git a/acapy_agent/anoncreds/tests/test_routes.py b/acapy_agent/anoncreds/tests/test_routes.py index 17c4d15bee..607b81f4ae 100644 --- a/acapy_agent/anoncreds/tests/test_routes.py +++ b/acapy_agent/anoncreds/tests/test_routes.py @@ -7,7 +7,7 @@ from ...admin.request_context import AdminRequestContext from ...anoncreds.base import AnonCredsObjectNotFound from ...anoncreds.issuer import AnonCredsIssuer -from ...anoncreds.models.anoncreds_schema import ( +from ...anoncreds.models.schema import ( AnonCredsSchema, SchemaResult, SchemaState, diff --git a/acapy_agent/anoncreds/tests/test_verifier.py b/acapy_agent/anoncreds/tests/test_verifier.py index 8f912a3f0f..0ff11fcb95 100644 --- a/acapy_agent/anoncreds/tests/test_verifier.py +++ b/acapy_agent/anoncreds/tests/test_verifier.py @@ -3,21 +3,21 @@ import pytest -from ...anoncreds.models.anoncreds_cred_def import ( +from ...anoncreds.models.credential_definition import ( CredDef, CredDefValue, CredDefValuePrimary, CredDefValueRevocation, GetCredDefResult, ) -from ...anoncreds.models.anoncreds_revocation import ( +from ...anoncreds.models.revocation import ( GetRevListResult, GetRevRegDefResult, RevList, RevRegDef, RevRegDefValue, ) -from ...anoncreds.models.anoncreds_schema import ( +from ...anoncreds.models.schema import ( AnonCredsSchema, GetSchemaResult, ) diff --git a/acapy_agent/anoncreds/verifier.py b/acapy_agent/anoncreds/verifier.py index 4f7972371d..849c44ab5b 100644 --- a/acapy_agent/anoncreds/verifier.py +++ b/acapy_agent/anoncreds/verifier.py @@ -1,4 +1,4 @@ -"""Indy-Credx verifier implementation.""" +"""Anoncreds verifier implementation.""" import asyncio import logging @@ -9,10 +9,10 @@ from anoncreds import AnoncredsError, Presentation, W3cPresentation from ..core.profile import Profile -from ..indy.models.xform import indy_proof_req2non_revoc_intervals from ..messaging.util import canon, encode from ..vc.vc_ld.validation_result import PresentationVerificationResult -from .models.anoncreds_cred_def import GetCredDefResult +from .models.credential_definition import GetCredDefResult +from .models.utils import extract_non_revocation_intervals_from_proof_request from .registry import AnonCredsRegistry LOGGER = logging.getLogger(__name__) @@ -45,7 +45,7 @@ def non_revoc_intervals(self, pres_req: dict, pres: dict, cred_defs: dict) -> li """Remove superfluous non-revocation intervals in presentation request. Irrevocable credentials constitute proof of non-revocation, but - indy rejects proof requests with non-revocation intervals lining up + anoncreds rejects proof requests with non-revocation intervals lining up with non-revocable credentials in proof: seek and remove. Args: @@ -116,13 +116,15 @@ async def check_timestamps( Args: profile: relevant profile - pres_req: indy proof request - pres: indy proof request + pres_req: anoncreds proof request + pres: anoncreds proof request rev_reg_defs: rev reg defs by rev reg id, augmented with transaction times """ msgs = [] now = int(time()) - non_revoc_intervals = indy_proof_req2non_revoc_intervals(pres_req) + non_revoc_intervals = extract_non_revocation_intervals_from_proof_request( + pres_req + ) LOGGER.debug(f">>> got non-revoc intervals: {non_revoc_intervals}") # timestamp for irrevocable credential diff --git a/acapy_agent/connections/models/conn_record.py b/acapy_agent/connections/models/conn_record.py index 874d8c3d7f..e27be92c4f 100644 --- a/acapy_agent/connections/models/conn_record.py +++ b/acapy_agent/connections/models/conn_record.py @@ -11,8 +11,8 @@ from ...messaging.valid import ( GENERIC_DID_EXAMPLE, GENERIC_DID_VALIDATE, - INDY_RAW_PUBLIC_KEY_EXAMPLE, - INDY_RAW_PUBLIC_KEY_VALIDATE, + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, UUID4_EXAMPLE, ) from ...protocols.connections.v1_0.message_types import ARIES_PROTOCOL as CONN_PROTO @@ -725,10 +725,10 @@ class Meta: ) invitation_key = fields.Str( required=False, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Public key for connection", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) invitation_msg_id = fields.Str( diff --git a/acapy_agent/connections/models/connection_target.py b/acapy_agent/connections/models/connection_target.py index ad7219db0a..bc81adc42e 100644 --- a/acapy_agent/connections/models/connection_target.py +++ b/acapy_agent/connections/models/connection_target.py @@ -8,8 +8,8 @@ from ...messaging.valid import ( GENERIC_DID_EXAMPLE, GENERIC_DID_VALIDATE, - INDY_RAW_PUBLIC_KEY_EXAMPLE, - INDY_RAW_PUBLIC_KEY_VALIDATE, + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, ) @@ -75,10 +75,10 @@ class Meta: ) recipient_keys = fields.List( fields.Str( - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Recipient public key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ), required=False, @@ -86,10 +86,10 @@ class Meta: ) routing_keys = fields.List( fields.Str( - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Routing key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ), data_key="routingKeys", @@ -98,9 +98,9 @@ class Meta: ) sender_key = fields.Str( required=False, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Sender public key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) diff --git a/acapy_agent/indy/models/cred_def.py b/acapy_agent/indy/models/cred_def.py index dbdaea2b2d..4c5547f96e 100644 --- a/acapy_agent/indy/models/cred_def.py +++ b/acapy_agent/indy/models/cred_def.py @@ -6,8 +6,8 @@ from ...messaging.valid import ( INDY_CRED_DEF_ID_EXAMPLE, INDY_CRED_DEF_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, NUM_STR_WHOLE_EXAMPLE, NUM_STR_WHOLE_VALIDATE, ) @@ -92,10 +92,10 @@ class CredentialDefinitionSchema(OpenAPISchema): """Marshmallow schema for indy cred def.""" ver = fields.Str( - validate=INDY_VERSION_VALIDATE, + validate=MAJOR_MINOR_VERSION_VALIDATE, metadata={ "description": "Node protocol version", - "example": INDY_VERSION_EXAMPLE, + "example": MAJOR_MINOR_VERSION_EXAMPLE, }, ) ident = fields.Str( diff --git a/acapy_agent/indy/models/pres_preview.py b/acapy_agent/indy/models/pres_preview.py index 496c1e93cd..d9e740193e 100644 --- a/acapy_agent/indy/models/pres_preview.py +++ b/acapy_agent/indy/models/pres_preview.py @@ -16,8 +16,8 @@ from ...messaging.valid import ( INDY_CRED_DEF_ID_EXAMPLE, INDY_CRED_DEF_ID_VALIDATE, - INDY_PREDICATE_EXAMPLE, - INDY_PREDICATE_VALIDATE, + PREDICATE_EXAMPLE, + PREDICATE_VALIDATE, ) from ...multitenant.base import BaseMultitenantManager from ...protocols.didcomm_prefix import DIDCommPrefix @@ -100,10 +100,10 @@ class Meta: ) predicate = fields.Str( required=True, - validate=INDY_PREDICATE_VALIDATE, + validate=PREDICATE_VALIDATE, metadata={ "description": "Predicate type ('<', '<=', '>=', or '>')", - "example": INDY_PREDICATE_EXAMPLE, + "example": PREDICATE_EXAMPLE, }, ) threshold = fields.Int( diff --git a/acapy_agent/indy/models/proof_request.py b/acapy_agent/indy/models/proof_request.py index 1c87ecf454..f27ac5a8f6 100644 --- a/acapy_agent/indy/models/proof_request.py +++ b/acapy_agent/indy/models/proof_request.py @@ -15,14 +15,14 @@ from ...messaging.models.openapi import OpenAPISchema from ...messaging.valid import ( INDY_CRED_DEF_ID_EXAMPLE, - INDY_PREDICATE_EXAMPLE, - INDY_PREDICATE_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, INT_EPOCH_EXAMPLE, INT_EPOCH_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, NUM_STR_NATURAL_EXAMPLE, NUM_STR_NATURAL_VALIDATE, + PREDICATE_EXAMPLE, + PREDICATE_VALIDATE, ) @@ -125,10 +125,10 @@ class IndyProofReqPredSpecSchema(OpenAPISchema): ) p_type = fields.Str( required=True, - validate=INDY_PREDICATE_VALIDATE, + validate=PREDICATE_VALIDATE, metadata={ "description": "Predicate type ('<', '<=', '>=', or '>')", - "example": INDY_PREDICATE_EXAMPLE, + "example": PREDICATE_EXAMPLE, }, ) p_value = fields.Int( @@ -251,10 +251,10 @@ class Meta: version = fields.Str( required=False, dump_default="1.0", - validate=INDY_VERSION_VALIDATE, + validate=MAJOR_MINOR_VERSION_VALIDATE, metadata={ "description": "Proof request version", - "example": INDY_VERSION_EXAMPLE, + "example": MAJOR_MINOR_VERSION_EXAMPLE, }, ) requested_attributes = fields.Dict( diff --git a/acapy_agent/indy/models/revocation.py b/acapy_agent/indy/models/revocation.py index a7a2795fbd..14c5617709 100644 --- a/acapy_agent/indy/models/revocation.py +++ b/acapy_agent/indy/models/revocation.py @@ -12,8 +12,8 @@ INDY_CRED_DEF_ID_VALIDATE, INDY_REV_REG_ID_EXAMPLE, INDY_REV_REG_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, NATURAL_NUM_EXAMPLE, NATURAL_NUM_VALIDATE, ) @@ -180,10 +180,10 @@ class Meta: unknown = EXCLUDE ver = fields.Str( - validate=INDY_VERSION_VALIDATE, + validate=MAJOR_MINOR_VERSION_VALIDATE, metadata={ "description": "Version of revocation registry definition", - "example": INDY_VERSION_EXAMPLE, + "example": MAJOR_MINOR_VERSION_EXAMPLE, }, ) id_ = fields.Str( @@ -294,10 +294,10 @@ class Meta: unknown = EXCLUDE ver = fields.Str( - validate=INDY_VERSION_VALIDATE, + validate=MAJOR_MINOR_VERSION_VALIDATE, metadata={ "description": "Version of revocation registry entry", - "example": INDY_VERSION_EXAMPLE, + "example": MAJOR_MINOR_VERSION_EXAMPLE, }, ) value = fields.Nested( diff --git a/acapy_agent/indy/models/schema.py b/acapy_agent/indy/models/schema.py index 5dff944356..df91802bc7 100644 --- a/acapy_agent/indy/models/schema.py +++ b/acapy_agent/indy/models/schema.py @@ -6,8 +6,8 @@ from ...messaging.valid import ( INDY_SCHEMA_ID_EXAMPLE, INDY_SCHEMA_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, NATURAL_NUM_EXAMPLE, NATURAL_NUM_VALIDATE, ) @@ -17,10 +17,10 @@ class SchemaSchema(OpenAPISchema): """Marshmallow schema for indy schema.""" ver = fields.Str( - validate=INDY_VERSION_VALIDATE, + validate=MAJOR_MINOR_VERSION_VALIDATE, metadata={ "description": "Node protocol version", - "example": INDY_VERSION_EXAMPLE, + "example": MAJOR_MINOR_VERSION_EXAMPLE, }, ) ident = fields.Str( @@ -38,8 +38,11 @@ class SchemaSchema(OpenAPISchema): } ) version = fields.Str( - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Schema version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, ) attr_names = fields.List( fields.Str(metadata={"description": "Attribute name", "example": "score"}), diff --git a/acapy_agent/ledger/routes.py b/acapy_agent/ledger/routes.py index 4d63eb5af3..fee5e15261 100644 --- a/acapy_agent/ledger/routes.py +++ b/acapy_agent/ledger/routes.py @@ -25,10 +25,10 @@ ENDPOINT_VALIDATE, INDY_DID_EXAMPLE, INDY_DID_VALIDATE, - INDY_RAW_PUBLIC_KEY_EXAMPLE, - INDY_RAW_PUBLIC_KEY_VALIDATE, INT_EPOCH_EXAMPLE, INT_EPOCH_VALIDATE, + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, UUID4_EXAMPLE, ) from ..multitenant.base import BaseMultitenantManager @@ -133,10 +133,10 @@ class RegisterLedgerNymQueryStringSchema(OpenAPISchema): ) verkey = fields.Str( required=True, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Verification key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) alias = fields.Str( @@ -230,10 +230,10 @@ class GetDIDVerkeyResponseSchema(OpenAPISchema): verkey = fields.Str( allow_none=True, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Full verification key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) diff --git a/acapy_agent/messaging/credential_definitions/util.py b/acapy_agent/messaging/credential_definitions/util.py index fb732ecd44..1cca544747 100644 --- a/acapy_agent/messaging/credential_definitions/util.py +++ b/acapy_agent/messaging/credential_definitions/util.py @@ -13,8 +13,8 @@ INDY_DID_VALIDATE, INDY_SCHEMA_ID_EXAMPLE, INDY_SCHEMA_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, ) CRED_DEF_SENT_RECORD_TYPE = "cred_def_sent" @@ -41,8 +41,11 @@ class CredDefQueryStringSchema(OpenAPISchema): ) schema_version = fields.Str( required=False, - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Schema version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, ) issuer_did = fields.Str( required=False, diff --git a/acapy_agent/messaging/decorators/attach_decorator.py b/acapy_agent/messaging/decorators/attach_decorator.py index 98fc177996..7b17c6f670 100644 --- a/acapy_agent/messaging/decorators/attach_decorator.py +++ b/acapy_agent/messaging/decorators/attach_decorator.py @@ -29,8 +29,8 @@ BASE64_VALIDATE, BASE64URL_NO_PAD_EXAMPLE, BASE64URL_NO_PAD_VALIDATE, - INDY_ISO8601_DATETIME_EXAMPLE, - INDY_ISO8601_DATETIME_VALIDATE, + ISO8601_DATETIME_EXAMPLE, + ISO8601_DATETIME_VALIDATE, JWS_HEADER_KID_EXAMPLE, JWS_HEADER_KID_VALIDATE, SHA256_EXAMPLE, @@ -778,12 +778,12 @@ class Meta: ) lastmod_time = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": ( "Hint regarding last modification datetime, in ISO-8601 format" ), - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) description = fields.Str( diff --git a/acapy_agent/messaging/decorators/service_decorator.py b/acapy_agent/messaging/decorators/service_decorator.py index 0a4695a01c..e4f94b90e3 100644 --- a/acapy_agent/messaging/decorators/service_decorator.py +++ b/acapy_agent/messaging/decorators/service_decorator.py @@ -9,7 +9,10 @@ from marshmallow import EXCLUDE, fields from ..models.base import BaseModel, BaseModelSchema -from ..valid import INDY_RAW_PUBLIC_KEY_EXAMPLE, INDY_RAW_PUBLIC_KEY_VALIDATE +from ..valid import ( + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, +) class ServiceDecorator(BaseModel): @@ -82,10 +85,10 @@ class Meta: recipient_keys = fields.List( fields.Str( - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Recipient public key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ), data_key="recipientKeys", @@ -102,10 +105,10 @@ class Meta: ) routing_keys = fields.List( fields.Str( - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Routing key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ), data_key="routingKeys", diff --git a/acapy_agent/messaging/decorators/signature_decorator.py b/acapy_agent/messaging/decorators/signature_decorator.py index 22ec1b38c1..ed7a217611 100644 --- a/acapy_agent/messaging/decorators/signature_decorator.py +++ b/acapy_agent/messaging/decorators/signature_decorator.py @@ -3,7 +3,7 @@ import json import struct import time -from typing import Optional +from typing import Optional, Tuple from marshmallow import EXCLUDE, fields @@ -15,8 +15,8 @@ from ..valid import ( BASE64URL_EXAMPLE, BASE64URL_VALIDATE, - INDY_RAW_PUBLIC_KEY_EXAMPLE, - INDY_RAW_PUBLIC_KEY_VALIDATE, + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, ) @@ -86,7 +86,7 @@ async def create( signer=signer, ) - def decode(self) -> (object, int): + def decode(self) -> Tuple[object, int]: """Decode the signature to its timestamp and value. Returns: @@ -164,9 +164,9 @@ class Meta: ) signer = fields.Str( required=True, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Signer verification key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) diff --git a/acapy_agent/messaging/decorators/timing_decorator.py b/acapy_agent/messaging/decorators/timing_decorator.py index 7ad8fc8c86..cd8dd829d7 100644 --- a/acapy_agent/messaging/decorators/timing_decorator.py +++ b/acapy_agent/messaging/decorators/timing_decorator.py @@ -11,7 +11,7 @@ from ..models.base import BaseModel, BaseModelSchema from ..util import datetime_to_str -from ..valid import INDY_ISO8601_DATETIME_EXAMPLE, INDY_ISO8601_DATETIME_VALIDATE +from ..valid import ISO8601_DATETIME_EXAMPLE, ISO8601_DATETIME_VALIDATE class TimingDecorator(BaseModel): @@ -62,34 +62,34 @@ class Meta: in_time = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": "Time of message receipt", - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) out_time = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": "Time of message dispatch", - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) stale_time = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": "Time when message should be considered stale", - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) expires_time = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": "Time when message should be considered expired", - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) delay_milli = fields.Int( @@ -102,9 +102,9 @@ class Meta: ) wait_until_time = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": "Earliest time at which to perform processing", - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) diff --git a/acapy_agent/messaging/models/base_record.py b/acapy_agent/messaging/models/base_record.py index a89894dfc6..e613c6e6d9 100644 --- a/acapy_agent/messaging/models/base_record.py +++ b/acapy_agent/messaging/models/base_record.py @@ -20,7 +20,7 @@ ) from ...storage.record import StorageRecord from ..util import datetime_to_str, time_now -from ..valid import INDY_ISO8601_DATETIME_EXAMPLE, INDY_ISO8601_DATETIME_VALIDATE +from ..valid import ISO8601_DATETIME_EXAMPLE, ISO8601_DATETIME_VALIDATE from .base import BaseModel, BaseModelError, BaseModelSchema LOGGER = logging.getLogger(__name__) @@ -583,18 +583,18 @@ class Meta: ) created_at = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": "Time of record creation", - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) updated_at = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": "Time of last record update", - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) diff --git a/acapy_agent/messaging/schemas/routes.py b/acapy_agent/messaging/schemas/routes.py index d8128a5398..c31983d264 100644 --- a/acapy_agent/messaging/schemas/routes.py +++ b/acapy_agent/messaging/schemas/routes.py @@ -49,8 +49,8 @@ B58, INDY_SCHEMA_ID_EXAMPLE, INDY_SCHEMA_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, UUID4_EXAMPLE, ) from .util import ( @@ -70,8 +70,11 @@ class SchemaSendRequestSchema(OpenAPISchema): ) schema_version = fields.Str( required=True, - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Schema version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, ) attributes = fields.List( fields.Str(metadata={"description": "attribute name", "example": "score"}), diff --git a/acapy_agent/messaging/schemas/util.py b/acapy_agent/messaging/schemas/util.py index 35f8ce5bae..9a3e0cf989 100644 --- a/acapy_agent/messaging/schemas/util.py +++ b/acapy_agent/messaging/schemas/util.py @@ -11,8 +11,8 @@ INDY_DID_VALIDATE, INDY_SCHEMA_ID_EXAMPLE, INDY_SCHEMA_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, ) @@ -37,8 +37,11 @@ class SchemaQueryStringSchema(OpenAPISchema): ) schema_version = fields.Str( required=False, - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Schema version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, ) diff --git a/acapy_agent/messaging/tests/test_valid.py b/acapy_agent/messaging/tests/test_valid.py index 0f3b3d3363..b99737c4a8 100644 --- a/acapy_agent/messaging/tests/test_valid.py +++ b/acapy_agent/messaging/tests/test_valid.py @@ -19,20 +19,20 @@ INDY_CRED_REV_ID_VALIDATE, INDY_DID_VALIDATE, INDY_EXTRA_WQL_VALIDATE, - INDY_ISO8601_DATETIME_VALIDATE, - INDY_PREDICATE_VALIDATE, - INDY_RAW_PUBLIC_KEY_VALIDATE, INDY_REV_REG_ID_VALIDATE, INDY_REV_REG_SIZE_VALIDATE, INDY_SCHEMA_ID_VALIDATE, - INDY_VERSION_VALIDATE, INDY_WQL_VALIDATE, INT_EPOCH_VALIDATE, + ISO8601_DATETIME_VALIDATE, JWS_HEADER_KID_VALIDATE, JWT_VALIDATE, + MAJOR_MINOR_VERSION_VALIDATE, NATURAL_NUM_VALIDATE, NUM_STR_NATURAL_VALIDATE, NUM_STR_WHOLE_VALIDATE, + PREDICATE_VALIDATE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, SHA256_VALIDATE, UUID4_VALIDATE, WHOLE_NUM_VALIDATE, @@ -141,9 +141,11 @@ def test_indy_raw_public_key(self): ] for non_indy_raw_public_key in non_indy_raw_public_keys: with self.assertRaises(ValidationError): - INDY_RAW_PUBLIC_KEY_VALIDATE(non_indy_raw_public_key) + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE(non_indy_raw_public_key) - INDY_RAW_PUBLIC_KEY_VALIDATE("Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9h") + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE( + "Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9h" + ) def test_jws_header_kid(self): non_kids = [ @@ -283,12 +285,12 @@ def test_version(self): non_versions = ["-1", "", "3_5", "3.5a"] for non_version in non_versions: with self.assertRaises(ValidationError): - INDY_VERSION_VALIDATE(non_version) + MAJOR_MINOR_VERSION_VALIDATE(non_version) - INDY_VERSION_VALIDATE("1.0") - INDY_VERSION_VALIDATE(".05") - INDY_VERSION_VALIDATE("1.2.3") - INDY_VERSION_VALIDATE("..") # perverse but technically OK + MAJOR_MINOR_VERSION_VALIDATE("1.0") + MAJOR_MINOR_VERSION_VALIDATE(".05") + MAJOR_MINOR_VERSION_VALIDATE("1.2.3") + MAJOR_MINOR_VERSION_VALIDATE("..") # perverse but technically OK def test_schema_id(self): non_schema_ids = [ @@ -311,12 +313,12 @@ def test_predicate(self): non_predicates = [">>", "", " >= ", "<<<=", "==", "=", "!="] for non_predicate in non_predicates: with self.assertRaises(ValidationError): - INDY_PREDICATE_VALIDATE(non_predicate) + PREDICATE_VALIDATE(non_predicate) - INDY_PREDICATE_VALIDATE("<") - INDY_PREDICATE_VALIDATE("<=") - INDY_PREDICATE_VALIDATE(">=") - INDY_PREDICATE_VALIDATE(">") + PREDICATE_VALIDATE("<") + PREDICATE_VALIDATE("<=") + PREDICATE_VALIDATE(">=") + PREDICATE_VALIDATE(">") def test_indy_date(self): non_datetimes = [ @@ -329,17 +331,17 @@ def test_indy_date(self): ] for non_datetime in non_datetimes: with self.assertRaises(ValidationError): - INDY_ISO8601_DATETIME_VALIDATE(non_datetime) - - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00Z") - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01T00:00:00Z") - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01T00:00:00") - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00") - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00+00:00") - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00-00:00") - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01 00:00-00:00") - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00.1-00:00") - INDY_ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00.123456-00:00") + ISO8601_DATETIME_VALIDATE(non_datetime) + + ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00Z") + ISO8601_DATETIME_VALIDATE("2020-01-01T00:00:00Z") + ISO8601_DATETIME_VALIDATE("2020-01-01T00:00:00") + ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00") + ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00+00:00") + ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00-00:00") + ISO8601_DATETIME_VALIDATE("2020-01-01 00:00-00:00") + ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00.1-00:00") + ISO8601_DATETIME_VALIDATE("2020-01-01 00:00:00.123456-00:00") def test_indy_wql(self): non_wqls = [ diff --git a/acapy_agent/messaging/valid.py b/acapy_agent/messaging/valid.py index fc1749d600..c5026ca382 100644 --- a/acapy_agent/messaging/valid.py +++ b/acapy_agent/messaging/valid.py @@ -362,6 +362,21 @@ def __init__(self): ) +class AnoncredsDID(Regexp): + """Validate value against indy DID.""" + + EXAMPLE = "did:(method):WgWxqztrNooG92RXvxSTWv" + PATTERN = re.compile("^(did:[a-z]:.+$)?$") + + def __init__(self): + """Initialize the instance.""" + + super().__init__( + IndyDID.PATTERN, + error="Value {input} is not an decentralized identifier (DID)", + ) + + class DIDValidation(Regexp): """Validate value against any valid DID spec.""" @@ -400,8 +415,8 @@ def __init__(self): ) -class IndyRawPublicKey(Regexp): - """Validate value against indy (Ed25519VerificationKey2018) raw public key.""" +class RawPublicEd25519VerificationKey2018(Regexp): + """Validate value against (Ed25519VerificationKey2018) raw public key.""" EXAMPLE = "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" PATTERN = rf"^[{B58}]{{43,44}}$" @@ -410,7 +425,7 @@ def __init__(self): """Initialize the instance.""" super().__init__( - IndyRawPublicKey.PATTERN, + RawPublicEd25519VerificationKey2018.PATTERN, error="Value {input} is not a raw Ed25519VerificationKey2018 key", ) @@ -423,7 +438,9 @@ class RoutingKey(Regexp): """ EXAMPLE = DIDKey.EXAMPLE - PATTERN = re.compile(DIDKey.PATTERN.pattern + "|" + IndyRawPublicKey.PATTERN) + PATTERN = re.compile( + DIDKey.PATTERN.pattern + "|" + RawPublicEd25519VerificationKey2018.PATTERN + ) def __init__(self): """Initialize the instance.""" @@ -458,8 +475,23 @@ def __init__(self): ) -class IndyVersion(Regexp): - """Validate value against indy version specification.""" +class AnoncredsCredDefId(Regexp): + """Validate value against anoncreds credential definition identifier specification.""" + + EXAMPLE = "did:(method):3:CL:20:tag" + PATTERN = r"^(.+$)" + + def __init__(self): + """Initialize the instance.""" + + super().__init__( + IndyCredDefId.PATTERN, + error="Value {input} is not an anoncreds credential definition identifier", + ) + + +class MajorMinorVersion(Regexp): + """Validate value against major minor version specification.""" EXAMPLE = "1.0" PATTERN = r"^[0-9.]+$" @@ -468,8 +500,8 @@ def __init__(self): """Initialize the instance.""" super().__init__( - IndyVersion.PATTERN, - error="Value {input} is not an indy version (use only digits and '.')", + MajorMinorVersion.PATTERN, + error="Value {input} is not a valid version major minor version (use only digits and '.')", # noqa: E501 ) @@ -488,6 +520,21 @@ def __init__(self): ) +class AnoncredsSchemaId(Regexp): + """Validate value against indy schema identifier specification.""" + + EXAMPLE = "did:(method):2:schema_name:1.0" + PATTERN = r"^(.+$)" + + def __init__(self): + """Initialize the instance.""" + + super().__init__( + IndySchemaId.PATTERN, + error="Value {input} is not an anoncreds schema identifier", + ) + + class IndyRevRegId(Regexp): """Validate value against indy revocation registry identifier specification.""" @@ -508,6 +555,21 @@ def __init__(self): ) +class AnoncredsRevRegId(Regexp): + """Validate value against anoncreds revocation registry identifier specification.""" + + EXAMPLE = "did:(method):4:did::3:CL:20:tag:CL_ACCUM:0" + PATTERN = r"^(.+$)" + + def __init__(self): + """Initialize the instance.""" + + super().__init__( + AnoncredsRevRegId.PATTERN, + error="Value {input} is not an anoncreds revocation registry identifier", + ) + + class IndyCredRevId(Regexp): """Validate value against indy credential revocation identifier specification.""" @@ -523,8 +585,8 @@ def __init__(self): ) -class IndyPredicate(OneOf): - """Validate value against indy predicate.""" +class Predicate(OneOf): + """Validate value against predicate.""" EXAMPLE = ">=" @@ -537,8 +599,8 @@ def __init__(self): ) -class IndyISO8601DateTime(Regexp): - """Validate value against ISO 8601 datetime format, indy profile.""" +class ISO8601DateTime(Regexp): + """Validate value against ISO 8601 datetime format.""" EXAMPLE = epoch_to_str(EXAMPLE_TIMESTAMP) PATTERN = ( @@ -550,7 +612,7 @@ def __init__(self): """Initialize the instance.""" super().__init__( - IndyISO8601DateTime.PATTERN, + ISO8601DateTime.PATTERN, error="Value {input} is not a date in valid format", ) @@ -960,29 +1022,38 @@ def __init__( GENERIC_DID_VALIDATE = MaybeIndyDID() GENERIC_DID_EXAMPLE = MaybeIndyDID.EXAMPLE -INDY_RAW_PUBLIC_KEY_VALIDATE = IndyRawPublicKey() -INDY_RAW_PUBLIC_KEY_EXAMPLE = IndyRawPublicKey.EXAMPLE +RAW_ED25519_2018_PUBLIC_KEY_VALIDATE = RawPublicEd25519VerificationKey2018() +RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE = RawPublicEd25519VerificationKey2018.EXAMPLE INDY_SCHEMA_ID_VALIDATE = IndySchemaId() INDY_SCHEMA_ID_EXAMPLE = IndySchemaId.EXAMPLE +ANONCREDS_SCHEMA_ID_VALIDATE = AnoncredsSchemaId() +ANONCREDS_SCHEMA_ID_EXAMPLE = AnoncredsSchemaId.EXAMPLE + INDY_CRED_DEF_ID_VALIDATE = IndyCredDefId() INDY_CRED_DEF_ID_EXAMPLE = IndyCredDefId.EXAMPLE +ANONCREDS_CRED_DEF_ID_VALIDATE = AnoncredsCredDefId() +ANONCREDS_CRED_DEF_ID_EXAMPLE = AnoncredsCredDefId.EXAMPLE + INDY_REV_REG_ID_VALIDATE = IndyRevRegId() INDY_REV_REG_ID_EXAMPLE = IndyRevRegId.EXAMPLE +ANONCREDS_REV_REG_ID_VALIDATE = AnoncredsRevRegId() +ANONCREDS_REV_REG_ID_EXAMPLE = AnoncredsRevRegId.EXAMPLE + INDY_CRED_REV_ID_VALIDATE = IndyCredRevId() INDY_CRED_REV_ID_EXAMPLE = IndyCredRevId.EXAMPLE -INDY_VERSION_VALIDATE = IndyVersion() -INDY_VERSION_EXAMPLE = IndyVersion.EXAMPLE +MAJOR_MINOR_VERSION_VALIDATE = MajorMinorVersion() +MAJOR_MINOR_VERSION_EXAMPLE = MajorMinorVersion.EXAMPLE -INDY_PREDICATE_VALIDATE = IndyPredicate() -INDY_PREDICATE_EXAMPLE = IndyPredicate.EXAMPLE +PREDICATE_VALIDATE = Predicate() +PREDICATE_EXAMPLE = Predicate.EXAMPLE -INDY_ISO8601_DATETIME_VALIDATE = IndyISO8601DateTime() -INDY_ISO8601_DATETIME_EXAMPLE = IndyISO8601DateTime.EXAMPLE +ISO8601_DATETIME_VALIDATE = ISO8601DateTime() +ISO8601_DATETIME_EXAMPLE = ISO8601DateTime.EXAMPLE RFC3339_DATETIME_VALIDATE = RFC3339DateTime() RFC3339_DATETIME_EXAMPLE = RFC3339DateTime.EXAMPLE @@ -1037,3 +1108,6 @@ def __init__( INDY_OR_KEY_DID_VALIDATE = IndyOrKeyDID() INDY_OR_KEY_DID_EXAMPLE = IndyOrKeyDID.EXAMPLE + +ANONCREDS_DID_VALIDATE = AnoncredsDID() +ANONCREDS_DID_EXAMPLE = AnoncredsDID.EXAMPLE diff --git a/acapy_agent/protocols/basicmessage/v1_0/messages/basicmessage.py b/acapy_agent/protocols/basicmessage/v1_0/messages/basicmessage.py index 840be506b9..1a8940a904 100644 --- a/acapy_agent/protocols/basicmessage/v1_0/messages/basicmessage.py +++ b/acapy_agent/protocols/basicmessage/v1_0/messages/basicmessage.py @@ -8,8 +8,8 @@ from .....messaging.agent_message import AgentMessage, AgentMessageSchema from .....messaging.util import datetime_now, datetime_to_str from .....messaging.valid import ( - INDY_ISO8601_DATETIME_EXAMPLE, - INDY_ISO8601_DATETIME_VALIDATE, + ISO8601_DATETIME_EXAMPLE, + ISO8601_DATETIME_VALIDATE, ) from ..message_types import BASIC_MESSAGE, PROTOCOL_PACKAGE @@ -63,12 +63,12 @@ class Meta: sent_time = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": ( "Time message was sent, ISO8601 with space date/time separator" ), - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) content = fields.Str( diff --git a/acapy_agent/protocols/connections/v1_0/messages/connection_invitation.py b/acapy_agent/protocols/connections/v1_0/messages/connection_invitation.py index d983eb0ede..51e9f5f3c2 100644 --- a/acapy_agent/protocols/connections/v1_0/messages/connection_invitation.py +++ b/acapy_agent/protocols/connections/v1_0/messages/connection_invitation.py @@ -10,8 +10,8 @@ from .....messaging.valid import ( GENERIC_DID_EXAMPLE, GENERIC_DID_VALIDATE, - INDY_RAW_PUBLIC_KEY_EXAMPLE, - INDY_RAW_PUBLIC_KEY_VALIDATE, + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, ) from .....wallet.util import b64_to_bytes, bytes_to_b64 from ..message_types import CONNECTION_INVITATION, PROTOCOL_PACKAGE @@ -131,10 +131,10 @@ class Meta: ) recipient_keys = fields.List( fields.Str( - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Recipient public key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ), data_key="recipientKeys", @@ -151,10 +151,10 @@ class Meta: ) routing_keys = fields.List( fields.Str( - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Routing key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ), data_key="routingKeys", diff --git a/acapy_agent/protocols/connections/v1_0/routes.py b/acapy_agent/protocols/connections/v1_0/routes.py index c6cbe47ecd..63344e5749 100644 --- a/acapy_agent/protocols/connections/v1_0/routes.py +++ b/acapy_agent/protocols/connections/v1_0/routes.py @@ -26,8 +26,8 @@ GENERIC_DID_VALIDATE, INDY_DID_EXAMPLE, INDY_DID_VALIDATE, - INDY_RAW_PUBLIC_KEY_EXAMPLE, - INDY_RAW_PUBLIC_KEY_VALIDATE, + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, UUID4_EXAMPLE, UUID4_VALIDATE, ) @@ -91,10 +91,10 @@ class CreateInvitationRequestSchema(OpenAPISchema): recipient_keys = fields.List( fields.Str( - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Recipient public key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ), required=False, @@ -109,10 +109,10 @@ class CreateInvitationRequestSchema(OpenAPISchema): ) routing_keys = fields.List( fields.Str( - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Routing key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ), required=False, @@ -210,10 +210,10 @@ class ConnectionStaticResultSchema(OpenAPISchema): ) my_verkey = fields.Str( required=True, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "My verification key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) my_endpoint = fields.Str( @@ -228,10 +228,10 @@ class ConnectionStaticResultSchema(OpenAPISchema): ) their_verkey = fields.Str( required=True, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Remote verification key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) record = fields.Nested(ConnRecordSchema(), required=True) @@ -245,10 +245,10 @@ class ConnectionsListQueryStringSchema(PaginatedQuerySchema): ) invitation_key = fields.Str( required=False, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "invitation key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) my_did = fields.Str( diff --git a/acapy_agent/protocols/issue_credential/v1_0/messages/credential_proposal.py b/acapy_agent/protocols/issue_credential/v1_0/messages/credential_proposal.py index 05416c54b1..d53ce0e549 100644 --- a/acapy_agent/protocols/issue_credential/v1_0/messages/credential_proposal.py +++ b/acapy_agent/protocols/issue_credential/v1_0/messages/credential_proposal.py @@ -12,8 +12,8 @@ INDY_DID_VALIDATE, INDY_SCHEMA_ID_EXAMPLE, INDY_SCHEMA_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, ) from ..message_types import CREDENTIAL_PROPOSAL, PROTOCOL_PACKAGE from .inner.credential_preview import CredentialPreview, CredentialPreviewSchema @@ -104,8 +104,8 @@ class Meta: schema_version = fields.Str( required=False, allow_none=False, - validate=INDY_VERSION_VALIDATE, - metadata={"example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={"example": MAJOR_MINOR_VERSION_EXAMPLE}, ) cred_def_id = fields.Str( required=False, diff --git a/acapy_agent/protocols/issue_credential/v1_0/routes.py b/acapy_agent/protocols/issue_credential/v1_0/routes.py index 725ad02992..1b5581a51b 100644 --- a/acapy_agent/protocols/issue_credential/v1_0/routes.py +++ b/acapy_agent/protocols/issue_credential/v1_0/routes.py @@ -31,8 +31,8 @@ INDY_DID_VALIDATE, INDY_SCHEMA_ID_EXAMPLE, INDY_SCHEMA_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, UUID4_EXAMPLE, UUID4_VALIDATE, ) @@ -139,8 +139,11 @@ class V10CredentialCreateSchema(AdminAPIMessageTracingSchema): ) schema_version = fields.Str( required=False, - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Schema version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, ) issuer_did = fields.Str( required=False, @@ -198,8 +201,11 @@ class V10CredentialProposalRequestSchemaBase(AdminAPIMessageTracingSchema): ) schema_version = fields.Str( required=False, - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Schema version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, ) issuer_did = fields.Str( required=False, diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py index e72614437a..a25e4bb62c 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/handler.py @@ -1,30 +1,28 @@ -"""V2.0 issue-credential indy credential format handler.""" +"""V2.0 issue-credential anoncreds credential format handler.""" import json import logging from typing import Mapping, Optional, Tuple +from anoncreds import CredentialDefinition, Schema from marshmallow import RAISE +from ......anoncreds.base import AnonCredsResolutionError from ......anoncreds.holder import AnonCredsHolder, AnonCredsHolderError -from ......anoncreds.issuer import AnonCredsIssuer +from ......anoncreds.issuer import CATEGORY_CRED_DEF, CATEGORY_SCHEMA, AnonCredsIssuer +from ......anoncreds.models.credential import AnoncredsCredentialSchema +from ......anoncreds.models.credential_offer import AnoncredsCredentialOfferSchema +from ......anoncreds.models.credential_proposal import ( + AnoncredsCredentialDefinitionProposal, +) +from ......anoncreds.models.credential_request import AnoncredsCredRequestSchema from ......anoncreds.registry import AnonCredsRegistry from ......anoncreds.revocation import AnonCredsRevocation from ......cache.base import BaseCache -from ......indy.models.cred import IndyCredentialSchema -from ......indy.models.cred_abstract import IndyCredAbstractSchema -from ......indy.models.cred_request import IndyCredRequestSchema -from ......ledger.base import BaseLedger -from ......ledger.multiple_ledger.ledger_requests_executor import ( - GET_CRED_DEF, - IndyLedgerRequestsExecutor, -) from ......messaging.credential_definitions.util import ( CRED_DEF_SENT_RECORD_TYPE, - CredDefQueryStringSchema, ) from ......messaging.decorators.attach_decorator import AttachDecorator -from ......multitenant.base import BaseMultitenantManager from ......revocation_anoncreds.models.issuer_cred_rev_record import IssuerCredRevRecord from ......storage.base import BaseStorage from ...message_types import ( @@ -40,16 +38,16 @@ from ...messages.cred_proposal import V20CredProposal from ...messages.cred_request import V20CredRequest from ...models.cred_ex_record import V20CredExRecord -from ...models.detail.indy import V20CredExRecordIndy +from ...models.detail.anoncreds import V20CredExRecordAnoncreds from ..handler import CredFormatAttachment, V20CredFormatError, V20CredFormatHandler LOGGER = logging.getLogger(__name__) class AnonCredsCredFormatHandler(V20CredFormatHandler): - """Indy credential format handler.""" + """Anoncreds credential format handler.""" - format = V20CredFormat.Format.INDY + format = V20CredFormat.Format.ANONCREDS @classmethod def validate_fields(cls, message_type: str, attachment_data: Mapping): @@ -71,10 +69,10 @@ def validate_fields(cls, message_type: str, attachment_data: Mapping): """ mapping = { - CRED_20_PROPOSAL: CredDefQueryStringSchema, - CRED_20_OFFER: IndyCredAbstractSchema, - CRED_20_REQUEST: IndyCredRequestSchema, - CRED_20_ISSUE: IndyCredentialSchema, + CRED_20_PROPOSAL: AnoncredsCredentialDefinitionProposal, + CRED_20_OFFER: AnoncredsCredentialOfferSchema, + CRED_20_REQUEST: AnoncredsCredRequestSchema, + CRED_20_ISSUE: AnoncredsCredentialSchema, } # Get schema class @@ -83,7 +81,7 @@ def validate_fields(cls, message_type: str, attachment_data: Mapping): # Validate, throw if not valid Schema(unknown=RAISE).load(attachment_data) - async def get_detail_record(self, cred_ex_id: str) -> V20CredExRecordIndy: + async def get_detail_record(self, cred_ex_id: str) -> V20CredExRecordAnoncreds: """Retrieve credential exchange detail record by cred_ex_id.""" async with self.profile.session() as session: @@ -167,7 +165,7 @@ async def _match_sent_cred_def_id(self, tag_query: Mapping[str, str]) -> str: async def create_proposal( self, cred_ex_record: V20CredExRecord, proposal_data: Mapping[str, str] ) -> Tuple[V20CredFormat, AttachDecorator]: - """Create indy credential proposal.""" + """Create anoncreds credential proposal.""" if proposal_data is None: proposal_data = {} @@ -176,7 +174,7 @@ async def create_proposal( async def receive_proposal( self, cred_ex_record: V20CredExRecord, cred_proposal_message: V20CredProposal ) -> None: - """Receive indy credential proposal. + """Receive anoncreds credential proposal. No custom handling is required for this step. """ @@ -184,35 +182,37 @@ async def receive_proposal( async def create_offer( self, cred_proposal_message: V20CredProposal ) -> CredFormatAttachment: - """Create indy credential offer.""" + """Create anoncreds credential offer.""" issuer = AnonCredsIssuer(self.profile) - ledger = self.profile.inject(BaseLedger) cache = self.profile.inject_or(BaseCache) + anoncreds_attachment = cred_proposal_message.attachment( + AnonCredsCredFormatHandler.format + ) + + if not anoncreds_attachment: + anoncreds_attachment = cred_proposal_message.attachment( + V20CredFormat.Format.INDY.api + ) + cred_def_id = await issuer.match_created_credential_definitions( - **cred_proposal_message.attachment(AnonCredsCredFormatHandler.format) + **anoncreds_attachment ) async def _create(): offer_json = await issuer.create_credential_offer(cred_def_id) return json.loads(offer_json) - multitenant_mgr = self.profile.inject_or(BaseMultitenantManager) - if multitenant_mgr: - ledger_exec_inst = IndyLedgerRequestsExecutor(self.profile) - else: - ledger_exec_inst = self.profile.inject(IndyLedgerRequestsExecutor) - ledger = ( - await ledger_exec_inst.get_ledger_for_identifier( - cred_def_id, - txn_record_type=GET_CRED_DEF, + async with self.profile.session() as session: + cred_def_entry = await session.handle.fetch(CATEGORY_CRED_DEF, cred_def_id) + cred_def_dict = CredentialDefinition.load(cred_def_entry.value).to_dict() + schema_entry = await session.handle.fetch( + CATEGORY_SCHEMA, cred_def_dict["schemaId"] ) - )[1] - async with ledger: - schema_id = await ledger.credential_definition_id2schema_id(cred_def_id) - schema = await ledger.get_schema(schema_id) - schema_attrs = set(schema["attrNames"]) + schema_dict = Schema.load(schema_entry.value).to_dict() + + schema_attrs = set(schema_dict["attrNames"]) preview_attrs = set(cred_proposal_message.credential_preview.attr_dict()) if preview_attrs != schema_attrs: raise V20CredFormatError( @@ -238,23 +238,26 @@ async def _create(): async def receive_offer( self, cred_ex_record: V20CredExRecord, cred_offer_message: V20CredOffer ) -> None: - """Receive indy credential offer.""" + """Receive anoncreds credential offer.""" async def create_request( self, cred_ex_record: V20CredExRecord, request_data: Optional[Mapping] = None ) -> CredFormatAttachment: - """Create indy credential request.""" + """Create anoncreds credential request.""" if cred_ex_record.state != V20CredExRecord.STATE_OFFER_RECEIVED: raise V20CredFormatError( - "Indy issue credential format cannot start from credential request" + "Anoncreds issue credential format cannot start from credential request" ) await self._check_uniqueness(cred_ex_record.cred_ex_id) - holder_did = request_data.get("holder_did") if request_data else None + + # For backwards compatibility, remove indy backup when indy format is retired + from ..indy.handler import IndyCredFormatHandler + cred_offer = cred_ex_record.cred_offer.attachment( AnonCredsCredFormatHandler.format - ) + ) or cred_ex_record.cred_offer.attachment(IndyCredFormatHandler.format) if "nonce" not in cred_offer: raise V20CredFormatError("Missing nonce in credential offer") @@ -265,19 +268,24 @@ async def create_request( async def _create(): anoncreds_registry = self.profile.inject(AnonCredsRegistry) - cred_def_result = await anoncreds_registry.get_credential_definition( - self.profile, cred_def_id - ) - - holder = AnonCredsHolder(self.profile) - request_json, metadata_json = await holder.create_credential_request( - cred_offer, cred_def_result.credential_definition, holder_did - ) + try: + cred_def_result = await anoncreds_registry.get_credential_definition( + self.profile, cred_def_id + ) + holder = AnonCredsHolder(self.profile) + request_json, metadata_json = await holder.create_credential_request( + cred_offer, cred_def_result.credential_definition, holder_did + ) - return { - "request": json.loads(request_json), - "metadata": json.loads(metadata_json), - } + return { + "request": json.loads(request_json), + "metadata": json.loads(metadata_json), + } + # This is for compatability with a holder that isn't anoncreds capable + except AnonCredsResolutionError: + return await IndyCredFormatHandler.create_cred_request_result( + self, cred_offer, holder_did, cred_def_id + ) cache_key = f"credential_request::{cred_def_id}::{holder_did}::{nonce}" cred_req_result = None @@ -292,7 +300,7 @@ async def _create(): if not cred_req_result: cred_req_result = await _create() - detail_record = V20CredExRecordIndy( + detail_record = V20CredExRecordAnoncreds( cred_ex_id=cred_ex_record.cred_ex_id, cred_request_metadata=cred_req_result["metadata"], ) @@ -305,18 +313,25 @@ async def _create(): async def receive_request( self, cred_ex_record: V20CredExRecord, cred_request_message: V20CredRequest ) -> None: - """Receive indy credential request.""" + """Receive anoncreds credential request.""" if not cred_ex_record.cred_offer: raise V20CredFormatError( - "Indy issue credential format cannot start from credential request" + "Anoncreds issue credential format cannot start from credential request" ) async def issue_credential( self, cred_ex_record: V20CredExRecord, retries: int = 5 ) -> CredFormatAttachment: - """Issue indy credential.""" + """Issue anoncreds credential.""" await self._check_uniqueness(cred_ex_record.cred_ex_id) + # For backwards compatibility, remove indy backup when indy format is retired + from ..indy.handler import IndyCredFormatHandler + + if cred_ex_record.cred_offer.attachment(IndyCredFormatHandler.format): + indy_handler = IndyCredFormatHandler(self.profile) + return await indy_handler.issue_credential(cred_ex_record, retries) + cred_offer = cred_ex_record.cred_offer.attachment( AnonCredsCredFormatHandler.format ) @@ -342,7 +357,7 @@ async def issue_credential( result = self.get_format_data(CRED_20_ISSUE, json.loads(cred_json)) async with self._profile.transaction() as txn: - detail_record = V20CredExRecordIndy( + detail_record = V20CredExRecordAnoncreds( cred_ex_id=cred_ex_record.cred_ex_id, rev_reg_id=rev_reg_def_id, cred_rev_id=cred_rev_id, @@ -371,7 +386,7 @@ async def issue_credential( async def receive_credential( self, cred_ex_record: V20CredExRecord, cred_issue_message: V20CredIssue ) -> None: - """Receive indy credential. + """Receive anoncreds credential. Validation is done in the store credential step. """ @@ -379,21 +394,33 @@ async def receive_credential( async def store_credential( self, cred_ex_record: V20CredExRecord, cred_id: Optional[str] = None ) -> None: - """Store indy credential.""" - cred = cred_ex_record.cred_issue.attachment(AnonCredsCredFormatHandler.format) + """Store anoncreds credential.""" + + # For backwards compatibility, remove indy backup when indy format is retired + from ..indy.handler import IndyCredFormatHandler + + cred = cred_ex_record.cred_issue.attachment( + AnonCredsCredFormatHandler.format + ) or cred_ex_record.cred_issue.attachment(IndyCredFormatHandler.format) rev_reg_def = None anoncreds_registry = self.profile.inject(AnonCredsRegistry) - cred_def_result = await anoncreds_registry.get_credential_definition( - self.profile, cred["cred_def_id"] - ) - if cred.get("rev_reg_id"): - rev_reg_def_result = ( - await anoncreds_registry.get_revocation_registry_definition( - self.profile, cred["rev_reg_id"] + try: + cred_def_result = await anoncreds_registry.get_credential_definition( + self.profile, cred["cred_def_id"] + ) + if cred.get("rev_reg_id"): + rev_reg_def_result = ( + await anoncreds_registry.get_revocation_registry_definition( + self.profile, cred["rev_reg_id"] + ) ) + rev_reg_def = rev_reg_def_result.revocation_registry + + except AnonCredsResolutionError: + return await IndyCredFormatHandler.store_credential( + self, cred_ex_record, cred_id ) - rev_reg_def = rev_reg_def_result.revocation_registry holder = AnonCredsHolder(self.profile) cred_offer_message = cred_ex_record.cred_offer diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py index 46606417fb..fed47beaf3 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/anoncreds/tests/test_handler.py @@ -36,10 +36,10 @@ from ....messages.cred_request import V20CredRequest from ....messages.inner.cred_preview import V20CredAttrSpec, V20CredPreview from ....models.cred_ex_record import V20CredExRecord -from ....models.detail.indy import V20CredExRecordIndy +from ....models.detail.anoncreds import V20CredExRecordAnoncreds from ...handler import V20CredFormatError from .. import handler as test_module -from ..handler import LOGGER as INDY_LOGGER +from ..handler import LOGGER as ANONCREDS_LOGGER from ..handler import AnonCredsCredFormatHandler TEST_DID = "LjgpST2rjsoxYegQDRm7EL" @@ -108,7 +108,7 @@ "tailsLocation": TAILS_LOCAL, }, } -INDY_OFFER = { +ANONCREDS_OFFER = { "schema_id": SCHEMA_ID, "cred_def_id": CRED_DEF_ID, "key_correctness_proof": { @@ -131,7 +131,7 @@ }, "nonce": "1234567890", } -INDY_CRED_REQ = { +ANONCREDS_CRED_REQ = { "prover_did": TEST_DID, "cred_def_id": CRED_DEF_ID, "blinded_ms": { @@ -148,7 +148,7 @@ }, "nonce": "9876543210", } -INDY_CRED = { +ANONCREDS_CRED = { "schema_id": SCHEMA_ID, "cred_def_id": CRED_DEF_ID, "rev_reg_id": REV_REG_ID, @@ -232,9 +232,9 @@ async def asyncSetUp(self): async def test_validate_fields(self): # Test correct data self.handler.validate_fields(CRED_20_PROPOSAL, {"cred_def_id": CRED_DEF_ID}) - self.handler.validate_fields(CRED_20_OFFER, INDY_OFFER) - self.handler.validate_fields(CRED_20_REQUEST, INDY_CRED_REQ) - self.handler.validate_fields(CRED_20_ISSUE, INDY_CRED) + self.handler.validate_fields(CRED_20_OFFER, ANONCREDS_OFFER) + self.handler.validate_fields(CRED_20_REQUEST, ANONCREDS_CRED_REQ) + self.handler.validate_fields(CRED_20_ISSUE, ANONCREDS_CRED) # test incorrect proposal with self.assertRaises(ValidationError): @@ -244,31 +244,31 @@ async def test_validate_fields(self): # test incorrect offer with self.assertRaises(ValidationError): - offer = INDY_OFFER.copy() + offer = ANONCREDS_OFFER.copy() offer.pop("nonce") self.handler.validate_fields(CRED_20_OFFER, offer) # test incorrect request with self.assertRaises(ValidationError): - req = INDY_CRED_REQ.copy() + req = ANONCREDS_CRED_REQ.copy() req.pop("nonce") self.handler.validate_fields(CRED_20_REQUEST, req) # test incorrect cred with self.assertRaises(ValidationError): - cred = INDY_CRED.copy() + cred = ANONCREDS_CRED.copy() cred.pop("schema_id") self.handler.validate_fields(CRED_20_ISSUE, cred) async def test_get_indy_detail_record(self): cred_ex_id = "dummy" details_indy = [ - V20CredExRecordIndy( + V20CredExRecordAnoncreds( cred_ex_id=cred_ex_id, rev_reg_id="rr-id", cred_rev_id="0", ), - V20CredExRecordIndy( + V20CredExRecordAnoncreds( cred_ex_id=cred_ex_id, rev_reg_id="rr-id", cred_rev_id="1", @@ -278,7 +278,9 @@ async def test_get_indy_detail_record(self): await details_indy[0].save(session) await details_indy[1].save(session) # exercise logger warning on get() - with mock.patch.object(INDY_LOGGER, "warning", mock.MagicMock()) as mock_warning: + with mock.patch.object( + ANONCREDS_LOGGER, "warning", mock.MagicMock() + ) as mock_warning: assert await self.handler.get_detail_record(cred_ex_id) in details_indy mock_warning.assert_called_once() @@ -354,7 +356,7 @@ async def test_create_offer(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], @@ -379,7 +381,7 @@ async def test_create_offer(self): await self.session.storage.add_record(cred_def_record) self.issuer.create_credential_offer = mock.CoroutineMock( - return_value=json.dumps(INDY_OFFER) + return_value=json.dumps(ANONCREDS_OFFER) ) (cred_format, attachment) = await self.handler.create_offer(cred_proposal) @@ -390,7 +392,7 @@ async def test_create_offer(self): assert cred_format.attach_id == self.handler.format.api == attachment.ident # assert content of attachment is proposal data - assert attachment.content == INDY_OFFER + assert attachment.content == ANONCREDS_OFFER # assert data is encoded as base64 assert attachment.data.base64 @@ -417,7 +419,7 @@ async def test_create_offer_no_cache(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], @@ -446,7 +448,7 @@ async def test_create_offer_no_cache(self): await self.session.storage.add_record(cred_def_record) self.issuer.create_credential_offer = mock.CoroutineMock( - return_value=json.dumps(INDY_OFFER) + return_value=json.dumps(ANONCREDS_OFFER) ) (cred_format, attachment) = await self.handler.create_offer(cred_proposal) @@ -457,7 +459,7 @@ async def test_create_offer_no_cache(self): assert cred_format.attach_id == self.handler.format.api == attachment.ident # assert content of attachment is proposal data - assert attachment.content == INDY_OFFER + assert attachment.content == ANONCREDS_OFFER # assert data is encoded as base64 assert attachment.data.base64 @@ -480,7 +482,7 @@ async def test_create_offer_attr_mismatch(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], @@ -509,7 +511,7 @@ async def test_create_offer_attr_mismatch(self): await self.session.storage.add_record(cred_def_record) self.issuer.create_credential_offer = mock.CoroutineMock( - return_value=json.dumps(INDY_OFFER) + return_value=json.dumps(ANONCREDS_OFFER) ) with mock.patch.object( IndyLedgerRequestsExecutor, @@ -526,7 +528,7 @@ async def test_create_offer_no_matching_sent_cred_def(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_PROPOSAL][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], @@ -534,7 +536,7 @@ async def test_create_offer_no_matching_sent_cred_def(self): ) self.issuer.create_credential_offer = mock.CoroutineMock( - return_value=json.dumps(INDY_OFFER) + return_value=json.dumps(ANONCREDS_OFFER) ) with self.assertRaises(V20CredFormatError) as context: @@ -557,11 +559,11 @@ async def test_create_request(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_OFFER][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - offers_attach=[AttachDecorator.data_base64(INDY_OFFER, ident="0")], + offers_attach=[AttachDecorator.data_base64(ANONCREDS_OFFER, ident="0")], ) cred_ex_record = V20CredExRecord( cred_ex_id="dummy-id", @@ -574,7 +576,7 @@ async def test_create_request(self): cred_req_meta = {} self.holder.create_credential_request = mock.CoroutineMock( - return_value=(json.dumps(INDY_CRED_REQ), json.dumps(cred_req_meta)) + return_value=(json.dumps(ANONCREDS_CRED_REQ), json.dumps(cred_req_meta)) ) (cred_format, attachment) = await self.handler.create_request( @@ -582,14 +584,14 @@ async def test_create_request(self): ) self.holder.create_credential_request.assert_called_once_with( - INDY_OFFER, cred_def, holder_did + ANONCREDS_OFFER, cred_def, holder_did ) # assert identifier match assert cred_format.attach_id == self.handler.format.api == attachment.ident # assert content of attachment is proposal data - assert attachment.content == INDY_CRED_REQ + assert attachment.content == ANONCREDS_CRED_REQ # assert data is encoded as base64 assert attachment.data.base64 @@ -617,16 +619,18 @@ async def test_create_request_bad_state(self): with self.assertRaises(V20CredFormatError) as context: await self.handler.create_request(cred_ex_record) - assert "Indy issue credential format cannot start from credential request" in str( - context.exception + assert ( + "Anoncreds issue credential format cannot start from credential request" + in str(context.exception) ) cred_ex_record.state = None with self.assertRaises(V20CredFormatError) as context: await self.handler.create_request(cred_ex_record) - assert "Indy issue credential format cannot start from credential request" in str( - context.exception + assert ( + "Anoncreds issue credential format cannot start from credential request" + in str(context.exception) ) async def test_create_request_not_unique_x(self): @@ -658,8 +662,9 @@ async def test_receive_request_no_offer(self): with self.assertRaises(V20CredFormatError) as context: await self.handler.receive_request(cred_ex_record, cred_request_message) - assert "Indy issue credential format cannot start from credential request" in str( - context.exception + assert ( + "Anoncreds issue credential format cannot start from credential request" + in str(context.exception) ) @pytest.mark.skip(reason="Anoncreds-break") @@ -680,22 +685,22 @@ async def test_issue_credential_revocable(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_OFFER][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - offers_attach=[AttachDecorator.data_base64(INDY_OFFER, ident="0")], + offers_attach=[AttachDecorator.data_base64(ANONCREDS_OFFER, ident="0")], ) cred_request = V20CredRequest( formats=[ V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_REQUEST][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - requests_attach=[AttachDecorator.data_base64(INDY_CRED_REQ, ident="0")], + requests_attach=[AttachDecorator.data_base64(ANONCREDS_CRED_REQ, ident="0")], ) cred_ex_record = V20CredExRecord( @@ -709,7 +714,7 @@ async def test_issue_credential_revocable(self): cred_rev_id = "1000" self.issuer.create_credential = mock.CoroutineMock( - return_value=(json.dumps(INDY_CRED), cred_rev_id) + return_value=(json.dumps(ANONCREDS_CRED), cred_rev_id) ) with mock.patch.object(test_module, "IndyRevocation", autospec=True) as revoc: @@ -732,8 +737,8 @@ async def test_issue_credential_revocable(self): self.issuer.create_credential.assert_called_once_with( SCHEMA, - INDY_OFFER, - INDY_CRED_REQ, + ANONCREDS_OFFER, + ANONCREDS_CRED_REQ, attr_values, REV_REG_ID, "dummy-path", @@ -743,7 +748,7 @@ async def test_issue_credential_revocable(self): assert cred_format.attach_id == self.handler.format.api == attachment.ident # assert content of attachment is proposal data - assert attachment.content == INDY_CRED + assert attachment.content == ANONCREDS_CRED # assert data is encoded as base64 assert attachment.data.base64 @@ -768,22 +773,22 @@ async def test_issue_credential_non_revocable(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_OFFER][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - offers_attach=[AttachDecorator.data_base64(INDY_OFFER, ident="0")], + offers_attach=[AttachDecorator.data_base64(ANONCREDS_OFFER, ident="0")], ) cred_request = V20CredRequest( formats=[ V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_REQUEST][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - requests_attach=[AttachDecorator.data_base64(INDY_CRED_REQ, ident="0")], + requests_attach=[AttachDecorator.data_base64(ANONCREDS_CRED_REQ, ident="0")], ) cred_ex_record = V20CredExRecord( @@ -796,7 +801,7 @@ async def test_issue_credential_non_revocable(self): ) self.issuer.create_credential = mock.CoroutineMock( - return_value=(json.dumps(INDY_CRED), None) + return_value=(json.dumps(ANONCREDS_CRED), None) ) self.ledger.get_credential_definition = mock.CoroutineMock( return_value=CRED_DEF_NR @@ -816,8 +821,8 @@ async def test_issue_credential_non_revocable(self): self.issuer.create_credential.assert_called_once_with( SCHEMA, - INDY_OFFER, - INDY_CRED_REQ, + ANONCREDS_OFFER, + ANONCREDS_CRED_REQ, attr_values, None, None, @@ -827,7 +832,7 @@ async def test_issue_credential_non_revocable(self): assert cred_format.attach_id == self.handler.format.api == attachment.ident # assert content of attachment is proposal data - assert attachment.content == INDY_CRED + assert attachment.content == ANONCREDS_CRED # assert data is encoded as base64 assert attachment.data.base64 @@ -867,22 +872,22 @@ async def test_issue_credential_no_active_rr_no_retries(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_OFFER][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - offers_attach=[AttachDecorator.data_base64(INDY_OFFER, ident="0")], + offers_attach=[AttachDecorator.data_base64(ANONCREDS_OFFER, ident="0")], ) cred_request = V20CredRequest( formats=[ V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_REQUEST][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - requests_attach=[AttachDecorator.data_base64(INDY_CRED_REQ, ident="0")], + requests_attach=[AttachDecorator.data_base64(ANONCREDS_CRED_REQ, ident="0")], ) cred_ex_record = V20CredExRecord( @@ -895,7 +900,7 @@ async def test_issue_credential_no_active_rr_no_retries(self): ) self.issuer.create_credential = mock.CoroutineMock( - return_value=(json.dumps(INDY_CRED), cred_rev_id) + return_value=(json.dumps(ANONCREDS_CRED), cred_rev_id) ) with mock.patch.object(test_module, "IndyRevocation", autospec=True) as revoc: @@ -926,22 +931,22 @@ async def test_issue_credential_no_active_rr_retry(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_OFFER][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - offers_attach=[AttachDecorator.data_base64(INDY_OFFER, ident="0")], + offers_attach=[AttachDecorator.data_base64(ANONCREDS_OFFER, ident="0")], ) cred_request = V20CredRequest( formats=[ V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_REQUEST][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - requests_attach=[AttachDecorator.data_base64(INDY_CRED_REQ, ident="0")], + requests_attach=[AttachDecorator.data_base64(ANONCREDS_CRED_REQ, ident="0")], ) cred_ex_record = V20CredExRecord( @@ -954,7 +959,7 @@ async def test_issue_credential_no_active_rr_retry(self): ) self.issuer.create_credential = mock.CoroutineMock( - return_value=(json.dumps(INDY_CRED), cred_rev_id) + return_value=(json.dumps(ANONCREDS_CRED), cred_rev_id) ) with mock.patch.object(test_module, "IndyRevocation", autospec=True) as revoc: @@ -996,22 +1001,22 @@ async def test_issue_credential_rr_full(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_OFFER][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - offers_attach=[AttachDecorator.data_base64(INDY_OFFER, ident="0")], + offers_attach=[AttachDecorator.data_base64(ANONCREDS_OFFER, ident="0")], ) cred_request = V20CredRequest( formats=[ V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_REQUEST][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - requests_attach=[AttachDecorator.data_base64(INDY_CRED_REQ, ident="0")], + requests_attach=[AttachDecorator.data_base64(ANONCREDS_CRED_REQ, ident="0")], ) cred_ex_record = V20CredExRecord( @@ -1075,11 +1080,11 @@ async def test_store_credential(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_OFFER][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - offers_attach=[AttachDecorator.data_base64(INDY_OFFER, ident="0")], + offers_attach=[AttachDecorator.data_base64(ANONCREDS_OFFER, ident="0")], ) cred_offer.assign_thread_id(thread_id) cred_request = V20CredRequest( @@ -1087,22 +1092,22 @@ async def test_store_credential(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_REQUEST][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - requests_attach=[AttachDecorator.data_base64(INDY_CRED_REQ, ident="0")], + requests_attach=[AttachDecorator.data_base64(ANONCREDS_CRED_REQ, ident="0")], ) cred_issue = V20CredIssue( formats=[ V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_ISSUE][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - credentials_attach=[AttachDecorator.data_base64(INDY_CRED, ident="0")], + credentials_attach=[AttachDecorator.data_base64(ANONCREDS_CRED, ident="0")], ) stored_cx_rec = V20CredExRecord( @@ -1167,7 +1172,7 @@ async def test_store_credential(self): self.holder.store_credential.assert_called_once_with( CRED_DEF, - INDY_CRED, + ANONCREDS_CRED, cred_req_meta, {"pic": "image/jpeg"}, credential_id=cred_id, @@ -1198,11 +1203,11 @@ async def test_store_credential_holder_store_indy_error(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_OFFER][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - offers_attach=[AttachDecorator.data_base64(INDY_OFFER, ident="0")], + offers_attach=[AttachDecorator.data_base64(ANONCREDS_OFFER, ident="0")], ) cred_offer.assign_thread_id(thread_id) cred_request = V20CredRequest( @@ -1210,22 +1215,22 @@ async def test_store_credential_holder_store_indy_error(self): V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_REQUEST][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - requests_attach=[AttachDecorator.data_base64(INDY_CRED_REQ, ident="0")], + requests_attach=[AttachDecorator.data_base64(ANONCREDS_CRED_REQ, ident="0")], ) cred_issue = V20CredIssue( formats=[ V20CredFormat( attach_id="0", format_=ATTACHMENT_FORMAT[CRED_20_ISSUE][ - V20CredFormat.Format.INDY.api + V20CredFormat.Format.ANONCREDS.api ], ) ], - credentials_attach=[AttachDecorator.data_base64(INDY_CRED, ident="0")], + credentials_attach=[AttachDecorator.data_base64(ANONCREDS_CRED, ident="0")], ) stored_cx_rec = V20CredExRecord( diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/indy/handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/indy/handler.py index ecadd98539..19a2857cf3 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/indy/handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/indy/handler.py @@ -7,6 +7,7 @@ from marshmallow import RAISE +from ......askar.profile_anon import AskarAnoncredsProfile from ......cache.base import BaseCache from ......core.profile import Profile from ......indy.holder import IndyHolder, IndyHolderError @@ -14,7 +15,6 @@ from ......indy.models.cred import IndyCredentialSchema from ......indy.models.cred_abstract import IndyCredAbstractSchema from ......indy.models.cred_request import IndyCredRequestSchema -from ......ledger.base import BaseLedger from ......ledger.multiple_ledger.ledger_requests_executor import ( GET_CRED_DEF, GET_SCHEMA, @@ -105,10 +105,6 @@ async def get_detail_record(self, cred_ex_id: str) -> V20CredExRecordIndy: session, cred_ex_id ) - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return await self.anoncreds_handler.get_detail_record(cred_ex_id) - if len(records) > 1: LOGGER.warning( "Cred ex id %s has %d %s detail records: should be 1", @@ -140,9 +136,6 @@ def get_format_identifier(self, message_type: str) -> str: str: Issue credential attachment format identifier """ - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return self.anoncreds_handler.get_format_identifier(message_type) return ATTACHMENT_FORMAT[message_type][IndyCredFormatHandler.format.api] @@ -162,9 +155,6 @@ def get_format_data(self, message_type: str, data: dict) -> CredFormatAttachment CredFormatAttachment: Credential format and attachment data objects """ - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return self.anoncreds_handler.get_format_data(message_type, data) return ( V20CredFormat( @@ -192,7 +182,7 @@ async def create_proposal( self, cred_ex_record: V20CredExRecord, proposal_data: Mapping[str, str] ) -> Tuple[V20CredFormat, AttachDecorator]: """Create indy credential proposal.""" - # Temporary shim while the new anoncreds library integration is in progress + # Create the proposal with the anoncreds handler if agent is anoncreds capable if self.anoncreds_handler: return await self.anoncreds_handler.create_proposal( cred_ex_record, @@ -217,12 +207,12 @@ async def create_offer( ) -> CredFormatAttachment: """Create indy credential offer.""" - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return await self.anoncreds_handler.create_offer(cred_proposal_message) + if isinstance(self.profile, AskarAnoncredsProfile): + raise V20CredFormatError( + "This issuer is anoncreds capable. Please use the anonreds format." + ) issuer = self.profile.inject(IndyIssuer) - ledger = self.profile.inject(BaseLedger) cache = self.profile.inject_or(BaseCache) cred_def_id = await self._match_sent_cred_def_id( @@ -275,11 +265,38 @@ async def receive_offer( ) -> None: """Receive indy credential offer.""" + async def create_cred_request_result(self, cred_offer, holder_did, cred_def_id): + """Create credential request result.""" + multitenant_mgr = self.profile.inject_or(BaseMultitenantManager) + if multitenant_mgr: + ledger_exec_inst = IndyLedgerRequestsExecutor(self.profile) + else: + ledger_exec_inst = self.profile.inject(IndyLedgerRequestsExecutor) + ledger = ( + await ledger_exec_inst.get_ledger_for_identifier( + cred_def_id, + txn_record_type=GET_CRED_DEF, + ) + )[1] + async with ledger: + cred_def = await ledger.get_credential_definition(cred_def_id) + + holder = self.profile.inject(IndyHolder) + request_json, metadata_json = await holder.create_credential_request( + cred_offer, cred_def, holder_did + ) + + return { + "request": json.loads(request_json), + "metadata": json.loads(metadata_json), + } + async def create_request( self, cred_ex_record: V20CredExRecord, request_data: Optional[Mapping] = None ) -> CredFormatAttachment: """Create indy credential request.""" - # Temporary shim while the new anoncreds library integration is in progress + + # Create the request with the anoncreds handler if agent is anoncreds capable if self.anoncreds_handler: return await self.anoncreds_handler.create_request( cred_ex_record, @@ -302,31 +319,6 @@ async def create_request( nonce = cred_offer["nonce"] cred_def_id = cred_offer["cred_def_id"] - async def _create(): - multitenant_mgr = self.profile.inject_or(BaseMultitenantManager) - if multitenant_mgr: - ledger_exec_inst = IndyLedgerRequestsExecutor(self.profile) - else: - ledger_exec_inst = self.profile.inject(IndyLedgerRequestsExecutor) - ledger = ( - await ledger_exec_inst.get_ledger_for_identifier( - cred_def_id, - txn_record_type=GET_CRED_DEF, - ) - )[1] - async with ledger: - cred_def = await ledger.get_credential_definition(cred_def_id) - - holder = self.profile.inject(IndyHolder) - request_json, metadata_json = await holder.create_credential_request( - cred_offer, cred_def, holder_did - ) - - return { - "request": json.loads(request_json), - "metadata": json.loads(metadata_json), - } - cache_key = f"credential_request::{cred_def_id}::{holder_did}::{nonce}" cred_req_result = None cache = self.profile.inject_or(BaseCache) @@ -335,10 +327,14 @@ async def _create(): if entry.result: cred_req_result = entry.result else: - cred_req_result = await _create() + cred_req_result = await self.create_cred_request_result( + cred_offer, holder_did, cred_def_id + ) await entry.set_result(cred_req_result, 3600) if not cred_req_result: - cred_req_result = await _create() + cred_req_result = await self.create_cred_request_result( + cred_offer, holder_did, cred_def_id + ) detail_record = V20CredExRecordIndy( cred_ex_id=cred_ex_record.cred_ex_id, @@ -354,7 +350,7 @@ async def receive_request( self, cred_ex_record: V20CredExRecord, cred_request_message: V20CredRequest ) -> None: """Receive indy credential request.""" - # Temporary shim while the new anoncreds library integration is in progress + # Receive the request with the anoncreds handler if agent is anoncreds capable if self.anoncreds_handler: return await self.anoncreds_handler.receive_request( cred_ex_record, @@ -445,9 +441,11 @@ async def issue_credential( await self._check_uniqueness(cred_ex_record.cred_ex_id) cred_offer = cred_ex_record.cred_offer.attachment(IndyCredFormatHandler.format) + from ..anoncreds.handler import AnonCredsCredFormatHandler + cred_request = cred_ex_record.cred_request.attachment( IndyCredFormatHandler.format - ) + ) or cred_ex_record.cred_request.attachment(AnonCredsCredFormatHandler.format) cred_values = cred_ex_record.cred_offer.credential_preview.attr_dict(decode=False) schema_id = cred_offer["schema_id"] cred_def_id = cred_offer["cred_def_id"] @@ -517,10 +515,14 @@ async def store_credential( ) -> None: """Store indy credential.""" # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: + if hasattr(self, "anoncreds_handler") and self.anoncreds_handler: return await self.anoncreds_handler.store_credential(cred_ex_record, cred_id) - cred = cred_ex_record.cred_issue.attachment(IndyCredFormatHandler.format) + from ..anoncreds.handler import AnonCredsCredFormatHandler + + cred = cred_ex_record.cred_issue.attachment( + IndyCredFormatHandler.format + ) or cred_ex_record.cred_issue.attachment(AnonCredsCredFormatHandler.format) rev_reg_def = None multitenant_mgr = self.profile.inject_or(BaseMultitenantManager) diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/models/cred_detail_options.py b/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/models/cred_detail_options.py index 9d74382d8d..7a9b1ca549 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/models/cred_detail_options.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/ld_proof/models/cred_detail_options.py @@ -6,8 +6,8 @@ from .......messaging.models.base import BaseModel, BaseModelSchema from .......messaging.valid import ( - INDY_ISO8601_DATETIME_EXAMPLE, - INDY_ISO8601_DATETIME_VALIDATE, + ISO8601_DATETIME_EXAMPLE, + ISO8601_DATETIME_VALIDATE, UUID4_EXAMPLE, ) @@ -109,13 +109,13 @@ class Meta: created = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": ( "The date and time of the proof (with a maximum accuracy in seconds)." " Defaults to current system time" ), - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py index ae8f23fa69..3ff75a5119 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py +++ b/acapy_agent/protocols/issue_credential/v2_0/formats/vc_di/tests/test_handler.py @@ -9,11 +9,11 @@ from .......anoncreds.holder import AnonCredsHolder, AnonCredsHolderError from .......anoncreds.issuer import AnonCredsIssuer -from .......anoncreds.models.anoncreds_cred_def import ( +from .......anoncreds.models.credential_definition import ( CredDef, GetCredDefResult, ) -from .......anoncreds.models.anoncreds_revocation import ( +from .......anoncreds.models.revocation import ( GetRevRegDefResult, RevRegDef, ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/manager.py b/acapy_agent/protocols/issue_credential/v2_0/manager.py index 068f94a4bd..124e832c47 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/manager.py +++ b/acapy_agent/protocols/issue_credential/v2_0/manager.py @@ -591,8 +591,14 @@ async def receive_credential( ] handled_formats = [] - # check that we didn't receive any formats not present in the request - if set(issue_formats) - set(req_formats): + def _check_formats(): + """Allow indy issue fomat and anoncreds req format or matching formats.""" + return ( + issue_formats == [V20CredFormat.Format.INDY] + and req_formats == [V20CredFormat.Format.ANONCREDS] + ) or len(set(issue_formats) - set(req_formats)) == 0 + + if not _check_formats(): raise V20CredManagerError( "Received issue credential format(s) not present in credential " f"request: {set(issue_formats) - set(req_formats)}" diff --git a/acapy_agent/protocols/issue_credential/v2_0/message_types.py b/acapy_agent/protocols/issue_credential/v2_0/message_types.py index 668d2b7332..e34ce0385d 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/message_types.py +++ b/acapy_agent/protocols/issue_credential/v2_0/message_types.py @@ -37,21 +37,25 @@ # Format specifications ATTACHMENT_FORMAT = { CRED_20_PROPOSAL: { + V20CredFormat.Format.ANONCREDS.api: "anoncreds/cred-filter@v2.0", V20CredFormat.Format.INDY.api: "hlindy/cred-filter@v2.0", V20CredFormat.Format.LD_PROOF.api: "aries/ld-proof-vc-detail@v1.0", V20CredFormat.Format.VC_DI.api: "didcomm/w3c-di-vc@v0.1", }, CRED_20_OFFER: { + V20CredFormat.Format.ANONCREDS.api: "anoncreds/cred-abstract@v2.0", V20CredFormat.Format.INDY.api: "hlindy/cred-abstract@v2.0", V20CredFormat.Format.LD_PROOF.api: "aries/ld-proof-vc-detail@v1.0", V20CredFormat.Format.VC_DI.api: "didcomm/w3c-di-vc-offer@v0.1", }, CRED_20_REQUEST: { + V20CredFormat.Format.ANONCREDS.api: "anoncreds/cred-req@v2.0", V20CredFormat.Format.INDY.api: "hlindy/cred-req@v2.0", V20CredFormat.Format.LD_PROOF.api: "aries/ld-proof-vc-detail@v1.0", V20CredFormat.Format.VC_DI.api: "didcomm/w3c-di-vc-request@v0.1", }, CRED_20_ISSUE: { + V20CredFormat.Format.ANONCREDS.api: "anoncreds/cred@v2.0", V20CredFormat.Format.INDY.api: "hlindy/cred@v2.0", V20CredFormat.Format.LD_PROOF.api: "aries/ld-proof-vc@v1.0", V20CredFormat.Format.VC_DI.api: "didcomm/w3c-di-vc@v0.1", diff --git a/acapy_agent/protocols/issue_credential/v2_0/messages/cred_format.py b/acapy_agent/protocols/issue_credential/v2_0/messages/cred_format.py index 0574d4736d..589dfcf579 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/messages/cred_format.py +++ b/acapy_agent/protocols/issue_credential/v2_0/messages/cred_format.py @@ -11,6 +11,7 @@ from .....messaging.models.base import BaseModel, BaseModelSchema from .....messaging.valid import UUID4_EXAMPLE from .....utils.classloader import DeferLoad +from ..models.detail.anoncreds import V20CredExRecordAnoncreds from ..models.detail.indy import V20CredExRecordIndy from ..models.detail.ld_proof import V20CredExRecordLDProof @@ -31,6 +32,14 @@ class Meta: class Format(Enum): """Attachment format.""" + ANONCREDS = FormatSpec( + "anoncreds/", + V20CredExRecordAnoncreds, + DeferLoad( + "acapy_agent.protocols.issue_credential.v2_0" + ".formats.anoncreds.handler.AnonCredsCredFormatHandler" + ), + ) INDY = FormatSpec( "hlindy/", V20CredExRecordIndy, @@ -39,23 +48,6 @@ class Format(Enum): ".formats.indy.handler.IndyCredFormatHandler" ), ) - """ - Once we switch to anoncreds this will replace the above INDY definition. - - In the meantime there are some hardcoded references in the - "...formats.indy.handler.IndyCredFormatHandler" class. - - :: - - INDY = FormatSpec( - "hlindy/", - V20CredExRecordIndy, - DeferLoad( - "acapy_agent.protocols.issue_credential.v2_0" - ".formats.anoncreds.handler.AnonCredsCredFormatHandler" - ), - ) - """ LD_PROOF = FormatSpec( "aries/", V20CredExRecordLDProof, @@ -97,7 +89,9 @@ def aries(self) -> str: return self.value.aries @property - def detail(self) -> Union[V20CredExRecordIndy, V20CredExRecordLDProof]: + def detail( + self, + ) -> Union[V20CredExRecordIndy, V20CredExRecordLDProof, V20CredExRecordAnoncreds]: """Accessor for credential exchange detail class.""" return self.value.detail diff --git a/acapy_agent/protocols/issue_credential/v2_0/models/detail/anoncreds.py b/acapy_agent/protocols/issue_credential/v2_0/models/detail/anoncreds.py new file mode 100644 index 0000000000..f683ff68ca --- /dev/null +++ b/acapy_agent/protocols/issue_credential/v2_0/models/detail/anoncreds.py @@ -0,0 +1,131 @@ +"""Anoncreds specific credential exchange information with non-secrets storage.""" + +from typing import Any, Mapping, Optional, Sequence + +from marshmallow import EXCLUDE, fields + +from ......core.profile import ProfileSession +from ......messaging.models.base_record import BaseRecord, BaseRecordSchema +from ......messaging.valid import ( + ANONCREDS_CRED_DEF_ID_EXAMPLE, + ANONCREDS_REV_REG_ID_EXAMPLE, + UUID4_EXAMPLE, +) +from .. import UNENCRYPTED_TAGS + + +class V20CredExRecordAnoncreds(BaseRecord): + """Credential exchange anoncreds detail record.""" + + class Meta: + """V20CredExRecordAnoncreds metadata.""" + + schema_class = "V20CredExRecordAnoncredsSchema" + + RECORD_ID_NAME = "cred_ex_anoncreds_id" + RECORD_TYPE = "anoncreds_cred_ex_v20" + TAG_NAMES = {"~cred_ex_id"} if UNENCRYPTED_TAGS else {"cred_ex_id"} + RECORD_TOPIC = "issue_credential_v2_0_anoncreds" + + def __init__( + self, + cred_ex_anoncreds_id: Optional[str] = None, + *, + cred_ex_id: Optional[str] = None, + cred_id_stored: Optional[str] = None, + cred_request_metadata: Optional[Mapping] = None, + rev_reg_id: Optional[str] = None, + cred_rev_id: Optional[str] = None, + **kwargs, + ): + """Initialize anoncreds credential exchange record details.""" + super().__init__(cred_ex_anoncreds_id, **kwargs) + + self.cred_ex_id = cred_ex_id + self.cred_id_stored = cred_id_stored + self.cred_request_metadata = cred_request_metadata + self.rev_reg_id = rev_reg_id + self.cred_rev_id = cred_rev_id + + @property + def cred_ex_anoncreds_id(self) -> str: + """Accessor for the ID associated with this exchange.""" + return self._id + + @property + def record_value(self) -> dict: + """Accessor for the JSON record value generated for this credential exchange.""" + return { + prop: getattr(self, prop) + for prop in ( + "cred_id_stored", + "cred_request_metadata", + "rev_reg_id", + "cred_rev_id", + ) + } + + @classmethod + async def query_by_cred_ex_id( + cls, + session: ProfileSession, + cred_ex_id: str, + ) -> Sequence["V20CredExRecordAnoncreds"]: + """Retrieve credential exchange anoncreds detail record(s) by its cred ex id.""" + return await cls.query( + session=session, + tag_filter={"cred_ex_id": cred_ex_id}, + ) + + def __eq__(self, other: Any) -> bool: + """Comparison between records.""" + return super().__eq__(other) + + +class V20CredExRecordAnoncredsSchema(BaseRecordSchema): + """Credential exchange anoncreds detail record detail schema.""" + + class Meta: + """Credential exchange anoncreds detail record schema metadata.""" + + model_class = V20CredExRecordAnoncreds + unknown = EXCLUDE + + cred_ex_anoncreds_id = fields.Str( + required=False, + metadata={"description": "Record identifier", "example": UUID4_EXAMPLE}, + ) + cred_ex_id = fields.Str( + required=False, + metadata={ + "description": "Corresponding v2.0 credential exchange record identifier", + "example": UUID4_EXAMPLE, + }, + ) + cred_id_stored = fields.Str( + required=False, + metadata={ + "description": "Credential identifier stored in wallet", + "example": UUID4_EXAMPLE, + }, + ) + cred_request_metadata = fields.Dict( + required=False, + metadata={"description": "Credential request metadata for anoncreds holder"}, + ) + rev_reg_id = fields.Str( + required=False, + metadata={ + "description": "Revocation registry identifier", + "example": ANONCREDS_REV_REG_ID_EXAMPLE, + }, + ) + cred_rev_id = fields.Str( + required=False, + metadata={ + "description": ( + "Credential revocation identifier within revocation registry" + ), + "example": ANONCREDS_CRED_DEF_ID_EXAMPLE, + }, + ) diff --git a/acapy_agent/protocols/issue_credential/v2_0/routes.py b/acapy_agent/protocols/issue_credential/v2_0/routes.py index 01cf9330d7..9128f7aeac 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/routes.py +++ b/acapy_agent/protocols/issue_credential/v2_0/routes.py @@ -28,14 +28,16 @@ from ....messaging.models.openapi import OpenAPISchema from ....messaging.models.paginated_query import PaginatedQuerySchema, get_limit_offset from ....messaging.valid import ( + ANONCREDS_DID_EXAMPLE, + ANONCREDS_SCHEMA_ID_EXAMPLE, INDY_CRED_DEF_ID_EXAMPLE, INDY_CRED_DEF_ID_VALIDATE, INDY_DID_EXAMPLE, INDY_DID_VALIDATE, INDY_SCHEMA_ID_EXAMPLE, INDY_SCHEMA_ID_VALIDATE, - INDY_VERSION_EXAMPLE, - INDY_VERSION_VALIDATE, + MAJOR_MINOR_VERSION_EXAMPLE, + MAJOR_MINOR_VERSION_VALIDATE, UUID4_EXAMPLE, UUID4_VALIDATE, ) @@ -132,6 +134,36 @@ class V20CredStoreRequestSchema(OpenAPISchema): credential_id = fields.Str(required=False) +class V20CredFilterAnoncredsSchema(OpenAPISchema): + """Anoncreds credential filtration criteria.""" + + cred_def_id = fields.Str( + required=False, + metadata={ + "description": "Credential definition identifier", + "example": ANONCREDS_DID_EXAMPLE, + }, + ) + schema_id = fields.Str( + required=False, + metadata={ + "description": "Schema identifier", + "example": ANONCREDS_SCHEMA_ID_EXAMPLE, + }, + ) + issuer_id = fields.Str( + required=False, + metadata={ + "description": "Credential issuer DID", + "example": ANONCREDS_DID_EXAMPLE, + }, + ) + epoch = fields.Str( + required=False, + metadata={"description": "Credential epoch time", "example": "2021-08-24"}, + ) + + class V20CredFilterIndySchema(OpenAPISchema): """Indy credential filtration criteria.""" @@ -162,8 +194,11 @@ class V20CredFilterIndySchema(OpenAPISchema): ) schema_version = fields.Str( required=False, - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Schema version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, ) issuer_did = fields.Str( required=False, @@ -202,8 +237,11 @@ class V20CredFilterVCDISchema(OpenAPISchema): ) schema_version = fields.Str( required=False, - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, + validate=MAJOR_MINOR_VERSION_VALIDATE, + metadata={ + "description": "Schema version", + "example": MAJOR_MINOR_VERSION_EXAMPLE, + }, ) issuer_did = fields.Str( required=False, @@ -215,6 +253,11 @@ class V20CredFilterVCDISchema(OpenAPISchema): class V20CredFilterSchema(OpenAPISchema): """Credential filtration criteria.""" + anoncreds = fields.Nested( + V20CredFilterAnoncredsSchema, + required=False, + metadata={"description": "Credential filter for anoncreds"}, + ) indy = fields.Nested( V20CredFilterIndySchema, required=False, @@ -946,11 +989,17 @@ async def _create_free_offer( ) cred_manager = V20CredManager(profile) - (cred_ex_record, cred_offer_message) = await cred_manager.create_offer( - cred_ex_record, - comment=comment, - replacement_id=replacement_id, - ) + try: + (cred_ex_record, cred_offer_message) = await cred_manager.create_offer( + cred_ex_record, + comment=comment, + replacement_id=replacement_id, + ) + except ValueError as err: + LOGGER.exception(f"Error creating credential offer: {err}") + async with profile.session() as session: + await cred_ex_record.save_error_state(session, reason=err) + raise web.HTTPBadRequest(reason=err) return (cred_ex_record, cred_offer_message) diff --git a/acapy_agent/protocols/issue_credential/v2_0/tests/test_routes.py b/acapy_agent/protocols/issue_credential/v2_0/tests/test_routes.py index 5ca0854086..1359057136 100644 --- a/acapy_agent/protocols/issue_credential/v2_0/tests/test_routes.py +++ b/acapy_agent/protocols/issue_credential/v2_0/tests/test_routes.py @@ -149,9 +149,10 @@ async def test_credential_exchange_retrieve(self): mock_handler.return_value.get_detail_record = mock.CoroutineMock( side_effect=[ - mock.MagicMock( # indy + mock.MagicMock( # anoncreds serialize=mock.MagicMock(return_value={"...": "..."}) ), + None, # indy None, # ld_proof None, # vc_di ] @@ -162,7 +163,8 @@ async def test_credential_exchange_retrieve(self): mock_response.assert_called_once_with( { "cred_ex_record": mock_cx_rec.serialize.return_value, - "indy": {"...": "..."}, + "anoncreds": {"...": "..."}, + "indy": None, "ld_proof": None, "vc_di": None, } @@ -185,6 +187,9 @@ async def test_credential_exchange_retrieve_indy_ld_proof(self): mock_handler.return_value.get_detail_record = mock.CoroutineMock( side_effect=[ + mock.MagicMock( # anoncreds + serialize=mock.MagicMock(return_value={"anon": "creds"}) + ), mock.MagicMock( # indy serialize=mock.MagicMock(return_value={"in": "dy"}) ), @@ -202,6 +207,7 @@ async def test_credential_exchange_retrieve_indy_ld_proof(self): mock_response.assert_called_once_with( { "cred_ex_record": mock_cx_rec.serialize.return_value, + "anoncreds": {"anon": "creds"}, "indy": {"in": "dy"}, "ld_proof": {"ld": "proof"}, "vc_di": {"vc": "di"}, @@ -1230,9 +1236,10 @@ async def test_credential_exchange_issue(self): mock_handler.return_value.get_detail_record = mock.CoroutineMock( side_effect=[ - mock.MagicMock( # indy + mock.MagicMock( # anoncreds serialize=mock.MagicMock(return_value={"...": "..."}) ), + None, None, # ld_proof None, # vc_di ] @@ -1248,7 +1255,8 @@ async def test_credential_exchange_issue(self): mock_response.assert_called_once_with( { "cred_ex_record": mock_cx_rec.serialize.return_value, - "indy": {"...": "..."}, + "anoncreds": {"...": "..."}, + "indy": None, "ld_proof": None, "vc_di": None, } @@ -1277,7 +1285,8 @@ async def test_credential_exchange_issue_vcdi(self): mock_handler.return_value.get_detail_record = mock.CoroutineMock( side_effect=[ - None, + None, # anoncreds + None, # indy None, # ld_proof mock.MagicMock( # indy serialize=mock.MagicMock(return_value={"...": "..."}) @@ -1295,6 +1304,7 @@ async def test_credential_exchange_issue_vcdi(self): mock_response.assert_called_once_with( { "cred_ex_record": mock_cx_rec.serialize.return_value, + "anoncreds": None, "indy": None, "ld_proof": None, "vc_di": {"...": "..."}, @@ -1498,6 +1508,7 @@ async def test_credential_exchange_store(self): ) mock_handler.return_value.get_detail_record = mock.CoroutineMock( side_effect=[ + None, # anoncreds mock.MagicMock( # indy serialize=mock.MagicMock(return_value={"...": "..."}) ), @@ -1519,6 +1530,7 @@ async def test_credential_exchange_store(self): mock_response.assert_called_once_with( { "cred_ex_record": mock_cx_rec.serialize.return_value, + "anoncreds": None, "indy": {"...": "..."}, "ld_proof": None, "vc_di": None, @@ -1575,6 +1587,7 @@ async def test_credential_exchange_store_bad_cred_id_json(self): mock_response.assert_called_once_with( { "cred_ex_record": mock_cx_rec.serialize.return_value, + "anoncreds": None, "indy": {"...": "..."}, "ld_proof": None, "vc_di": None, @@ -1678,6 +1691,7 @@ async def test_credential_exchange_store_x(self): ) mock_handler.return_value.get_detail_record = mock.CoroutineMock( side_effect=[ + None, # anoncreds mock.MagicMock( # indy serialize=mock.MagicMock(return_value={"...": "..."}) ), diff --git a/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py b/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py index 0052a78873..d1d73f8a72 100644 --- a/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py +++ b/acapy_agent/protocols/present_proof/anoncreds/pres_exch_handler.py @@ -1,4 +1,4 @@ -"""Utilities for dif presentation exchange attachment.""" +"""Utilities for anoncreds presentation exchange attachment.""" import json import logging @@ -6,14 +6,15 @@ from typing import Dict, Optional, Tuple, Union from ....anoncreds.holder import AnonCredsHolder, AnonCredsHolderError -from ....anoncreds.models.anoncreds_cred_def import CredDef -from ....anoncreds.models.anoncreds_revocation import RevRegDef -from ....anoncreds.models.anoncreds_schema import AnonCredsSchema +from ....anoncreds.models.credential_definition import CredDef +from ....anoncreds.models.revocation import RevRegDef +from ....anoncreds.models.schema import AnonCredsSchema +from ....anoncreds.models.utils import extract_non_revocation_intervals_from_proof_request from ....anoncreds.registry import AnonCredsRegistry from ....anoncreds.revocation import AnonCredsRevocation +from ....askar.profile_anon import AskarAnoncredsProfile from ....core.error import BaseError from ....core.profile import Profile -from ....indy.models.xform import indy_proof_req2non_revoc_intervals from ..v1_0.models.presentation_exchange import V10PresentationExchange from ..v2_0.messages.pres_format import V20PresFormat from ..v2_0.models.pres_exchange import V20PresExRecord @@ -22,7 +23,7 @@ class AnonCredsPresExchHandlerError(BaseError): - """Base class for Indy Presentation Exchange related errors.""" + """Base class for Anoncreds Presentation Exchange related errors.""" class AnonCredsPresExchHandler: @@ -39,7 +40,9 @@ def __init__( def _extract_proof_request(self, pres_ex_record): if isinstance(pres_ex_record, V20PresExRecord): - return pres_ex_record.pres_request.attachment(V20PresFormat.Format.INDY) + return pres_ex_record.pres_request.attachment( + V20PresFormat.Format.ANONCREDS + ) or pres_ex_record.pres_request.attachment(V20PresFormat.Format.INDY) elif isinstance(pres_ex_record, V10PresentationExchange): return pres_ex_record._presentation_request.ser @@ -229,10 +232,23 @@ async def return_presentation( pres_ex_record: Union[V10PresentationExchange, V20PresExRecord], requested_credentials: Optional[dict] = None, ) -> dict: - """Return Indy proof request as dict.""" + """Return Anoncreds proof request as dict.""" + + # If not anoncreds capable, try to use indy handler. This should be removed when + # indy filter is completely retired + if not isinstance(self._profile, AskarAnoncredsProfile): + from ..indy.pres_exch_handler import IndyPresExchHandler + + handler = IndyPresExchHandler(self._profile) + return await handler.return_presentation( + pres_ex_record, requested_credentials + ) + requested_credentials = requested_credentials or {} proof_request = self._extract_proof_request(pres_ex_record) - non_revoc_intervals = indy_proof_req2non_revoc_intervals(proof_request) + non_revoc_intervals = extract_non_revocation_intervals_from_proof_request( + proof_request + ) requested_referents = self._get_requested_referents( proof_request, requested_credentials, non_revoc_intervals @@ -253,12 +269,12 @@ async def return_presentation( self._set_timestamps(requested_credentials, requested_referents) - indy_proof_json = await self.holder.create_presentation( + proof_json = await self.holder.create_presentation( proof_request, requested_credentials, schemas, cred_defs, revocation_states, ) - indy_proof = json.loads(indy_proof_json) - return indy_proof + proof = json.loads(proof_json) + return proof diff --git a/acapy_agent/protocols/present_proof/indy/pres_exch_handler.py b/acapy_agent/protocols/present_proof/indy/pres_exch_handler.py index 9c510afc9a..b62701ced1 100644 --- a/acapy_agent/protocols/present_proof/indy/pres_exch_handler.py +++ b/acapy_agent/protocols/present_proof/indy/pres_exch_handler.py @@ -55,6 +55,13 @@ async def return_presentation( proof_request = pres_ex_record.pres_request.attachment( V20PresFormat.Format.INDY ) + # If indy filter fails try anoncreds filter format. This is for a + # non-anoncreds agent that gets a anoncreds format proof request and + # should removed when indy format is fully retired. + if not proof_request: + proof_request = pres_ex_record.pres_request.attachment( + V20PresFormat.Format.ANONCREDS + ) elif isinstance(pres_ex_record, V10PresentationExchange): proof_request = pres_ex_record._presentation_request.ser non_revoc_intervals = indy_proof_req2non_revoc_intervals(proof_request) diff --git a/acapy_agent/protocols/present_proof/v1_0/tests/test_routes.py b/acapy_agent/protocols/present_proof/v1_0/tests/test_routes.py index afe923e8be..5c55474765 100644 --- a/acapy_agent/protocols/present_proof/v1_0/tests/test_routes.py +++ b/acapy_agent/protocols/present_proof/v1_0/tests/test_routes.py @@ -4,8 +4,10 @@ from marshmallow import ValidationError from .....admin.request_context import AdminRequestContext +from .....anoncreds.models.presentation_request import ( + AnoncredsPresentationReqAttrSpecSchema, +) from .....indy.holder import IndyHolder -from .....indy.models.proof_request import IndyProofReqAttrSpecSchema from .....indy.verifier import IndyVerifier from .....ledger.base import BaseLedger from .....storage.error import StorageNotFoundError @@ -35,7 +37,7 @@ async def asyncSetUp(self): ) async def test_validate_proof_req_attr_spec(self): - aspec = IndyProofReqAttrSpecSchema() + aspec = AnoncredsPresentationReqAttrSpecSchema() aspec.validate_fields({"name": "attr0"}) aspec.validate_fields( { diff --git a/acapy_agent/protocols/present_proof/v2_0/formats/anoncreds/handler.py b/acapy_agent/protocols/present_proof/v2_0/formats/anoncreds/handler.py index d5618f4a50..2c19d13443 100644 --- a/acapy_agent/protocols/present_proof/v2_0/formats/anoncreds/handler.py +++ b/acapy_agent/protocols/present_proof/v2_0/formats/anoncreds/handler.py @@ -1,4 +1,4 @@ -"""V2.0 present-proof indy presentation-exchange format handler.""" +"""V2.0 present-proof anoncreds presentation-exchange format handler.""" import json import logging @@ -7,12 +7,12 @@ from marshmallow import RAISE from ......anoncreds.holder import AnonCredsHolder +from ......anoncreds.models.predicate import Predicate +from ......anoncreds.models.presentation_request import AnoncredsPresentationRequestSchema +from ......anoncreds.models.proof import AnoncredsProofSchema +from ......anoncreds.models.utils import get_requested_creds_from_proof_request_preview from ......anoncreds.util import generate_pr_nonce from ......anoncreds.verifier import AnonCredsVerifier -from ......indy.models.predicate import Predicate -from ......indy.models.proof import IndyProofSchema -from ......indy.models.proof_request import IndyProofRequestSchema -from ......indy.models.xform import indy_proof_req_preview2indy_requested_creds from ......messaging.decorators.attach_decorator import AttachDecorator from ......messaging.util import canon from ....anoncreds.pres_exch_handler import AnonCredsPresExchHandler @@ -33,7 +33,7 @@ class AnonCredsPresExchangeHandler(V20PresFormatHandler): """Anoncreds presentation format handler.""" - format = V20PresFormat.Format.INDY + format = V20PresFormat.Format.ANONCREDS @classmethod def validate_fields(cls, message_type: str, attachment_data: Mapping): @@ -55,9 +55,9 @@ def validate_fields(cls, message_type: str, attachment_data: Mapping): """ mapping = { - PRES_20_REQUEST: IndyProofRequestSchema, - PRES_20_PROPOSAL: IndyProofRequestSchema, - PRES_20: IndyProofSchema, + PRES_20_REQUEST: AnoncredsPresentationRequestSchema, + PRES_20_PROPOSAL: AnoncredsPresentationRequestSchema, + PRES_20: AnoncredsProofSchema, } # Get schema class @@ -109,20 +109,20 @@ async def create_bound_request( A tuple (updated presentation exchange record, presentation request message) """ - indy_proof_request = pres_ex_record.pres_proposal.attachment( + proof_request = pres_ex_record.pres_proposal.attachment( AnonCredsPresExchangeHandler.format ) if request_data: - indy_proof_request["name"] = request_data.get("name", "proof-request") - indy_proof_request["version"] = request_data.get("version", "1.0") - indy_proof_request["nonce"] = ( + proof_request["name"] = request_data.get("name", "proof-request") + proof_request["version"] = request_data.get("version", "1.0") + proof_request["nonce"] = ( request_data.get("nonce") or await generate_pr_nonce() ) else: - indy_proof_request["name"] = "proof-request" - indy_proof_request["version"] = "1.0" - indy_proof_request["nonce"] = await generate_pr_nonce() - return self.get_format_data(PRES_20_REQUEST, indy_proof_request) + proof_request["name"] = "proof-request" + proof_request["version"] = "1.0" + proof_request["nonce"] = await generate_pr_nonce() + return self.get_format_data(PRES_20_REQUEST, proof_request) async def create_pres( self, @@ -131,45 +131,58 @@ async def create_pres( ) -> Tuple[V20PresFormat, AttachDecorator]: """Create a presentation.""" requested_credentials = {} + + # This is used for the fallback to indy format + from ..indy.handler import IndyPresExchangeHandler + if not request_data: try: proof_request = pres_ex_record.pres_request - indy_proof_request = proof_request.attachment( + # Fall back to indy format should be removed when indy format retired + proof_request = proof_request.attachment( AnonCredsPresExchangeHandler.format - ) - requested_credentials = await indy_proof_req_preview2indy_requested_creds( - indy_proof_request, - preview=None, - holder=AnonCredsHolder(self._profile), + ) or proof_request.attachment(IndyPresExchangeHandler.format) + requested_credentials = ( + await get_requested_creds_from_proof_request_preview( + proof_request, + holder=AnonCredsHolder(self._profile), + ) ) except ValueError as err: LOGGER.warning(f"{err}") - raise V20PresFormatHandlerError( - f"No matching Indy credentials found: {err}" - ) + raise V20PresFormatHandlerError(f"No matching credentials found: {err}") else: - if AnonCredsPresExchangeHandler.format.api in request_data: - indy_spec = request_data.get(AnonCredsPresExchangeHandler.format.api) + # Fall back to indy format should be removed when indy format retired + if ( + AnonCredsPresExchangeHandler.format.api in request_data + or IndyPresExchangeHandler.format.api in request_data + ): + spec = request_data.get( + AnonCredsPresExchangeHandler.format.api + ) or request_data.get(IndyPresExchangeHandler.format.api) requested_credentials = { - "self_attested_attributes": indy_spec["self_attested_attributes"], - "requested_attributes": indy_spec["requested_attributes"], - "requested_predicates": indy_spec["requested_predicates"], + "self_attested_attributes": spec["self_attested_attributes"], + "requested_attributes": spec["requested_attributes"], + "requested_predicates": spec["requested_predicates"], } - indy_handler = AnonCredsPresExchHandler(self._profile) - indy_proof = await indy_handler.return_presentation( + handler = AnonCredsPresExchHandler(self._profile) + presentation_proof = await handler.return_presentation( pres_ex_record=pres_ex_record, requested_credentials=requested_credentials, ) - return self.get_format_data(PRES_20, indy_proof) + return self.get_format_data(PRES_20, presentation_proof) async def receive_pres(self, message: V20Pres, pres_ex_record: V20PresExRecord): """Receive a presentation and check for presented values vs. proposal request.""" def _check_proof_vs_proposal(): """Check for bait and switch in presented values vs. proposal request.""" + from ..indy.handler import IndyPresExchangeHandler + + # Fall back to indy format should be removed when indy format retired proof_req = pres_ex_record.pres_request.attachment( AnonCredsPresExchangeHandler.format - ) + ) or pres_ex_record.pres_request.attachment(IndyPresExchangeHandler.format) # revealed attrs for reft, attr_spec in proof["requested_proof"]["revealed_attrs"].items(): @@ -256,7 +269,8 @@ def _check_proof_vs_proposal(): for req_restriction in req_restrictions: for k in list(req_restriction): # cannot modify en passant if k.startswith("attr::"): - req_restriction.pop(k) # let indy-sdk reject mismatch here + # let anoncreds-sdk reject mismatch here + req_restriction.pop(k) sub_proof_index = pred_spec["sub_proof_index"] for ge_proof in proof["proof"]["proofs"][sub_proof_index][ "primary_proof" @@ -313,10 +327,8 @@ async def verify_pres(self, pres_ex_record: V20PresExRecord) -> V20PresExRecord: """ pres_request_msg = pres_ex_record.pres_request - indy_proof_request = pres_request_msg.attachment( - AnonCredsPresExchangeHandler.format - ) - indy_proof = pres_ex_record.pres.attachment(AnonCredsPresExchangeHandler.format) + proof_request = pres_request_msg.attachment(AnonCredsPresExchangeHandler.format) + proof = pres_ex_record.pres.attachment(AnonCredsPresExchangeHandler.format) verifier = AnonCredsVerifier(self._profile) ( @@ -324,13 +336,13 @@ async def verify_pres(self, pres_ex_record: V20PresExRecord) -> V20PresExRecord: cred_defs, rev_reg_defs, rev_lists, - ) = await verifier.process_pres_identifiers(indy_proof["identifiers"]) + ) = await verifier.process_pres_identifiers(proof["identifiers"]) verifier = AnonCredsVerifier(self._profile) (verified, verified_msgs) = await verifier.verify_presentation( - indy_proof_request, - indy_proof, + proof_request, + proof, schemas, cred_defs, rev_reg_defs, diff --git a/acapy_agent/protocols/present_proof/v2_0/formats/handler.py b/acapy_agent/protocols/present_proof/v2_0/formats/handler.py index c4abf9d4c2..7e4e421cb6 100644 --- a/acapy_agent/protocols/present_proof/v2_0/formats/handler.py +++ b/acapy_agent/protocols/present_proof/v2_0/formats/handler.py @@ -1,4 +1,4 @@ -"""present-proof-v2 format handler - supports DIF and INDY.""" +"""present-proof-v2 format handler - supports ANONCREDS, DIF and INDY.""" import logging from abc import ABC, abstractclassmethod, abstractmethod diff --git a/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py b/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py index 306ed3b1af..bac3933919 100644 --- a/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py +++ b/acapy_agent/protocols/present_proof/v2_0/formats/indy/handler.py @@ -88,9 +88,6 @@ def get_format_identifier(self, message_type: str) -> str: str: Issue credential attachment format identifier """ - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return self.anoncreds_handler.get_format_identifier(message_type) return ATTACHMENT_FORMAT[message_type][IndyPresExchangeHandler.format.api] @@ -98,9 +95,6 @@ def get_format_data( self, message_type: str, data: dict ) -> Tuple[V20PresFormat, AttachDecorator]: """Get presentation format and attach objects for use in pres_ex messages.""" - # Temporary shim while the new anoncreds library integration is in progress - if self.anoncreds_handler: - return self.anoncreds_handler.get_format_data(message_type, data) return ( V20PresFormat( @@ -154,9 +148,12 @@ async def create_pres( request_data: Optional[dict] = None, ) -> Tuple[V20PresFormat, AttachDecorator]: """Create a presentation.""" - # Temporary shim while the new anoncreds library integration is in progress + if self.anoncreds_handler: - return await self.anoncreds_handler.create_pres(pres_ex_record, request_data) + return await self.anoncreds_handler.create_pres( + pres_ex_record, + request_data, + ) requested_credentials = {} if not request_data: @@ -349,8 +346,14 @@ async def verify_pres(self, pres_ex_record: V20PresExRecord) -> V20PresExRecord: return await self.anoncreds_handler.verify_pres(pres_ex_record) pres_request_msg = pres_ex_record.pres_request - indy_proof_request = pres_request_msg.attachment(IndyPresExchangeHandler.format) - indy_proof = pres_ex_record.pres.attachment(IndyPresExchangeHandler.format) + + # The `or` anoncreds format is for the indy <--> anoncreds compatibility + indy_proof_request = pres_request_msg.attachment( + IndyPresExchangeHandler.format + ) or pres_request_msg.attachment(AnonCredsPresExchangeHandler.format) + indy_proof = pres_ex_record.pres.attachment( + IndyPresExchangeHandler.format + ) or pres_ex_record.pres.attachment(AnonCredsPresExchangeHandler.format) indy_handler = IndyPresExchHandler(self._profile) ( schemas, diff --git a/acapy_agent/protocols/present_proof/v2_0/message_types.py b/acapy_agent/protocols/present_proof/v2_0/message_types.py index 97b8f063fc..5654ef7d42 100644 --- a/acapy_agent/protocols/present_proof/v2_0/message_types.py +++ b/acapy_agent/protocols/present_proof/v2_0/message_types.py @@ -32,14 +32,17 @@ # Format specifications ATTACHMENT_FORMAT = { PRES_20_PROPOSAL: { + V20PresFormat.Format.ANONCREDS.api: "anoncreds/proof-req@v2.0", V20PresFormat.Format.INDY.api: "hlindy/proof-req@v2.0", V20PresFormat.Format.DIF.api: "dif/presentation-exchange/definitions@v1.0", }, PRES_20_REQUEST: { + V20PresFormat.Format.ANONCREDS.api: "anoncreds/proof-req@v2.0", V20PresFormat.Format.INDY.api: "hlindy/proof-req@v2.0", V20PresFormat.Format.DIF.api: "dif/presentation-exchange/definitions@v1.0", }, PRES_20: { + V20PresFormat.Format.ANONCREDS.api: "anoncreds/proof@v2.0", V20PresFormat.Format.INDY.api: "hlindy/proof@v2.0", V20PresFormat.Format.DIF.api: "dif/presentation-exchange/submission@v1.0", }, diff --git a/acapy_agent/protocols/present_proof/v2_0/messages/pres_format.py b/acapy_agent/protocols/present_proof/v2_0/messages/pres_format.py index 5c55384c86..e65e98644f 100644 --- a/acapy_agent/protocols/present_proof/v2_0/messages/pres_format.py +++ b/acapy_agent/protocols/present_proof/v2_0/messages/pres_format.py @@ -30,6 +30,13 @@ class Meta: class Format(Enum): """Attachment format.""" + ANONCREDS = FormatSpec( + "anoncreds/", + DeferLoad( + "acapy_agent.protocols.present_proof.v2_0" + ".formats.anoncreds.handler.AnonCredsPresExchangeHandler" + ), + ) INDY = FormatSpec( "hlindy/", DeferLoad( @@ -37,19 +44,6 @@ class Format(Enum): ".formats.indy.handler.IndyPresExchangeHandler" ), ) - """ - To make the switch from indy to anoncreds replace the above with the following. - - :: - - INDY = FormatSpec( - "hlindy/", - DeferLoad( - "acapy_agent.protocols.present_proof.v2_0" - ".formats.anoncreds.handler.AnonCredsPresExchangeHandler" - ), - ) - """ DIF = FormatSpec( "dif/", DeferLoad( diff --git a/acapy_agent/protocols/present_proof/v2_0/routes.py b/acapy_agent/protocols/present_proof/v2_0/routes.py index 2edb0e4c08..b53188f118 100644 --- a/acapy_agent/protocols/present_proof/v2_0/routes.py +++ b/acapy_agent/protocols/present_proof/v2_0/routes.py @@ -16,6 +16,7 @@ from ....admin.decorators.auth import tenant_authentication from ....admin.request_context import AdminRequestContext from ....anoncreds.holder import AnonCredsHolder, AnonCredsHolderError +from ....anoncreds.models.presentation_request import AnoncredsPresentationRequestSchema from ....connections.models.conn_record import ConnRecord from ....indy.holder import IndyHolder, IndyHolderError from ....indy.models.cred_precis import IndyCredPrecisSchema @@ -118,6 +119,11 @@ class V20PresExRecordListSchema(OpenAPISchema): class V20PresProposalByFormatSchema(OpenAPISchema): """Schema for presentation proposal per format.""" + anoncreds = fields.Nested( + AnoncredsPresentationRequestSchema, + required=False, + metadata={"description": "Presentation proposal for anoncreds"}, + ) indy = fields.Nested( IndyProofRequestSchema, required=False, @@ -192,6 +198,11 @@ class V20PresProposalRequestSchema(AdminAPIMessageTracingSchema): class V20PresRequestByFormatSchema(OpenAPISchema): """Presentation request per format.""" + anoncreds = fields.Nested( + AnoncredsPresentationRequestSchema, + required=False, + metadata={"description": "Presentation proposal for anoncreds"}, + ) indy = fields.Nested( IndyProofRequestSchema, required=False, @@ -293,6 +304,11 @@ class V20PresentationSendRequestToProposalSchema(AdminAPIMessageTracingSchema): class V20PresSpecByFormatRequestSchema(AdminAPIMessageTracingSchema): """Presentation specification schema by format, for send-presentation request.""" + anoncreds = fields.Nested( + IndyPresSpecSchema, + required=False, + metadata={"description": "Presentation specification for anoncreds"}, + ) indy = fields.Nested( IndyPresSpecSchema, required=False, @@ -406,7 +422,10 @@ def _formats_attach(by_format: Mapping, msg_type: str, spec: str) -> Mapping: """Break out formats and proposals/requests/presentations for v2.0 messages.""" attach = [] for fmt_api, item_by_fmt in by_format.items(): - if fmt_api == V20PresFormat.Format.INDY.api: + if ( + fmt_api == V20PresFormat.Format.ANONCREDS.api + or fmt_api == V20PresFormat.Format.INDY.api + ): attach.append(AttachDecorator.data_base64(mapping=item_by_fmt, ident=fmt_api)) elif fmt_api == V20PresFormat.Format.DIF.api: attach.append(AttachDecorator.data_json(mapping=item_by_fmt, ident=fmt_api)) @@ -557,19 +576,24 @@ async def present_proof_credentials_list(request: web.BaseRequest): wallet_type = profile.settings.get_value("wallet.type") if wallet_type == "askar-anoncreds": - indy_holder = AnonCredsHolder(profile) + holder = AnonCredsHolder(profile) else: - indy_holder = profile.inject(IndyHolder) - indy_credentials = [] - # INDY + holder = profile.inject(IndyHolder) + credentials = [] + # ANONCREDS or INDY try: - indy_pres_request = pres_ex_record.by_format["pres_request"].get( - V20PresFormat.Format.INDY.api + # try anoncreds and fallback to indy + pres_request = pres_ex_record.by_format["pres_request"].get( + V20PresFormat.Format.ANONCREDS.api ) - if indy_pres_request: - indy_credentials = ( - await indy_holder.get_credentials_for_presentation_request_by_referent( - indy_pres_request, + if not pres_request: + pres_request = pres_ex_record.by_format["pres_request"].get( + V20PresFormat.Format.INDY.api + ) + if pres_request: + credentials = ( + await holder.get_credentials_for_presentation_request_by_referent( + pres_request, pres_referents, start, count, @@ -771,7 +795,7 @@ async def present_proof_credentials_list(request: web.BaseRequest): pres_ex_record, outbound_handler, ) - credentials = list(indy_credentials) + dif_cred_value_list + credentials = list(credentials) + dif_cred_value_list return web.json_response(credentials) @@ -911,8 +935,11 @@ async def present_proof_create_request(request: web.BaseRequest): comment = body.get("comment") pres_request_spec = body.get("presentation_request") - if pres_request_spec and V20PresFormat.Format.INDY.api in pres_request_spec: - await _add_nonce(pres_request_spec[V20PresFormat.Format.INDY.api]) + if pres_request_spec: + if V20PresFormat.Format.INDY.api in pres_request_spec: + await _add_nonce(pres_request_spec[V20PresFormat.Format.INDY.api]) + if V20PresFormat.Format.ANONCREDS.api in pres_request_spec: + await _add_nonce(pres_request_spec[V20PresFormat.Format.ANONCREDS.api]) pres_request_message = V20PresRequest( comment=comment, @@ -995,8 +1022,11 @@ async def present_proof_send_free_request(request: web.BaseRequest): comment = body.get("comment") pres_request_spec = body.get("presentation_request") - if pres_request_spec and V20PresFormat.Format.INDY.api in pres_request_spec: - await _add_nonce(pres_request_spec[V20PresFormat.Format.INDY.api]) + if pres_request_spec: + if V20PresFormat.Format.INDY.api in pres_request_spec: + await _add_nonce(pres_request_spec[V20PresFormat.Format.INDY.api]) + if V20PresFormat.Format.ANONCREDS.api in pres_request_spec: + await _add_nonce(pres_request_spec[V20PresFormat.Format.ANONCREDS.api]) pres_request_message = V20PresRequest( comment=comment, will_confirm=True, @@ -1157,7 +1187,7 @@ async def present_proof_send_presentation(request: web.BaseRequest): outbound_handler = request["outbound_message_router"] pres_ex_id = request.match_info["pres_ex_id"] body = await request.json() - supported_formats = ["dif", "indy"] + supported_formats = ["anoncreds", "dif", "indy"] if not any(x in body for x in supported_formats): raise web.HTTPBadRequest( reason=( diff --git a/acapy_agent/protocols/present_proof/v2_0/tests/test_manager_anoncreds.py b/acapy_agent/protocols/present_proof/v2_0/tests/test_manager_anoncreds.py index 0ee4f1ad38..78d93e01a7 100644 --- a/acapy_agent/protocols/present_proof/v2_0/tests/test_manager_anoncreds.py +++ b/acapy_agent/protocols/present_proof/v2_0/tests/test_manager_anoncreds.py @@ -74,7 +74,7 @@ ) ], ) -INDY_PROOF_REQ_NAME = { +ANONCREDS_PROOF_REQ_NAME = { "name": PROOF_REQ_NAME, "version": PROOF_REQ_VERSION, "nonce": PROOF_REQ_NONCE, @@ -100,7 +100,7 @@ } }, } -INDY_PROOF_REQ_NAMES = { +ANONCREDS_PROOF_REQ_NAMES = { "name": PROOF_REQ_NAME, "version": PROOF_REQ_VERSION, "nonce": PROOF_REQ_NONCE, @@ -121,7 +121,7 @@ } }, } -INDY_PROOF_REQ_SELFIE = { +ANONCREDS_PROOF_REQ_SELFIE = { "name": PROOF_REQ_NAME, "version": PROOF_REQ_VERSION, "nonce": PROOF_REQ_NONCE, @@ -133,7 +133,7 @@ "0_highscore_GE_uuid": {"name": "highScore", "p_type": ">=", "p_value": 1000000} }, } -INDY_PROOF = { +ANONCREDS_PROOF = { "proof": { "proofs": [ { @@ -252,7 +252,7 @@ } ], } -INDY_PROOF_NAMES = { +ANONCREDS_PROOF_NAMES = { "proof": { "proofs": [ { @@ -512,7 +512,9 @@ async def test_record_eq(self): async def test_create_exchange_for_proposal(self): proposal = V20PresProposal( formats=[ - V20PresFormat(attach_id="indy", format_=V20PresFormat.Format.INDY.aries) + V20PresFormat( + attach_id="anoncreds", format_=V20PresFormat.Format.ANONCREDS.aries + ) ] ) @@ -537,7 +539,9 @@ async def test_receive_proposal(self): connection_record = mock.MagicMock(connection_id=CONN_ID) proposal = V20PresProposal( formats=[ - V20PresFormat(attach_id="indy", format_=V20PresFormat.Format.INDY.aries) + V20PresFormat( + attach_id="anoncreds", format_=V20PresFormat.Format.ANONCREDS.aries + ) ] ) with mock.patch.object(V20PresExRecord, "save", autospec=True) as save_ex: @@ -555,14 +559,14 @@ async def test_create_bound_request_a(self): proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], proposals_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) px_rec = V20PresExRecord( @@ -589,14 +593,14 @@ async def test_create_bound_request_b(self): proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], proposals_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) px_rec = V20PresExRecord( @@ -725,14 +729,16 @@ async def test_create_exchange_for_request(self): will_confirm=True, formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(mapping=INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64( + mapping=ANONCREDS_PROOF_REQ_NAME, ident="anoncreds" + ) ], ) pres_req.assign_thread_id("dummy") @@ -765,14 +771,14 @@ async def test_create_pres_indy(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) px_rec_in = V20PresExRecord(pres_request=pres_request.serialize()) @@ -795,9 +801,9 @@ async def test_create_pres_indy(self): ) req_creds = await indy_proof_req_preview2indy_requested_creds( - INDY_PROOF_REQ_NAME, preview=None, holder=self.holder + ANONCREDS_PROOF_REQ_NAME, preview=None, holder=self.holder ) - request_data = {"indy": req_creds} + request_data = {"anoncreds": req_creds} assert not req_creds["self_attested_attributes"] assert len(req_creds["requested_attributes"]) == 2 assert len(req_creds["requested_predicates"]) == 1 @@ -813,9 +819,9 @@ async def test_create_pres_indy_and_dif(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ), V20PresFormat( @@ -826,7 +832,7 @@ async def test_create_pres_indy_and_dif(self): ), ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy"), + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds"), AttachDecorator.data_json(DIF_PRES_REQ, ident="dif"), ], ) @@ -857,9 +863,9 @@ async def test_create_pres_indy_and_dif(self): ) req_creds = await indy_proof_req_preview2indy_requested_creds( - INDY_PROOF_REQ_NAME, preview=None, holder=self.holder + ANONCREDS_PROOF_REQ_NAME, preview=None, holder=self.holder ) - request_data = {"indy": req_creds, "dif": DIF_PRES_REQ} + request_data = {"anoncreds": req_creds, "dif": DIF_PRES_REQ} assert not req_creds["self_attested_attributes"] assert len(req_creds["requested_attributes"]) == 2 assert len(req_creds["requested_predicates"]) == 1 @@ -872,19 +878,19 @@ async def test_create_pres_indy_and_dif(self): @pytest.mark.skip(reason="Anoncreds-break") async def test_create_pres_proof_req_non_revoc_interval_none(self): - indy_proof_req_vcx = deepcopy(INDY_PROOF_REQ_NAME) + indy_proof_req_vcx = deepcopy(ANONCREDS_PROOF_REQ_NAME) indy_proof_req_vcx["non_revoked"] = None # simulate interop with indy-vcx pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req_vcx, ident="indy") + AttachDecorator.data_base64(indy_proof_req_vcx, ident="anoncreds") ], ) px_rec_in = V20PresExRecord(pres_request=pres_request.serialize()) @@ -918,7 +924,7 @@ async def test_create_pres_proof_req_non_revoc_interval_none(self): req_creds = await indy_proof_req_preview2indy_requested_creds( indy_proof_req_vcx, preview=None, holder=self.holder ) - request_data = {"indy": req_creds} + request_data = {"anoncreds": req_creds} assert not req_creds["self_attested_attributes"] assert len(req_creds["requested_attributes"]) == 2 assert len(req_creds["requested_predicates"]) == 1 @@ -934,14 +940,14 @@ async def test_create_pres_self_asserted(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_SELFIE, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_SELFIE, ident="anoncreds") ], ) px_rec_in = V20PresExRecord(pres_request=pres_request.serialize()) @@ -965,9 +971,9 @@ async def test_create_pres_self_asserted(self): ) req_creds = await indy_proof_req_preview2indy_requested_creds( - INDY_PROOF_REQ_SELFIE, preview=None, holder=self.holder + ANONCREDS_PROOF_REQ_SELFIE, preview=None, holder=self.holder ) - request_data = {"indy": req_creds} + request_data = {"anoncreds": req_creds} assert len(req_creds["self_attested_attributes"]) == 3 assert not req_creds["requested_attributes"] @@ -991,14 +997,14 @@ async def test_create_pres_no_revocation(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) px_rec_in = V20PresExRecord(pres_request=pres_request.serialize()) @@ -1042,10 +1048,10 @@ async def test_create_pres_no_revocation(self): ) req_creds = await indy_proof_req_preview2indy_requested_creds( - INDY_PROOF_REQ_NAME, preview=None, holder=self.holder + ANONCREDS_PROOF_REQ_NAME, preview=None, holder=self.holder ) request_data = { - "indy": { + "anoncreds": { "self_attested_attributes": req_creds["self_attested_attributes"], "requested_attributes": req_creds["requested_attributes"], "requested_predicates": req_creds["requested_predicates"], @@ -1062,7 +1068,7 @@ async def test_create_pres_no_revocation(self): for pred_reft_spec in req_creds["requested_predicates"].values(): pred_reft_spec["timestamp"] = 1234567890 request_data = { - "indy": { + "anoncreds": { "self_attested_attributes": req_creds["self_attested_attributes"], "requested_attributes": req_creds["requested_attributes"], "requested_predicates": req_creds["requested_predicates"], @@ -1076,14 +1082,14 @@ async def test_create_pres_bad_revoc_state(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) px_rec_in = V20PresExRecord(pres_request=pres_request.serialize()) @@ -1147,14 +1153,14 @@ async def test_create_pres_multi_matching_proposal_creds_names(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAMES, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAMES, ident="anoncreds") ], ) px_rec_in = V20PresExRecord(pres_request=pres_request.serialize()) @@ -1228,12 +1234,12 @@ async def test_create_pres_multi_matching_proposal_creds_names(self): ) req_creds = await indy_proof_req_preview2indy_requested_creds( - INDY_PROOF_REQ_NAMES, preview=None, holder=self.holder + ANONCREDS_PROOF_REQ_NAMES, preview=None, holder=self.holder ) assert not req_creds["self_attested_attributes"] assert len(req_creds["requested_attributes"]) == 1 assert len(req_creds["requested_predicates"]) == 1 - request_data = {"indy": req_creds} + request_data = {"anoncreds": req_creds} (px_rec_out, pres_msg) = await self.manager.create_pres( px_rec_in, request_data ) @@ -1244,14 +1250,14 @@ async def test_no_matching_creds_for_proof_req(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAMES, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAMES, ident="anoncreds") ], ) V20PresExRecord(pres_request=pres_request.serialize()) @@ -1260,7 +1266,7 @@ async def test_no_matching_creds_for_proof_req(self): with self.assertRaises(ValueError): await indy_proof_req_preview2indy_requested_creds( - INDY_PROOF_REQ_NAMES, preview=None, holder=self.holder + ANONCREDS_PROOF_REQ_NAMES, preview=None, holder=self.holder ) get_creds = mock.CoroutineMock( @@ -1277,21 +1283,21 @@ async def test_no_matching_creds_for_proof_req(self): ) self.holder.get_credentials_for_presentation_request_by_referent = get_creds await indy_proof_req_preview2indy_requested_creds( - INDY_PROOF_REQ_NAMES, preview=None, holder=self.holder + ANONCREDS_PROOF_REQ_NAMES, preview=None, holder=self.holder ) async def test_no_matching_creds_indy_handler(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAMES, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAMES, ident="anoncreds") ], ) px_rec_in = V20PresExRecord(pres_request=pres_request.serialize()) @@ -1311,44 +1317,50 @@ async def test_no_matching_creds_indy_handler(self): (px_rec_out, pres_msg) = await self.manager.create_pres( px_rec_in, request_data ) - assert "No matching Indy" in str(context.exception) + assert "AnonCreds interface requires AskarAnoncreds profile" in str( + context.exception + ) async def test_receive_pres(self): connection_record = mock.MagicMock(connection_id=CONN_ID) pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], proposals_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) pres = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) pres.assign_thread_id("thread-id") @@ -1360,8 +1372,8 @@ async def test_receive_pres(self): # cover by_format property by_format = px_rec_dummy.by_format - assert by_format.get("pres_proposal").get("indy") == INDY_PROOF_REQ_NAME - assert by_format.get("pres_request").get("indy") == INDY_PROOF_REQ_NAME + assert by_format.get("pres_proposal").get("anoncreds") == ANONCREDS_PROOF_REQ_NAME + assert by_format.get("pres_request").get("anoncreds") == ANONCREDS_PROOF_REQ_NAME with mock.patch.object( V20PresExRecord, "save", autospec=True @@ -1383,41 +1395,45 @@ async def test_receive_pres_receive_pred_value_mismatch_punt_to_indy(self): pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], proposals_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) - indy_proof_req = deepcopy(INDY_PROOF_REQ_NAME) + indy_proof_req = deepcopy(ANONCREDS_PROOF_REQ_NAME) indy_proof_req["requested_predicates"]["0_highscore_GE_uuid"]["restrictions"][0][ "attr::player::value" ] = "impostor" pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) pres.assign_thread_id("thread-id") @@ -1429,8 +1445,8 @@ async def test_receive_pres_receive_pred_value_mismatch_punt_to_indy(self): # cover by_format property by_format = px_rec_dummy.by_format - assert by_format.get("pres_proposal").get("indy") == INDY_PROOF_REQ_NAME - assert by_format.get("pres_request").get("indy") == indy_proof_req + assert by_format.get("pres_proposal").get("anoncreds") == ANONCREDS_PROOF_REQ_NAME + assert by_format.get("pres_request").get("anoncreds") == indy_proof_req with mock.patch.object( V20PresExRecord, "save", autospec=True @@ -1478,24 +1494,28 @@ async def test_receive_pres_indy_no_predicate_restrictions(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) pres.assign_thread_id("thread-id") @@ -1506,7 +1526,7 @@ async def test_receive_pres_indy_no_predicate_restrictions(self): # cover by_format property by_format = px_rec_dummy.by_format - assert by_format.get("pres_request").get("indy") == indy_proof_req + assert by_format.get("pres_request").get("anoncreds") == indy_proof_req with mock.patch.object( V20PresExRecord, "save", autospec=True @@ -1538,7 +1558,7 @@ async def test_receive_pres_indy_no_attr_restrictions(self): }, "requested_predicates": {}, } - proof = deepcopy(INDY_PROOF) + proof = deepcopy(ANONCREDS_PROOF) proof["requested_proof"]["revealed_attrs"] = { "0_player_uuid": { "sub_proof_index": 0, @@ -1550,24 +1570,26 @@ async def test_receive_pres_indy_no_attr_restrictions(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(proof, ident="indy")], + presentations_attach=[AttachDecorator.data_base64(proof, ident="anoncreds")], ) pres.assign_thread_id("thread-id") @@ -1578,7 +1600,7 @@ async def test_receive_pres_indy_no_attr_restrictions(self): # cover by_format property by_format = px_rec_dummy.by_format - assert by_format.get("pres_request").get("indy") == indy_proof_req + assert by_format.get("pres_request").get("anoncreds") == indy_proof_req with mock.patch.object( V20PresExRecord, "save", autospec=True @@ -1597,44 +1619,48 @@ async def test_receive_pres_indy_no_attr_restrictions(self): async def test_receive_pres_bait_and_switch_attr_name(self): connection_record = mock.MagicMock(connection_id=CONN_ID) - indy_proof_req = deepcopy(INDY_PROOF_REQ_NAME) + indy_proof_req = deepcopy(ANONCREDS_PROOF_REQ_NAME) indy_proof_req["requested_attributes"]["0_screencapture_uuid"]["restrictions"][0][ "attr::screenCapture::value" ] = "c2NyZWVuIGNhcHR1cmUgc2hvd2luZyBzY29yZSBpbiB0aGUgbWlsbGlvbnM=" pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], proposals_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres_x = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) px_rec_dummy = V20PresExRecord( pres_proposal=pres_proposal.serialize(), @@ -1655,33 +1681,41 @@ async def test_receive_pres_bait_and_switch_attr_name(self): pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], - proposals_attach=[AttachDecorator.data_base64(indy_proof_req, ident="indy")], + proposals_attach=[ + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") + ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres_x = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) px_rec_dummy = V20PresExRecord( @@ -1699,43 +1733,47 @@ async def test_receive_pres_bait_and_switch_attr_name(self): async def test_receive_pres_bait_and_switch_attr_names(self): connection_record = mock.MagicMock(connection_id=CONN_ID) - indy_proof_req = deepcopy(INDY_PROOF_REQ_NAMES) + indy_proof_req = deepcopy(ANONCREDS_PROOF_REQ_NAMES) indy_proof_req["requested_attributes"]["0_player_uuid"]["restrictions"][0][ "attr::screenCapture::value" ] = "c2NyZWVuIGNhcHR1cmUgc2hvd2luZyBzY29yZSBpbiB0aGUgbWlsbGlvbnM=" pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], - proposals_attach=[AttachDecorator.data_base64(indy_proof_req, ident="indy")], + proposals_attach=[ + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") + ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres_x = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_NAMES, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_NAMES, ident="anoncreds") ], ) @@ -1760,34 +1798,40 @@ async def test_receive_pres_bait_and_switch_attr_names(self): pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], - proposals_attach=[AttachDecorator.data_base64(indy_proof_req, ident="indy")], + proposals_attach=[ + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") + ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres_x = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_NAMES, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_NAMES, ident="anoncreds") ], ) @@ -1806,42 +1850,46 @@ async def test_receive_pres_bait_and_switch_attr_names(self): async def test_receive_pres_bait_and_switch_pred(self): connection_record = mock.MagicMock(connection_id=CONN_ID) - indy_proof_req = deepcopy(INDY_PROOF_REQ_NAME) + indy_proof_req = deepcopy(ANONCREDS_PROOF_REQ_NAME) indy_proof_req["requested_predicates"] = {} pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], proposals_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres_x = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) px_rec_dummy = V20PresExRecord( @@ -1867,33 +1915,41 @@ async def test_receive_pres_bait_and_switch_pred(self): pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], - proposals_attach=[AttachDecorator.data_base64(indy_proof_req, ident="indy")], + proposals_attach=[ + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") + ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres_x = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) px_rec_dummy = V20PresExRecord( @@ -1919,33 +1975,41 @@ async def test_receive_pres_bait_and_switch_pred(self): pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], - proposals_attach=[AttachDecorator.data_base64(indy_proof_req, ident="indy")], + proposals_attach=[ + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") + ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres_x = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) px_rec_dummy = V20PresExRecord( @@ -1971,33 +2035,41 @@ async def test_receive_pres_bait_and_switch_pred(self): pres_proposal = V20PresProposal( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], - proposals_attach=[AttachDecorator.data_base64(indy_proof_req, ident="indy")], + proposals_attach=[ + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") + ], ) pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], request_presentations_attach=[ - AttachDecorator.data_base64(indy_proof_req, ident="indy") + AttachDecorator.data_base64(indy_proof_req, ident="anoncreds") ], ) pres_x = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) px_rec_dummy = V20PresExRecord( @@ -2020,25 +2092,29 @@ async def test_verify_pres(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ) ], will_confirm=True, request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy") + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds") ], ) pres = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ) ], - presentations_attach=[AttachDecorator.data_base64(INDY_PROOF, ident="indy")], + presentations_attach=[ + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds") + ], ) px_rec_in = V20PresExRecord( pres_request=pres_request, @@ -2063,9 +2139,9 @@ async def test_verify_pres_indy_and_dif(self): pres_request = V20PresRequest( formats=[ V20PresFormat( - attach_id="indy", + attach_id="anoncreds", format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][ - V20PresFormat.Format.INDY.api + V20PresFormat.Format.ANONCREDS.api ], ), V20PresFormat( @@ -2077,15 +2153,17 @@ async def test_verify_pres_indy_and_dif(self): ], will_confirm=True, request_presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF_REQ_NAME, ident="indy"), + AttachDecorator.data_base64(ANONCREDS_PROOF_REQ_NAME, ident="anoncreds"), AttachDecorator.data_json(DIF_PRES_REQ, ident="dif"), ], ) pres = V20Pres( formats=[ V20PresFormat( - attach_id="indy", - format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api], + attach_id="anoncreds", + format_=ATTACHMENT_FORMAT[PRES_20][ + V20PresFormat.Format.ANONCREDS.api + ], ), V20PresFormat( attach_id="dif", @@ -2093,7 +2171,7 @@ async def test_verify_pres_indy_and_dif(self): ), ], presentations_attach=[ - AttachDecorator.data_base64(INDY_PROOF, ident="indy"), + AttachDecorator.data_base64(ANONCREDS_PROOF, ident="anoncreds"), AttachDecorator.data_json(DIF_PRES, ident="dif"), ], ) diff --git a/acapy_agent/protocols/present_proof/v2_0/tests/test_routes.py b/acapy_agent/protocols/present_proof/v2_0/tests/test_routes.py index af70cd2d0b..b1fb15ef7f 100644 --- a/acapy_agent/protocols/present_proof/v2_0/tests/test_routes.py +++ b/acapy_agent/protocols/present_proof/v2_0/tests/test_routes.py @@ -6,8 +6,10 @@ from marshmallow import ValidationError from .....admin.request_context import AdminRequestContext +from .....anoncreds.models.presentation_request import ( + AnoncredsPresentationReqAttrSpecSchema, +) from .....indy.holder import IndyHolder -from .....indy.models.proof_request import IndyProofReqAttrSpecSchema from .....indy.verifier import IndyVerifier from .....ledger.base import BaseLedger from .....storage.error import StorageNotFoundError @@ -221,7 +223,7 @@ async def test_validate(self): schema.validate_fields({"veres-one": {"no": "support"}}) async def test_validate_proof_req_attr_spec(self): - aspec = IndyProofReqAttrSpecSchema() + aspec = AnoncredsPresentationReqAttrSpecSchema() aspec.validate_fields({"name": "attr0"}) aspec.validate_fields( { diff --git a/acapy_agent/protocols/present_proof/v2_0/tests/test_routes_anoncreds.py b/acapy_agent/protocols/present_proof/v2_0/tests/test_routes_anoncreds.py index 96c3da744e..faa4f0f278 100644 --- a/acapy_agent/protocols/present_proof/v2_0/tests/test_routes_anoncreds.py +++ b/acapy_agent/protocols/present_proof/v2_0/tests/test_routes_anoncreds.py @@ -8,8 +8,10 @@ from .....admin.request_context import AdminRequestContext from .....anoncreds.holder import AnonCredsHolder +from .....anoncreds.models.presentation_request import ( + AnoncredsPresentationReqAttrSpecSchema, +) from .....anoncreds.verifier import AnonCredsVerifier -from .....indy.models.proof_request import IndyProofReqAttrSpecSchema from .....ledger.base import BaseLedger from .....storage.error import StorageNotFoundError from .....storage.vc_holder.base import VCHolder @@ -223,7 +225,7 @@ async def test_validate(self): schema.validate_fields({"veres-one": {"no": "support"}}) async def test_validate_proof_req_attr_spec(self): - aspec = IndyProofReqAttrSpecSchema() + aspec = AnoncredsPresentationReqAttrSpecSchema() aspec.validate_fields({"name": "attr0"}) aspec.validate_fields( { diff --git a/acapy_agent/revocation_anoncreds/routes.py b/acapy_agent/revocation_anoncreds/routes.py index 928ef0ebd8..4c5b3bd8b0 100644 --- a/acapy_agent/revocation_anoncreds/routes.py +++ b/acapy_agent/revocation_anoncreds/routes.py @@ -24,7 +24,7 @@ ) from ..anoncreds.default.legacy_indy.registry import LegacyIndyRegistry from ..anoncreds.issuer import AnonCredsIssuerError -from ..anoncreds.models.anoncreds_revocation import RevRegDefState +from ..anoncreds.models.revocation import RevRegDefState from ..anoncreds.revocation import AnonCredsRevocation, AnonCredsRevocationError from ..anoncreds.routes import ( create_transaction_for_endorser_description, diff --git a/acapy_agent/revocation_anoncreds/tests/test_routes.py b/acapy_agent/revocation_anoncreds/tests/test_routes.py index 11d4ea25e3..4fef93761e 100644 --- a/acapy_agent/revocation_anoncreds/tests/test_routes.py +++ b/acapy_agent/revocation_anoncreds/tests/test_routes.py @@ -6,7 +6,7 @@ from aiohttp.web import HTTPNotFound from ...admin.request_context import AdminRequestContext -from ...anoncreds.models.anoncreds_revocation import RevRegDef, RevRegDefValue +from ...anoncreds.models.revocation import RevRegDef, RevRegDefValue from ...tests import mock from ...utils.testing import create_test_profile from .. import routes as test_module diff --git a/acapy_agent/vc/vc_ld/models/linked_data_proof.py b/acapy_agent/vc/vc_ld/models/linked_data_proof.py index c441ff5911..57853000c6 100644 --- a/acapy_agent/vc/vc_ld/models/linked_data_proof.py +++ b/acapy_agent/vc/vc_ld/models/linked_data_proof.py @@ -6,8 +6,8 @@ from ....messaging.models.base import BaseModel, BaseModelSchema from ....messaging.valid import ( - INDY_ISO8601_DATETIME_EXAMPLE, - INDY_ISO8601_DATETIME_VALIDATE, + ISO8601_DATETIME_EXAMPLE, + ISO8601_DATETIME_VALIDATE, UUID4_EXAMPLE, Uri, ) @@ -93,13 +93,13 @@ class Meta: created = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": ( "The string value of an ISO8601 combined date and time string generated" " by the Signature Algorithm" ), - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) diff --git a/acapy_agent/vc/vc_ld/models/options.py b/acapy_agent/vc/vc_ld/models/options.py index 2d7adbe4e2..a939df56ac 100644 --- a/acapy_agent/vc/vc_ld/models/options.py +++ b/acapy_agent/vc/vc_ld/models/options.py @@ -5,8 +5,8 @@ from marshmallow import INCLUDE, Schema, fields from acapy_agent.messaging.valid import ( - INDY_ISO8601_DATETIME_EXAMPLE, - INDY_ISO8601_DATETIME_VALIDATE, + ISO8601_DATETIME_EXAMPLE, + ISO8601_DATETIME_VALIDATE, UUID4_EXAMPLE, ) @@ -124,13 +124,13 @@ class Meta: created = fields.Str( required=False, - validate=INDY_ISO8601_DATETIME_VALIDATE, + validate=ISO8601_DATETIME_VALIDATE, metadata={ "description": ( "The date and time of the proof (with a maximum accuracy in seconds)." " Defaults to current system time" ), - "example": INDY_ISO8601_DATETIME_EXAMPLE, + "example": ISO8601_DATETIME_EXAMPLE, }, ) diff --git a/acapy_agent/wallet/anoncreds_upgrade.py b/acapy_agent/wallet/anoncreds_upgrade.py index 12f2cb2dd3..ce944c75d7 100644 --- a/acapy_agent/wallet/anoncreds_upgrade.py +++ b/acapy_agent/wallet/anoncreds_upgrade.py @@ -21,15 +21,15 @@ CATEGORY_CRED_DEF_PRIVATE, CATEGORY_SCHEMA, ) -from ..anoncreds.models.anoncreds_cred_def import CredDef, CredDefState -from ..anoncreds.models.anoncreds_revocation import ( +from ..anoncreds.models.credential_definition import CredDef, CredDefState +from ..anoncreds.models.revocation import ( RevList, RevListState, RevRegDef, RevRegDefState, RevRegDefValue, ) -from ..anoncreds.models.anoncreds_schema import SchemaState +from ..anoncreds.models.schema import SchemaState from ..anoncreds.revocation import ( CATEGORY_REV_LIST, CATEGORY_REV_REG_DEF, diff --git a/acapy_agent/wallet/routes.py b/acapy_agent/wallet/routes.py index 00bc48cfb1..cf539d61ac 100644 --- a/acapy_agent/wallet/routes.py +++ b/acapy_agent/wallet/routes.py @@ -9,11 +9,10 @@ from aiohttp_apispec import docs, querystring_schema, request_schema, response_schema from marshmallow import fields, validate -from acapy_agent.connections.base_manager import BaseConnectionManager - from ..admin.decorators.auth import tenant_authentication from ..admin.request_context import AdminRequestContext from ..config.injection_context import InjectionContext +from ..connections.base_manager import BaseConnectionManager from ..connections.models.conn_record import ConnRecord from ..core.event_bus import Event, EventBus from ..core.profile import Profile @@ -35,12 +34,12 @@ GENERIC_DID_VALIDATE, INDY_DID_EXAMPLE, INDY_DID_VALIDATE, - INDY_RAW_PUBLIC_KEY_EXAMPLE, - INDY_RAW_PUBLIC_KEY_VALIDATE, JWT_EXAMPLE, JWT_VALIDATE, NON_SD_LIST_EXAMPLE, NON_SD_LIST_VALIDATE, + RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, + RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, SD_JWT_EXAMPLE, SD_JWT_VALIDATE, UUID4_EXAMPLE, @@ -95,10 +94,10 @@ class DIDSchema(OpenAPISchema): ) verkey = fields.Str( required=True, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Public verification key", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) posture = fields.Str( @@ -293,10 +292,10 @@ class DIDListQueryStringSchema(OpenAPISchema): ) verkey = fields.Str( required=False, - validate=INDY_RAW_PUBLIC_KEY_VALIDATE, + validate=RAW_ED25519_2018_PUBLIC_KEY_VALIDATE, metadata={ "description": "Verification key of interest", - "example": INDY_RAW_PUBLIC_KEY_EXAMPLE, + "example": RAW_ED25519_2018_PUBLIC_KEY_EXAMPLE, }, ) posture = fields.Str( diff --git a/demo/bdd_support/agent_backchannel_client.py b/demo/bdd_support/agent_backchannel_client.py index 5d116e2fea..fa6db011c7 100644 --- a/demo/bdd_support/agent_backchannel_client.py +++ b/demo/bdd_support/agent_backchannel_client.py @@ -143,11 +143,13 @@ def aries_container_issue_credential( the_container: AgentContainer, cred_def_id: str, cred_attrs: list, + filter_type: str = "indy", ): return run_coroutine( the_container.issue_credential, cred_def_id, cred_attrs, + filter_type=filter_type, ) @@ -167,11 +169,13 @@ def aries_container_request_proof( the_container: AgentContainer, proof_request: dict, explicit_revoc_required: bool = False, + is_anoncreds: bool = False, ): return run_coroutine( the_container.request_proof, proof_request, explicit_revoc_required=explicit_revoc_required, + is_anoncreds=is_anoncreds, ) diff --git a/demo/features/0453-issue-credential.feature b/demo/features/0453-issue-credential.feature index 3927bbf4d9..4f9b47e46d 100644 --- a/demo/features/0453-issue-credential.feature +++ b/demo/features/0453-issue-credential.feature @@ -30,7 +30,7 @@ Feature: RFC 0453 Aries agent issue credential | --public-did --wallet-type askar-anoncreds | --wallet-type askar-anoncreds | driverslicense | Data_DL_NormalizedValues | | | | --public-did --wallet-type askar-anoncreds --cred-type vc_di | --wallet-type askar-anoncreds | driverslicense | Data_DL_NormalizedValues | | | - @Release @WalletType_Askar_AnonCreds @AltTests + @PR @Release @WalletType_Askar_AnonCreds Examples: | Acme_capabilities | Bob_capabilities | Schema_name | Credential_data | Acme_extra | Bob_extra | | --public-did --wallet-type askar-anoncreds | | driverslicense | Data_DL_NormalizedValues | | | diff --git a/demo/features/steps/0453-issue-credential.py b/demo/features/steps/0453-issue-credential.py index 97106d3e1d..d96fdae10a 100644 --- a/demo/features/steps/0453-issue-credential.py +++ b/demo/features/steps/0453-issue-credential.py @@ -62,10 +62,9 @@ def step_impl(context, issuer, credential_data): agent = context.active_agents[issuer] cred_attrs = read_credential_data(context.schema_name, credential_data) + filter_type = "indy" if not is_anoncreds(agent) else "anoncreds" cred_exchange = aries_container_issue_credential( - agent["agent"], - context.cred_def_id, - cred_attrs, + agent["agent"], context.cred_def_id, cred_attrs, filter_type ) context.cred_attrs = cred_attrs diff --git a/demo/features/steps/0454-present-proof.py b/demo/features/steps/0454-present-proof.py index 984ee72e63..31e91930f5 100644 --- a/demo/features/steps/0454-present-proof.py +++ b/demo/features/steps/0454-present-proof.py @@ -34,7 +34,11 @@ def step_impl(context, verifier, request_for_proof, prover): "restrictions" ] = cred_def_restrictions - proof_exchange = aries_container_request_proof(agent["agent"], proof_request_info) + proof_exchange = aries_container_request_proof( + agent["agent"], + proof_request_info, + agent["agent"].wallet_type == "askar-anoncreds", + ) context.proof_request = proof_request_info context.proof_exchange = proof_exchange @@ -49,7 +53,10 @@ def step_impl(context, verifier, request_for_proof, prover): proof_request_info = read_proof_req_data(request_for_proof) proof_exchange = aries_container_request_proof( - agent["agent"], proof_request_info, explicit_revoc_required=True + agent["agent"], + proof_request_info, + explicit_revoc_required=True, + is_anoncreds=agent["agent"].wallet_type == "askar-anoncreds", ) context.proof_request = proof_request_info diff --git a/demo/features/steps/0586-sign-transaction.py b/demo/features/steps/0586-sign-transaction.py index bf5a8a0c3c..f8ade72f98 100644 --- a/demo/features/steps/0586-sign-transaction.py +++ b/demo/features/steps/0586-sign-transaction.py @@ -593,14 +593,15 @@ def step_impl(context, agent_name): agent["agent"], "/issue-credential-2.0/records/" + cred_exchange["cred_ex_id"] ) context.cred_exchange = cred_exchange + cred_exchange_format = cred_exchange.get("indy") or cred_exchange.get("anoncreds") agent_container_POST( agent["agent"], endpoint, data={ - "cred_rev_id": cred_exchange["indy"]["cred_rev_id"], + "cred_rev_id": cred_exchange_format["cred_rev_id"], "publish": False, - "rev_reg_id": cred_exchange["indy"]["rev_reg_id"], + "rev_reg_id": cred_exchange_format["rev_reg_id"], "connection_id": cred_exchange["cred_ex_record"]["connection_id"], }, ) @@ -627,11 +628,13 @@ def step_impl(context, agent_name): context.cred_exchange = cred_exchange connection_id = agent["agent"].agent.connection_id + cred_exchange_format = cred_exchange.get("indy") or cred_exchange.get("anoncreds") + # revoke the credential if not is_anoncreds(agent): data = { - "rev_reg_id": cred_exchange["indy"]["rev_reg_id"], - "cred_rev_id": cred_exchange["indy"]["cred_rev_id"], + "rev_reg_id": cred_exchange_format["rev_reg_id"], + "cred_rev_id": cred_exchange_format["cred_rev_id"], "publish": False, "connection_id": cred_exchange["cred_ex_record"]["connection_id"], } @@ -642,9 +645,9 @@ def step_impl(context, agent_name): endpoint = "/revocation/revoke" else: data = { - "cred_rev_id": cred_exchange["indy"]["cred_rev_id"], + "cred_rev_id": cred_exchange_format["cred_rev_id"], "publish": False, - "rev_reg_id": cred_exchange["indy"]["rev_reg_id"], + "rev_reg_id": cred_exchange_format["rev_reg_id"], "connection_id": cred_exchange["cred_ex_record"]["connection_id"], "options": { "endorser_connection_id": connection_id, @@ -676,15 +679,17 @@ def step_impl(context, agent_name): else: endpoint = "/anoncreds/revocation/publish-revocations" + cred_exchange_format = context.cred_exchange.get("indy") or context.cred_exchange.get( + "anoncreds" + ) + # create rev_reg entry transaction created_rev_reg = agent_container_POST( agent["agent"], endpoint, data={ "rrid2crid": { - context.cred_exchange["indy"]["rev_reg_id"]: [ - context.cred_exchange["indy"]["cred_rev_id"] - ] + cred_exchange_format["rev_reg_id"]: [cred_exchange_format["cred_rev_id"]] } }, params={}, @@ -703,14 +708,15 @@ def step_impl(context, agent_name): agent = context.active_agents[agent_name] connection_id = agent["agent"].agent.connection_id + cred_exchange_format = context.cred_exchange.get("indy") or context.cred_exchange.get( + "anoncreds" + ) # create rev_reg entry transaction if not is_anoncreds(agent): data = { "rrid2crid": { - context.cred_exchange["indy"]["rev_reg_id"]: [ - context.cred_exchange["indy"]["cred_rev_id"] - ] + cred_exchange_format["rev_reg_id"]: [cred_exchange_format["cred_rev_id"]] } } params = { @@ -721,9 +727,7 @@ def step_impl(context, agent_name): else: data = { "rrid2crid": { - context.cred_exchange["indy"]["rev_reg_id"]: [ - context.cred_exchange["indy"]["cred_rev_id"] - ] + cred_exchange_format["rev_reg_id"]: [cred_exchange_format["cred_rev_id"]] }, "options": { "endorser_connection_id": connection_id, diff --git a/demo/features/upgrade.feature b/demo/features/upgrade.feature index 259c7a485a..557dd75646 100644 --- a/demo/features/upgrade.feature +++ b/demo/features/upgrade.feature @@ -19,10 +19,7 @@ Feature: ACA-Py Anoncreds Upgrade Then "Faber" has the proof verification fail Then "Bob" can verify the credential from "" was revoked And "" upgrades the wallet to anoncreds - And "Bob" has an issued credential from "" And "Bob" upgrades the wallet to anoncreds - And "Bob" has an issued credential from "" - When "Faber" sends a request for proof presentation to "Bob" Examples: | issuer | Acme_capabilities | Bob_capabilities | Schema_name | Credential_data | Proof_request | diff --git a/demo/runners/agent_container.py b/demo/runners/agent_container.py index c2ad39fe5f..61b07f4ef7 100644 --- a/demo/runners/agent_container.py +++ b/demo/runners/agent_container.py @@ -36,6 +36,8 @@ log_timer, ) +from .support.agent import CRED_FORMAT_ANONCREDS + CRED_PREVIEW_TYPE = "https://didcomm.org/issue-credential/2.0/credential-preview" SELF_ATTESTED = os.getenv("SELF_ATTESTED") TAILS_FILE_COUNT = int(os.getenv("TAILS_FILE_COUNT", 100)) @@ -272,16 +274,25 @@ async def handle_issue_credential_v2_0(self, message): elif state == "offer-received": log_status("#15 After receiving credential offer, send credential request") + + def _should_send_request_without_data(message): + """Formats that do not require credential request data.""" + cred_offer_by_format = message["by_format"].get("cred_offer") + + return ( + not message.get("by_format") + or cred_offer_by_format.get("anoncreds") + or cred_offer_by_format.get("indy") + or cred_offer_by_format.get("vc_di") + ) + # Should wait for a tiny bit for the delete tests await asyncio.sleep(0.2) if not message.get("by_format"): # this should not happen, something hinky when running in IDE... # this will work if using indy payloads self.log(f"No 'by_format' in message: {message}") - await self.admin_POST( - f"/issue-credential-2.0/records/{cred_ex_id}/send-request" - ) - elif message["by_format"]["cred_offer"].get("indy"): + elif _should_send_request_without_data(message): await self.admin_POST( f"/issue-credential-2.0/records/{cred_ex_id}/send-request" ) @@ -294,10 +305,6 @@ async def handle_issue_credential_v2_0(self, message): await self.admin_POST( f"/issue-credential-2.0/records/{cred_ex_id}/send-request", data ) - elif message["by_format"]["cred_offer"].get("vc_di"): - await self.admin_POST( - f"/issue-credential-2.0/records/{cred_ex_id}/send-request" - ) elif state == "done": pass @@ -327,6 +334,26 @@ async def handle_issue_credential_v2_0_indy(self, message): self.log(f"Revocation registry ID: {rev_reg_id}") self.log(f"Credential revocation ID: {cred_rev_id}") + async def handle_issue_credential_v2_0_anoncreds(self, message): + rev_reg_id = message.get("rev_reg_id") + cred_rev_id = message.get("cred_rev_id") + cred_id_stored = message.get("cred_id_stored") + + if cred_id_stored: + cred_id = message["cred_id_stored"] + log_status(f"#18.1 Stored credential {cred_id} in wallet") + cred = await self.admin_GET(f"/credential/{cred_id}") + log_json(cred, label="Credential details:") + self.log("credential_id", cred_id) + self.log("cred_def_id", cred["cred_def_id"]) + self.log("schema_id", cred["schema_id"]) + # track last successfully received credential + self.last_credential_received = cred + + if rev_reg_id and cred_rev_id: + self.log(f"Revocation registry ID: {rev_reg_id}") + self.log(f"Credential revocation ID: {cred_rev_id}") + async def handle_issue_credential_v2_0_vc_di(self, message): self.log(f"Handle VC_DI Credential: message = {message}") @@ -442,16 +469,18 @@ async def handle_present_proof_v2_0(self, message): # this should not happen, something hinky when running in IDE... self.log(f"No 'by_format' in message: {message}") else: - pres_request_indy = ( - message["by_format"].get("pres_request", {}).get("indy") - ) - pres_request_dif = message["by_format"].get("pres_request", {}).get("dif") + pres_request_by_format = message["by_format"].get("pres_request", {}) + pres_request = pres_request_by_format.get( + "indy" + ) or pres_request_by_format.get("anoncreds") + + pres_request_dif = pres_request_by_format.get("dif") request = {} - if not pres_request_dif and not pres_request_indy: + if not pres_request_dif and not pres_request: raise Exception("Invalid presentation request received") - if pres_request_indy: + if pres_request: # include self-attested attributes (not included in credentials) creds_by_reft = {} revealed = {} @@ -463,7 +492,6 @@ async def handle_present_proof_v2_0(self, message): creds = await self.admin_GET( f"/present-proof-2.0/records/{pres_ex_id}/credentials" ) - # print(">>> creds:", creds) if creds: # select only indy credentials creds = [x for x in creds if "cred_info" in x] @@ -484,7 +512,7 @@ async def handle_present_proof_v2_0(self, message): # submit the proof wit one unrevealed revealed attribute revealed_flag = False - for referent in pres_request_indy["requested_attributes"]: + for referent in pres_request["requested_attributes"]: if referent in creds_by_reft: revealed[referent] = { "cred_id": creds_by_reft[referent]["cred_info"][ @@ -496,7 +524,7 @@ async def handle_present_proof_v2_0(self, message): else: self_attested[referent] = "my self-attested value" - for referent in pres_request_indy["requested_predicates"]: + for referent in pres_request["requested_predicates"]: if referent in creds_by_reft: predicates[referent] = { "cred_id": creds_by_reft[referent]["cred_info"][ @@ -504,15 +532,15 @@ async def handle_present_proof_v2_0(self, message): ] } - log_status("#25 Generate the indy proof") - indy_request = { - "indy": { + log_status("#25 Generate the proof") + request = { + "indy" if "indy" in pres_request_by_format else "anoncreds": { "requested_predicates": predicates, "requested_attributes": revealed, "self_attested_attributes": self_attested, } } - request.update(indy_request) + request.update(request) except ClientError: pass @@ -779,7 +807,7 @@ def __init__( # endorsers and authors need public DIDs (assume cred_type is Indy) if endorser_role == "author" or endorser_role == "endorser": self.public_did = True - self.cred_type = CRED_FORMAT_INDY + # self.cred_type = CRED_FORMAT_INDY self.reuse_connections = reuse_connections self.multi_use_invitations = multi_use_invitations @@ -938,7 +966,7 @@ async def create_schema_and_cred_def( ): if not self.public_did: raise Exception("Can't create a schema/cred def without a public DID :-(") - if self.cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: + if self.cred_type in [CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: # need to redister schema and cred def on the ledger self.cred_def_id = await self.agent.create_schema_and_cred_def( schema_name, @@ -981,20 +1009,26 @@ async def issue_credential( self, cred_def_id: str, cred_attrs: list, + filter_type: str = "indy", ): log_status("#13 Issue credential offer to X") - if self.cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: + if self.cred_type in [CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: cred_preview = { "@type": CRED_PREVIEW_TYPE, "attributes": cred_attrs, } + if filter_type == "indy": + _filter = {"indy": {"cred_def_id": cred_def_id}} + else: + _filter = {"anoncreds": {"cred_def_id": cred_def_id}} + offer_request = { "connection_id": self.agent.connection_id, "comment": f"Offer on cred def id {cred_def_id}", "auto_remove": False, "credential_preview": cred_preview, - "filter": {"indy": {"cred_def_id": cred_def_id}}, + "filter": _filter, "trace": self.exchange_tracing, } cred_exchange = await self.agent.admin_POST( @@ -1041,11 +1075,13 @@ async def receive_credential( return matched - async def request_proof(self, proof_request, explicit_revoc_required: bool = False): + async def request_proof( + self, proof_request, explicit_revoc_required: bool = False, is_anoncreds=False + ): log_status("#20 Request proof of degree from alice") - if self.cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: - indy_proof_request = { + if self.cred_type in [CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: + proof_request = { "name": ( proof_request["name"] if "name" in proof_request else "Proof of stuff" ), @@ -1061,24 +1097,24 @@ async def request_proof(self, proof_request, explicit_revoc_required: bool = Fal # plug in revocation where requested in the supplied proof request non_revoked = {"to": int(time.time())} if "non_revoked" in proof_request: - indy_proof_request["non_revoked"] = non_revoked + proof_request["non_revoked"] = non_revoked non_revoked_supplied = True for attr in proof_request["requested_attributes"]: if "non_revoked" in proof_request["requested_attributes"][attr]: - indy_proof_request["requested_attributes"][attr][ - "non_revoked" - ] = non_revoked + proof_request["requested_attributes"][attr]["non_revoked"] = ( + non_revoked + ) non_revoked_supplied = True for pred in proof_request["requested_predicates"]: if "non_revoked" in proof_request["requested_predicates"][pred]: - indy_proof_request["requested_predicates"][pred][ - "non_revoked" - ] = non_revoked + proof_request["requested_predicates"][pred]["non_revoked"] = ( + non_revoked + ) non_revoked_supplied = True if not non_revoked_supplied and not explicit_revoc_required: # else just make it global - indy_proof_request["non_revoked"] = non_revoked + proof_request["non_revoked"] = non_revoked else: # make sure we are not leaking non-revoc requests @@ -1091,13 +1127,16 @@ async def request_proof(self, proof_request, explicit_revoc_required: bool = Fal if "non_revoked" in proof_request["requested_predicates"][pred]: del proof_request["requested_predicates"][pred]["non_revoked"] - log_status(f" >>> asking for proof for request: {indy_proof_request}") + log_status(f" >>> asking for proof for request: {proof_request}") + + if is_anoncreds: + presentation_request = {"anoncreds": proof_request} + else: + presentation_request = {"indy": proof_request} proof_request_web_request = { "connection_id": self.agent.connection_id, - "presentation_request": { - "indy": indy_proof_request, - }, + "presentation_request": presentation_request, "trace": self.exchange_tracing, } proof_exchange = await self.agent.admin_POST( @@ -1108,7 +1147,6 @@ async def request_proof(self, proof_request, explicit_revoc_required: bool = Fal elif self.cred_type == CRED_FORMAT_JSON_LD: # TODO create and send the json-ld proof request - pass return None else: @@ -1125,7 +1163,7 @@ async def verify_proof(self, proof_request): # log_status(f">>> last proof received: {self.agent.last_proof_received}") - if self.cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: + if self.cred_type in [CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: # return verified status return self.agent.last_proof_received["verified"] @@ -1514,12 +1552,14 @@ async def create_agent_with_args(args, ident: str = None, extra_args: list = Non aip = 20 if "cred_type" in args and args.cred_type not in [ + CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI, ]: public_did = None aip = 20 elif "cred_type" in args and args.cred_type in [ + CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI, ]: @@ -1528,6 +1568,12 @@ async def create_agent_with_args(args, ident: str = None, extra_args: list = Non public_did = args.public_did if "public_did" in args else None cred_type = args.cred_type if "cred_type" in args else None + + # Set anoncreds agent to use anoncreds credential format + wallet_type = arg_file_dict.get("wallet-type") or args.wallet_type + if wallet_type == "askar-anoncreds": + cred_type = CRED_FORMAT_ANONCREDS + log_msg( f"Initializing demo agent {agent_ident} with AIP {aip} and credential type {cred_type}" ) @@ -1564,7 +1610,7 @@ async def create_agent_with_args(args, ident: str = None, extra_args: list = Non mediation=args.mediation, cred_type=cred_type, use_did_exchange=(aip == 20) if ("aip" in args) else args.did_exchange, - wallet_type=arg_file_dict.get("wallet-type") or args.wallet_type, + wallet_type=wallet_type, public_did=public_did, seed="random" if public_did else None, arg_file=arg_file, diff --git a/demo/runners/faber.py b/demo/runners/faber.py index 5cecf47d37..00cc9a2e98 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -17,6 +17,7 @@ create_agent_with_args, ) from runners.support.agent import ( # noqa:E402 + CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_JSON_LD, CRED_FORMAT_VC_DI, @@ -111,7 +112,7 @@ def generate_credential_offer(self, aip, cred_type, cred_def_id, exchange_tracin return offer_request elif aip == 20: - if cred_type == CRED_FORMAT_INDY: + if cred_type == CRED_FORMAT_ANONCREDS or cred_type == CRED_FORMAT_INDY: self.cred_attrs[cred_def_id] = { "name": "Alice Smith", "date": "2018-05-28", @@ -127,12 +128,16 @@ def generate_credential_offer(self, aip, cred_type, cred_def_id, exchange_tracin for (n, v) in self.cred_attrs[cred_def_id].items() ], } + if cred_type == CRED_FORMAT_ANONCREDS: + _filter = {"anoncreds": {"cred_def_id": cred_def_id}} + else: + _filter = {"indy": {"cred_def_id": cred_def_id}} offer_request = { "connection_id": self.connection_id, "comment": f"Offer on cred def id {cred_def_id}", "auto_remove": False, "credential_preview": cred_preview, - "filter": {"indy": {"cred_def_id": cred_def_id}}, + "filter": _filter, "trace": exchange_tracing, } return offer_request @@ -249,7 +254,7 @@ def generate_proof_request_web_request( "restrictions": [{"schema_name": "degree schema"}], } ] - indy_proof_request = { + proof_request = { "name": "Proof of Education", "version": "1.0", "requested_attributes": { @@ -261,10 +266,10 @@ def generate_proof_request_web_request( } if revocation: - indy_proof_request["non_revoked"] = {"to": int(time.time())} + proof_request["non_revoked"] = {"to": int(time.time())} proof_request_web_request = { - "proof_request": indy_proof_request, + "proof_request": proof_request, "trace": exchange_tracing, } if not connectionless: @@ -272,7 +277,7 @@ def generate_proof_request_web_request( return proof_request_web_request elif aip == 20: - if cred_type == CRED_FORMAT_INDY: + if cred_type == CRED_FORMAT_ANONCREDS or cred_type == CRED_FORMAT_INDY: req_attrs = [ { "name": "name", @@ -312,7 +317,7 @@ def generate_proof_request_web_request( "restrictions": [{"schema_name": "degree schema"}], } ] - indy_proof_request = { + proof_request = { "name": "Proof of Education", "version": "1.0", "requested_attributes": { @@ -325,14 +330,19 @@ def generate_proof_request_web_request( } if revocation: - indy_proof_request["non_revoked"] = {"to": int(time.time())} + proof_request["non_revoked"] = {"to": int(time.time())} + if cred_type == CRED_FORMAT_ANONCREDS: + presentation_request = {"anoncreds": proof_request} + else: + presentation_request = {"indy": proof_request} proof_request_web_request = { - "presentation_request": {"indy": indy_proof_request}, + "presentation_request": presentation_request, "trace": exchange_tracing, } if not connectionless: proof_request_web_request["connection_id"] = self.connection_id + return proof_request_web_request elif cred_type == CRED_FORMAT_VC_DI: @@ -537,7 +547,11 @@ async def main(args): "birthdate_dateint", "timestamp", ] - if faber_agent.cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: + if faber_agent.cred_type in [ + CRED_FORMAT_ANONCREDS, + CRED_FORMAT_INDY, + CRED_FORMAT_VC_DI, + ]: faber_agent.public_did = True await faber_agent.initialize( the_agent=agent, @@ -569,6 +583,7 @@ async def main(args): exchange_tracing = False options = " (1) Issue Credential\n" if faber_agent.cred_type in [ + CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI, ]: @@ -664,12 +679,14 @@ async def main(args): elif option == "1a": new_cred_type = await prompt( - "Enter credential type ({}, {}): ".format( + "Enter credential type ({}, {}, {}): ".format( + CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI, ) ) if new_cred_type in [ + CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI, ]: @@ -689,7 +706,11 @@ async def main(args): ) elif faber_agent.aip == 20: - if faber_agent.cred_type == CRED_FORMAT_INDY: + if faber_agent.cred_type in [ + CRED_FORMAT_ANONCREDS, + CRED_FORMAT_INDY, + CRED_FORMAT_VC_DI, + ]: offer_request = faber_agent.agent.generate_credential_offer( faber_agent.aip, faber_agent.cred_type, @@ -705,14 +726,6 @@ async def main(args): exchange_tracing, ) - elif faber_agent.cred_type == CRED_FORMAT_VC_DI: - offer_request = faber_agent.agent.generate_credential_offer( - faber_agent.aip, - faber_agent.cred_type, - faber_agent.cred_def_id, - exchange_tracing, - ) - else: raise Exception( f"Error invalid credential type: {faber_agent.cred_type}" @@ -742,27 +755,12 @@ async def main(args): pass elif faber_agent.aip == 20: - if faber_agent.cred_type == CRED_FORMAT_INDY: - proof_request_web_request = ( - faber_agent.agent.generate_proof_request_web_request( - faber_agent.aip, - faber_agent.cred_type, - faber_agent.revocation, - exchange_tracing, - ) - ) - - elif faber_agent.cred_type == CRED_FORMAT_JSON_LD: - proof_request_web_request = ( - faber_agent.agent.generate_proof_request_web_request( - faber_agent.aip, - faber_agent.cred_type, - faber_agent.revocation, - exchange_tracing, - ) - ) - - elif faber_agent.cred_type == CRED_FORMAT_VC_DI: + if faber_agent.cred_type in [ + CRED_FORMAT_ANONCREDS, + CRED_FORMAT_INDY, + CRED_FORMAT_VC_DI, + CRED_FORMAT_JSON_LD, + ]: proof_request_web_request = ( faber_agent.agent.generate_proof_request_web_request( faber_agent.aip, @@ -771,7 +769,6 @@ async def main(args): exchange_tracing, ) ) - else: raise Exception( "Error invalid credential type:" + faber_agent.cred_type @@ -819,28 +816,12 @@ async def main(args): qr.print_ascii(invert=True) elif faber_agent.aip == 20: - if faber_agent.cred_type == CRED_FORMAT_INDY: - proof_request_web_request = ( - faber_agent.agent.generate_proof_request_web_request( - faber_agent.aip, - faber_agent.cred_type, - faber_agent.revocation, - exchange_tracing, - connectionless=True, - ) - ) - elif faber_agent.cred_type == CRED_FORMAT_JSON_LD: - proof_request_web_request = ( - faber_agent.agent.generate_proof_request_web_request( - faber_agent.aip, - faber_agent.cred_type, - faber_agent.revocation, - exchange_tracing, - connectionless=True, - ) - ) - - elif faber_agent.cred_type == CRED_FORMAT_VC_DI: + if faber_agent.cred_type in [ + CRED_FORMAT_ANONCREDS, + CRED_FORMAT_INDY, + CRED_FORMAT_VC_DI, + CRED_FORMAT_JSON_LD, + ]: proof_request_web_request = ( faber_agent.agent.generate_proof_request_web_request( faber_agent.aip, diff --git a/demo/runners/support/agent.py b/demo/runners/support/agent.py index 2905ad4912..5d1e10ccd6 100644 --- a/demo/runners/support/agent.py +++ b/demo/runners/support/agent.py @@ -70,6 +70,7 @@ WALLET_TYPE_ASKAR = "askar" WALLET_TYPE_ANONCREDS = "askar-anoncreds" +CRED_FORMAT_ANONCREDS = "anoncreds" CRED_FORMAT_INDY = "indy" CRED_FORMAT_JSON_LD = "json-ld" CRED_FORMAT_VC_DI = "vc_di" @@ -672,7 +673,7 @@ async def register_did( role: str = "TRUST_ANCHOR", cred_type: str = CRED_FORMAT_INDY, ): - if cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: + if cred_type in [CRED_FORMAT_ANONCREDS, CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]: # if registering a did for issuing indy credentials, publish the did on the ledger self.log(f"Registering {self.ident} ...") if not ledger_url: diff --git a/scenarios/examples/anoncreds_issuance_and_revocation/docker-compose.yml b/scenarios/examples/anoncreds_issuance_and_revocation/docker-compose.yml index 247a0b7daf..6e0a757fbd 100644 --- a/scenarios/examples/anoncreds_issuance_and_revocation/docker-compose.yml +++ b/scenarios/examples/anoncreds_issuance_and_revocation/docker-compose.yml @@ -1,22 +1,26 @@ services: - alice: + agency: image: acapy-test ports: - "3001:3001" command: > start - --label Alice + --label Agency --inbound-transport http 0.0.0.0 3000 --outbound-transport http - --endpoint http://alice:3000 + --endpoint http://agency:3000 --admin 0.0.0.0 3001 --admin-insecure-mode --tails-server-base-url http://tails:6543 --genesis-url http://test.bcovrin.vonx.io/genesis - --wallet-type askar-anoncreds - --wallet-name alice + --wallet-type askar + --wallet-name agency --wallet-key insecure --auto-provision + --multitenant + --multitenant-admin + --jwt-secret insecure + --multitenancy-config wallet_type=single-wallet-askar key_derivation_method=RAW --log-level info --debug-webhooks --notify-revocation @@ -30,22 +34,50 @@ tails: condition: service_started - bob: + holder_anoncreds: image: acapy-test ports: - "3002:3001" command: > start - --label Bob + --label Holder-Anoncreds --inbound-transport http 0.0.0.0 3000 --outbound-transport http - --endpoint http://bob:3000 + --endpoint http://holder_anoncreds:3000 --admin 0.0.0.0 3001 --admin-insecure-mode --tails-server-base-url http://tails:6543 --genesis-url http://test.bcovrin.vonx.io/genesis --wallet-type askar-anoncreds - --wallet-name bob + --wallet-name holder_anoncreds + --wallet-key insecure + --auto-provision + --log-level info + --debug-webhooks + --monitor-revocation-notification + healthcheck: + test: curl -s -o /dev/null -w '%{http_code}' "http://localhost:3001/status/live" | grep "200" > /dev/null + start_period: 30s + interval: 7s + timeout: 5s + retries: 5 + + holder_indy: + image: acapy-test + ports: + - "3003:3001" + command: > + start + --label Holder-Indy + --inbound-transport http 0.0.0.0 3000 + --outbound-transport http + --endpoint http://holder_indy:3000 + --admin 0.0.0.0 3001 + --admin-insecure-mode + --tails-server-base-url http://tails:6543 + --genesis-url http://test.bcovrin.vonx.io/genesis + --wallet-type askar + --wallet-name holder_indy --wallet-key insecure --auto-provision --log-level info @@ -63,15 +95,18 @@ build: context: ../.. environment: - - ALICE=http://alice:3001 - - BOB=http://bob:3001 + - AGENCY=http://agency:3001 + - HOLDER_ANONCREDS=http://holder_anoncreds:3001 + - HOLDER_INDY=http://holder_indy:3001 volumes: - ./example.py:/usr/src/app/example.py:ro,z command: python -m example depends_on: - alice: + agency: + condition: service_healthy + holder_anoncreds: condition: service_healthy - bob: + holder_indy: condition: service_healthy tails: diff --git a/scenarios/examples/anoncreds_issuance_and_revocation/example.py b/scenarios/examples/anoncreds_issuance_and_revocation/example.py index 6d7d1a1bd2..05a68c395a 100644 --- a/scenarios/examples/anoncreds_issuance_and_revocation/example.py +++ b/scenarios/examples/anoncreds_issuance_and_revocation/example.py @@ -7,23 +7,30 @@ import json from dataclasses import dataclass from os import getenv -from secrets import token_hex +from secrets import randbelow, token_hex +from typing import Any, Dict, List, Mapping, Optional, Tuple, Type, Union +from uuid import uuid4 from acapy_controller import Controller -from acapy_controller.controller import Minimal +from acapy_controller.controller import Minimal, MinType from acapy_controller.logging import logging_to_stdout -from acapy_controller.models import V20PresExRecord, V20PresExRecordList +from acapy_controller.models import ( + CreateWalletResponse, + V20CredExRecordIndy, + V20PresExRecord, + V20PresExRecordList, +) from acapy_controller.protocols import ( DIDResult, didexchange, - indy_issue_credential_v2, - indy_present_proof_v2, + indy_anoncred_credential_artifacts, params, ) from aiohttp import ClientSession -ALICE = getenv("ALICE", "http://alice:3001") -BOB = getenv("BOB", "http://bob:3001") +AGENCY = getenv("AGENCY", "http://agency:3001") +HOLDER_ANONCREDS = getenv("HOLDER_ANONCREDS", "http://holder_anoncreds:3001") +HOLDER_INDY = getenv("HOLDER_INDY", "http://holder_indy:3001") def summary(presentation: V20PresExRecord) -> str: @@ -33,7 +40,9 @@ def summary(presentation: V20PresExRecord) -> str: { "state": presentation.state, "verified": presentation.verified, - "presentation_request": request.dict(by_alias=True) if request else None, + "presentation_request": request.model_dump(by_alias=True) + if request + else None, }, indent=2, sort_keys=True, @@ -41,32 +50,395 @@ def summary(presentation: V20PresExRecord) -> str: @dataclass -class SchemaResult(Minimal): +class SchemaResultAnoncreds(Minimal): """Schema result.""" schema_state: dict @dataclass -class CredDefResult(Minimal): +class CredDefResultAnoncreds(Minimal): """Credential definition result.""" credential_definition_state: dict +@dataclass +class V20CredExRecord(Minimal): + """V2.0 credential exchange record.""" + + state: str + cred_ex_id: str + connection_id: str + thread_id: str + + +@dataclass +class V20CredExRecordFormat(Minimal): + """V2.0 credential exchange record anoncreds.""" + + rev_reg_id: Optional[str] = None + cred_rev_id: Optional[str] = None + + +@dataclass +class V20CredExRecordDetail(Minimal): + """V2.0 credential exchange record detail.""" + + cred_ex_record: V20CredExRecord + details: Optional[V20CredExRecordFormat] = None + + +@dataclass +class ProofRequest(Minimal): + """Proof request.""" + + requested_attributes: Dict[str, Any] + requested_predicates: Dict[str, Any] + + +@dataclass +class PresSpec(Minimal): + """Presentation specification.""" + + requested_attributes: Dict[str, Any] + requested_predicates: Dict[str, Any] + self_attested_attributes: Dict[str, Any] + + +@dataclass +class CredInfo(Minimal): + """Credential information.""" + + referent: str + attrs: Dict[str, Any] + + +@dataclass +class CredPrecis(Minimal): + """Credential precis.""" + + cred_info: CredInfo + presentation_referents: List[str] + + @classmethod + def deserialize(cls: Type[MinType], value: Mapping[str, Any]) -> MinType: + """Deserialize the credential precis.""" + value = dict(value) + if cred_info := value.get("cred_info"): + value["cred_info"] = CredInfo.deserialize(cred_info) + return super().deserialize(value) + + +@dataclass +class Settings(Minimal): + """Settings information.""" + + +def auto_select_credentials_for_presentation_request( + presentation_request: Union[ProofRequest, dict], + relevant_creds: List[CredPrecis], +) -> PresSpec: + """Select credentials to use for presentation automatically.""" + if isinstance(presentation_request, dict): + presentation_request = ProofRequest.deserialize(presentation_request) + + requested_attributes = {} + for pres_referrent in presentation_request.requested_attributes.keys(): + for cred_precis in relevant_creds: + if pres_referrent in cred_precis.presentation_referents: + requested_attributes[pres_referrent] = { + "cred_id": cred_precis.cred_info.referent, + "revealed": True, + } + requested_predicates = {} + for pres_referrent in presentation_request.requested_predicates.keys(): + for cred_precis in relevant_creds: + if pres_referrent in cred_precis.presentation_referents: + requested_predicates[pres_referrent] = { + "cred_id": cred_precis.cred_info.referent, + } + + return PresSpec.deserialize( + { + "requested_attributes": requested_attributes, + "requested_predicates": requested_predicates, + "self_attested_attributes": {}, + } + ) + + +async def issue_credential_v2( + issuer: Controller, + holder: Controller, + issuer_connection_id: str, + holder_connection_id: str, + cred_def_id: str, + attributes: Mapping[str, str], +) -> Tuple[V20CredExRecordDetail, V20CredExRecordDetail]: + """Issue an credential using issue-credential/2.0. + + Issuer and holder should already be connected. + """ + + is_issuer_anoncreds = (await issuer.get("/settings", response=Settings)).get( + "wallet.type" + ) == "askar-anoncreds" + is_holder_anoncreds = (await holder.get("/settings", response=Settings)).get( + "wallet.type" + ) == "askar-anoncreds" + + if is_issuer_anoncreds: + _filter = {"anoncreds": {"cred_def_id": cred_def_id}} + else: + _filter = {"indy": {"cred_def_id": cred_def_id}} + issuer_cred_ex = await issuer.post( + "/issue-credential-2.0/send-offer", + json={ + "auto_issue": False, + "auto_remove": False, + "comment": "Credential from minimal example", + "trace": False, + "connection_id": issuer_connection_id, + "filter": _filter, + "credential_preview": { + "type": "issue-credential-2.0/2.0/credential-preview", # pyright: ignore + "attributes": [ + { + "mime_type": None, + "name": name, + "value": value, + } + for name, value in attributes.items() + ], + }, + }, + response=V20CredExRecord, + ) + issuer_cred_ex_id = issuer_cred_ex.cred_ex_id + + holder_cred_ex = await holder.event_with_values( + topic="issue_credential_v2_0", + event_type=V20CredExRecord, + connection_id=holder_connection_id, + state="offer-received", + ) + holder_cred_ex_id = holder_cred_ex.cred_ex_id + + await holder.post( + f"/issue-credential-2.0/records/{holder_cred_ex_id}/send-request", + response=V20CredExRecord, + ) + + await issuer.event_with_values( + topic="issue_credential_v2_0", + cred_ex_id=issuer_cred_ex_id, + state="request-received", + ) + + await issuer.post( + f"/issue-credential-2.0/records/{issuer_cred_ex_id}/issue", + json={}, + response=V20CredExRecordDetail, + ) + + await holder.event_with_values( + topic="issue_credential_v2_0", + cred_ex_id=holder_cred_ex_id, + state="credential-received", + ) + + await holder.post( + f"/issue-credential-2.0/records/{holder_cred_ex_id}/store", + json={}, + response=V20CredExRecordDetail, + ) + issuer_cred_ex = await issuer.event_with_values( + topic="issue_credential_v2_0", + event_type=V20CredExRecord, + cred_ex_id=issuer_cred_ex_id, + state="done", + ) + issuer_indy_record = await issuer.event_with_values( + topic="issue_credential_v2_0_anoncreds" + if is_issuer_anoncreds + else "issue_credential_v2_0_indy", + event_type=V20CredExRecordIndy, + ) + + holder_cred_ex = await holder.event_with_values( + topic="issue_credential_v2_0", + event_type=V20CredExRecord, + cred_ex_id=holder_cred_ex_id, + state="done", + ) + holder_indy_record = await holder.event_with_values( + topic="issue_credential_v2_0_anoncreds" + if is_holder_anoncreds + else "issue_credential_v2_0_indy", + event_type=V20CredExRecordIndy, + ) + + return ( + V20CredExRecordDetail(cred_ex_record=issuer_cred_ex, details=issuer_indy_record), + V20CredExRecordDetail( + cred_ex_record=holder_cred_ex, + details=holder_indy_record, + ), + ) + + +async def present_proof_v2( + holder: Controller, + verifier: Controller, + holder_connection_id: str, + verifier_connection_id: str, + *, + name: Optional[str] = None, + version: Optional[str] = None, + comment: Optional[str] = None, + requested_attributes: Optional[List[Mapping[str, Any]]] = None, + requested_predicates: Optional[List[Mapping[str, Any]]] = None, + non_revoked: Optional[Mapping[str, int]] = None, +): + """Present an credential using present proof v2.""" + + is_verifier_anoncreds = (await verifier.get("/settings", response=Settings)).get( + "wallet.type" + ) == "askar-anoncreds" + + attrs = { + "name": name or "proof", + "version": version or "0.1.0", + "nonce": str(randbelow(10**10)), + "requested_attributes": { + str(uuid4()): attr for attr in requested_attributes or [] + }, + "requested_predicates": { + str(uuid4()): pred for pred in requested_predicates or [] + }, + "non_revoked": (non_revoked if non_revoked else None), + } + + if is_verifier_anoncreds: + presentation_request = { + "anoncreds": attrs, + } + else: + presentation_request = { + "indy": attrs, + } + verifier_pres_ex = await verifier.post( + "/present-proof-2.0/send-request", + json={ + "auto_verify": False, + "comment": comment or "Presentation request from minimal", + "connection_id": verifier_connection_id, + "presentation_request": presentation_request, + "trace": False, + }, + response=V20PresExRecord, + ) + verifier_pres_ex_id = verifier_pres_ex.pres_ex_id + + holder_pres_ex = await holder.event_with_values( + topic="present_proof_v2_0", + event_type=V20PresExRecord, + connection_id=holder_connection_id, + state="request-received", + ) + assert holder_pres_ex.pres_request + holder_pres_ex_id = holder_pres_ex.pres_ex_id + + relevant_creds = await holder.get( + f"/present-proof-2.0/records/{holder_pres_ex_id}/credentials", + response=List[CredPrecis], + ) + assert holder_pres_ex.by_format.pres_request + proof_request = holder_pres_ex.by_format.pres_request.get( + "anoncreds" + ) or holder_pres_ex.by_format.pres_request.get("indy") + pres_spec = auto_select_credentials_for_presentation_request( + proof_request, relevant_creds + ) + if is_verifier_anoncreds: + proof = {"anoncreds": pres_spec.serialize()} + else: + proof = {"indy": pres_spec.serialize()} + await holder.post( + f"/present-proof-2.0/records/{holder_pres_ex_id}/send-presentation", + json=proof, + response=V20PresExRecord, + ) + + await verifier.event_with_values( + topic="present_proof_v2_0", + event_type=V20PresExRecord, + pres_ex_id=verifier_pres_ex_id, + state="presentation-received", + ) + await verifier.post( + f"/present-proof-2.0/records/{verifier_pres_ex_id}/verify-presentation", + json={}, + response=V20PresExRecord, + ) + verifier_pres_ex = await verifier.event_with_values( + topic="present_proof_v2_0", + event_type=V20PresExRecord, + pres_ex_id=verifier_pres_ex_id, + state="done", + ) + + holder_pres_ex = await holder.event_with_values( + topic="present_proof_v2_0", + event_type=V20PresExRecord, + pres_ex_id=holder_pres_ex_id, + state="done", + ) + + return holder_pres_ex, verifier_pres_ex + + async def main(): """Test Controller protocols.""" - async with Controller(base_url=ALICE) as alice, Controller(base_url=BOB) as bob: + issuer_name = "issuer" + token_hex(8) + async with Controller(base_url=AGENCY) as agency: + issuer = await agency.post( + "/multitenancy/wallet", + json={ + "label": issuer_name, + "wallet_name": issuer_name, + "wallet_type": "askar", + }, + response=CreateWalletResponse, + ) + + async with Controller( + base_url=AGENCY, + wallet_id=issuer.wallet_id, + subwallet_token=issuer.token, + ) as issuer, Controller(base_url=HOLDER_ANONCREDS) as holder_anoncreds, Controller( + base_url=HOLDER_INDY + ) as holder_indy: + """ + This section of the test script demonstrates the issuance, presentation and + revocation of a credential where both the issuer is not anoncreds capable + (wallet type askar) and the holder is anoncreds capable + (wallet type askar-anoncreds). + """ + # Connecting - alice_conn, bob_conn = await didexchange(alice, bob) + issuer_conn_with_anoncreds_holder, holder_anoncreds_conn = await didexchange( + issuer, holder_anoncreds + ) # Issuance prep - config = (await alice.get("/status/config"))["config"] + config = (await issuer.get("/status/config"))["config"] genesis_url = config.get("ledger.genesis_url") - public_did = (await alice.get("/wallet/did/public", response=DIDResult)).result + public_did = (await issuer.get("/wallet/did/public", response=DIDResult)).result if not public_did: public_did = ( - await alice.post( + await issuer.post( "/wallet/did/create", json={"method": "sov", "options": {"key_type": "ed25519"}}, response=DIDResult, @@ -87,21 +459,154 @@ async def main(): ) as resp: assert resp.ok - await alice.post("/wallet/did/public", params=params(did=public_did.did)) + await issuer.post("/wallet/did/public", params=params(did=public_did.did)) + + _, cred_def = await indy_anoncred_credential_artifacts( + issuer, + ["firstname", "lastname"], + support_revocation=True, + ) + + # Issue a credential + issuer_cred_ex, _ = await issue_credential_v2( + issuer, + holder_anoncreds, + issuer_conn_with_anoncreds_holder.connection_id, + holder_anoncreds_conn.connection_id, + cred_def.credential_definition_id, + {"firstname": "Anoncreds", "lastname": "Holder"}, + ) + + # Present the the credential's attributes + await present_proof_v2( + holder_anoncreds, + issuer, + holder_anoncreds_conn.connection_id, + issuer_conn_with_anoncreds_holder.connection_id, + requested_attributes=[{"name": "firstname"}], + ) + + # Revoke credential + await issuer.post( + url="/revocation/revoke", + json={ + "connection_id": issuer_conn_with_anoncreds_holder.connection_id, + "rev_reg_id": issuer_cred_ex.details.rev_reg_id, + "cred_rev_id": issuer_cred_ex.details.cred_rev_id, + "publish": True, + "notify": True, + "notify_version": "v1_0", + }, + ) + + await holder_anoncreds.record(topic="revocation-notification") + + """ + This section of the test script demonstrates the issuance, presentation and + revocation of a credential where the issuer and holder are not anoncreds + capable. Both are askar wallet type. + """ + + # Connecting + issuer_conn_with_indy_holder, holder_indy_conn = await didexchange( + issuer, holder_indy + ) + + # Issue a credential + issuer_cred_ex, _ = await issue_credential_v2( + issuer, + holder_indy, + issuer_conn_with_indy_holder.connection_id, + holder_indy_conn.connection_id, + cred_def.credential_definition_id, + {"firstname": "Indy", "lastname": "Holder"}, + ) + + # Present the the credential's attributes + await present_proof_v2( + holder_indy, + issuer, + holder_indy_conn.connection_id, + issuer_conn_with_indy_holder.connection_id, + requested_attributes=[{"name": "firstname"}], + ) + # Query presentations + presentations = await issuer.get( + "/present-proof-2.0/records", + response=V20PresExRecordList, + ) + + # Presentation summary + for _, pres in enumerate(presentations.results): + print(summary(pres)) + + # Revoke credential + await issuer.post( + url="/revocation/revoke", + json={ + "connection_id": issuer_conn_with_indy_holder.connection_id, + "rev_reg_id": issuer_cred_ex.details.rev_reg_id, + "cred_rev_id": issuer_cred_ex.details.cred_rev_id, + "publish": True, + "notify": True, + "notify_version": "v1_0", + }, + ) + + await holder_indy.record(topic="revocation-notification") - schema = await alice.post( + """ + Upgrade the issuer tenant to anoncreds capable wallet type. When upgrading a + tenant the agent doesn't require a restart. That is why the test is done + with multitenancy + """ + await issuer.post( + "/anoncreds/wallet/upgrade", + params={ + "wallet_name": issuer_name, + }, + ) + + # Wait for the upgrade to complete + await asyncio.sleep(2) + + """ + Do issuance and presentation again after the upgrade. This time the issuer is + an anoncreds capable wallet (wallet type askar-anoncreds). + """ + # Presentation for anoncreds capable holder on existing credential + await present_proof_v2( + holder_anoncreds, + issuer, + holder_anoncreds_conn.connection_id, + issuer_conn_with_anoncreds_holder.connection_id, + requested_attributes=[{"name": "firstname"}], + ) + + # Presentation for indy capable holder on existing credential + await present_proof_v2( + holder_indy, + issuer, + holder_indy_conn.connection_id, + issuer_conn_with_indy_holder.connection_id, + requested_attributes=[{"name": "firstname"}], + ) + + # Create a new schema and cred def with different attributes on new + # anoncreds endpoints + schema = await issuer.post( "/anoncreds/schema", json={ "schema": { "name": "anoncreds-test-" + token_hex(8), "version": "1.0", - "attrNames": ["firstname", "lastname"], + "attrNames": ["middlename"], "issuerId": public_did.did, } }, - response=SchemaResult, + response=SchemaResultAnoncreds, ) - cred_def = await alice.post( + cred_def = await issuer.post( "/anoncreds/credential-definition", json={ "credential_definition": { @@ -109,77 +614,73 @@ async def main(): "schemaId": schema.schema_state["schema_id"], "tag": token_hex(8), }, - "options": { - "revocation_registry_size": 2000, - "support_revocation": True, - }, + "options": {"support_revocation": True, "revocation_registry_size": 10}, }, - response=CredDefResult, + response=CredDefResultAnoncreds, ) - # Issue a credential - alice_cred_ex, _ = await indy_issue_credential_v2( - alice, - bob, - alice_conn.connection_id, - bob_conn.connection_id, + # Issue a new credential to anoncreds holder + issuer_cred_ex, _ = await issue_credential_v2( + issuer, + holder_anoncreds, + issuer_conn_with_anoncreds_holder.connection_id, + holder_anoncreds_conn.connection_id, cred_def.credential_definition_state["credential_definition_id"], - {"firstname": "Bob", "lastname": "Builder"}, + {"middlename": "Anoncreds"}, ) - - # Present the the credential's attributes - await indy_present_proof_v2( - bob, - alice, - bob_conn.connection_id, - alice_conn.connection_id, - requested_attributes=[{"name": "firstname"}], + # Presentation for anoncreds capable holder + await present_proof_v2( + holder_anoncreds, + issuer, + holder_anoncreds_conn.connection_id, + issuer_conn_with_anoncreds_holder.connection_id, + requested_attributes=[{"name": "middlename"}], ) - # Revoke credential - await alice.post( + await issuer.post( url="/anoncreds/revocation/revoke", json={ - "connection_id": alice_conn.connection_id, - "rev_reg_id": alice_cred_ex.indy.rev_reg_id, - "cred_rev_id": alice_cred_ex.indy.cred_rev_id, + "connection_id": issuer_conn_with_anoncreds_holder.connection_id, + "rev_reg_id": issuer_cred_ex.details.rev_reg_id, + "cred_rev_id": issuer_cred_ex.details.cred_rev_id, "publish": True, "notify": True, "notify_version": "v1_0", }, ) + await holder_anoncreds.record(topic="revocation-notification") - await bob.record(topic="revocation-notification") - - # Request proof, no interval - await indy_present_proof_v2( - bob, - alice, - bob_conn.connection_id, - alice_conn.connection_id, - requested_attributes=[ - { - "name": "firstname", - "restrictions": [ - { - "cred_def_id": cred_def.credential_definition_state[ - "credential_definition_id" - ] - } - ], - } - ], + # Issue a new credential to indy holder + issuer_cred_ex, _ = await issue_credential_v2( + issuer, + holder_indy, + issuer_conn_with_indy_holder.connection_id, + holder_indy_conn.connection_id, + cred_def.credential_definition_state["credential_definition_id"], + {"middlename": "Indy"}, ) - - # Query presentations - presentations = await alice.get( - "/present-proof-2.0/records", - response=V20PresExRecordList, + # Presentation for indy holder + await present_proof_v2( + holder_indy, + issuer, + holder_indy_conn.connection_id, + issuer_conn_with_indy_holder.connection_id, + requested_attributes=[{"name": "middlename"}], + ) + # Revoke credential + await issuer.post( + url="/anoncreds/revocation/revoke", + json={ + "connection_id": issuer_conn_with_indy_holder.connection_id, + "rev_reg_id": issuer_cred_ex.details.rev_reg_id, + "cred_rev_id": issuer_cred_ex.details.cred_rev_id, + "publish": True, + "notify": True, + "notify_version": "v1_0", + }, ) - # Presentation summary - for i, pres in enumerate(presentations.results): - print(summary(pres)) + await holder_indy.record(topic="revocation-notification") if __name__ == "__main__": From ddfcfdc17683bf65a95c80b5896b3deb8ffbb06f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emiliano=20Su=C3=B1=C3=A9?= Date: Wed, 20 Nov 2024 14:18:52 -0800 Subject: [PATCH 59/72] Fix handling of base_wallet_routes startup parameter in auth decorator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emiliano Suñé --- acapy_agent/admin/decorators/auth.py | 29 ++++++++++++++++++++++++++++ acapy_agent/admin/server.py | 25 +----------------------- acapy_agent/admin/tests/test_auth.py | 24 +++++++++++++++++++++++ 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/acapy_agent/admin/decorators/auth.py b/acapy_agent/admin/decorators/auth.py index 818f297d40..6d673a19f9 100644 --- a/acapy_agent/admin/decorators/auth.py +++ b/acapy_agent/admin/decorators/auth.py @@ -1,6 +1,8 @@ """Authentication decorators for the admin API.""" import functools +import re +from typing import Optional, Pattern, Sequence, cast from aiohttp import web @@ -48,6 +50,8 @@ def tenant_authentication(handler): - check for a valid bearer token in the Autorization header if running in multi-tenant mode - check for a valid x-api-key header if running in single-tenant mode + - check if the base wallet has access to teh requested path if running + in multi-tenant mode """ @functools.wraps(handler) @@ -61,11 +65,15 @@ async def tenant_auth(request): ) insecure_mode = bool(profile.settings.get("admin.admin_insecure_mode")) multitenant_enabled = profile.settings.get("multitenant.enabled") + base_wallet_allowed_route = _base_wallet_route_access( + profile.settings.get("multitenant.base_wallet_routes"), request.path + ) # CORS fix: allow OPTIONS method access to paths without a token if ( (multitenant_enabled and authorization_header) or (not multitenant_enabled and valid_key) + or (multitenant_enabled and valid_key and base_wallet_allowed_route) or insecure_mode or request.method == "OPTIONS" ): @@ -78,3 +86,24 @@ async def tenant_auth(request): ) return tenant_auth + + +def _base_wallet_route_access(additional_routes: str, request_path: str) -> bool: + """Check if request path matches additional routes.""" + additional_routes_pattern = _build_additional_routes_pattern(additional_routes) + return _matches_additional_routes(additional_routes_pattern, request_path) + + +def _build_additional_routes_pattern(pattern_string: str) -> Optional[Pattern]: + """Build pattern from string.""" + base_wallet_routes = cast(Sequence[str], pattern_string) + if base_wallet_routes: + return re.compile("^(?:" + "|".join(base_wallet_routes) + ")") + return None + + +def _matches_additional_routes(pattern: Pattern, path: str) -> bool: + """Matches request path to provided pattern.""" + if pattern and path: + return bool(pattern.match(path)) + return False diff --git a/acapy_agent/admin/server.py b/acapy_agent/admin/server.py index 84650ed11b..111d2f2a52 100644 --- a/acapy_agent/admin/server.py +++ b/acapy_agent/admin/server.py @@ -5,7 +5,7 @@ import re import warnings import weakref -from typing import Callable, Coroutine, Optional, Pattern, Sequence, cast +from typing import Callable, Coroutine, Optional import aiohttp_cors import jwt @@ -280,29 +280,6 @@ def __init__( self.websocket_queues = {} self.site = None self.multitenant_manager = context.inject_or(BaseMultitenantManager) - self._additional_route_pattern: Optional[Pattern] = None - - @property - def additional_routes_pattern(self) -> Optional[Pattern]: - """Pattern for configured additional routes to permit base wallet to access.""" - if self._additional_route_pattern: - return self._additional_route_pattern - - base_wallet_routes = self.context.settings.get("multitenant.base_wallet_routes") - base_wallet_routes = cast(Sequence[str], base_wallet_routes) - if base_wallet_routes: - self._additional_route_pattern = re.compile( - "^(?:" + "|".join(base_wallet_routes) + ")" - ) - return None - - def _matches_additional_routes(self, path: str) -> bool: - """Path matches additional_routes_pattern.""" - pattern = self.additional_routes_pattern - if pattern: - return bool(pattern.match(path)) - - return False async def make_application(self) -> web.Application: """Get the aiohttp application instance.""" diff --git a/acapy_agent/admin/tests/test_auth.py b/acapy_agent/admin/tests/test_auth.py index 1ebd0cd171..7be0549866 100644 --- a/acapy_agent/admin/tests/test_auth.py +++ b/acapy_agent/admin/tests/test_auth.py @@ -133,3 +133,27 @@ async def test_multi_tenant_valid_auth_header(self): decor_func = tenant_authentication(self.decorated_handler) await decor_func(self.request) self.decorated_handler.assert_called_once_with(self.request) + + async def test_base_wallet_additional_route_allowed(self): + self.profile.settings["multitenant.base_wallet_routes"] = "/extra-route" + self.request = mock.MagicMock( + __getitem__=lambda _, k: self.request_dict[k], + headers={"x-api-key": "admin_api_key"}, + method="POST", + path="/extra-route", + ) + decor_func = tenant_authentication(self.decorated_handler) + await decor_func(self.request) + self.decorated_handler.assert_called_once_with(self.request) + + async def test_base_wallet_additional_route_denied(self): + self.profile.settings["multitenant.base_wallet_routes"] = "/wrong-extra-route" + self.request = mock.MagicMock( + __getitem__=lambda _, k: self.request_dict[k], + headers={"x-api-key": "admin_api_key"}, + method="POST", + path="/extra-route", + ) + decor_func = tenant_authentication(self.decorated_handler) + with self.assertRaises(web.HTTPUnauthorized): + await decor_func(self.request) From 84a9f3304dde4dfecee93732847820a5405b3f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emiliano=20Su=C3=B1=C3=A9?= Date: Wed, 20 Nov 2024 19:19:25 -0800 Subject: [PATCH 60/72] Restore --base-wallet-extra-routes argument functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emiliano Suñé --- acapy_agent/admin/decorators/auth.py | 11 +++++------ acapy_agent/admin/tests/test_auth.py | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/acapy_agent/admin/decorators/auth.py b/acapy_agent/admin/decorators/auth.py index 6d673a19f9..6e9f1597a8 100644 --- a/acapy_agent/admin/decorators/auth.py +++ b/acapy_agent/admin/decorators/auth.py @@ -2,7 +2,7 @@ import functools import re -from typing import Optional, Pattern, Sequence, cast +from typing import Optional, Pattern from aiohttp import web @@ -95,11 +95,10 @@ def _base_wallet_route_access(additional_routes: str, request_path: str) -> bool def _build_additional_routes_pattern(pattern_string: str) -> Optional[Pattern]: - """Build pattern from string.""" - base_wallet_routes = cast(Sequence[str], pattern_string) - if base_wallet_routes: - return re.compile("^(?:" + "|".join(base_wallet_routes) + ")") - return None + """Build pattern from space delimited list of paths.""" + # create array and add word boundary to avoid false positives + paths = pattern_string.split(" ") + return re.compile("^((?:)" + "|".join(paths) + ")$") def _matches_additional_routes(pattern: Pattern, path: str) -> bool: diff --git a/acapy_agent/admin/tests/test_auth.py b/acapy_agent/admin/tests/test_auth.py index 7be0549866..73680a1b00 100644 --- a/acapy_agent/admin/tests/test_auth.py +++ b/acapy_agent/admin/tests/test_auth.py @@ -147,12 +147,12 @@ async def test_base_wallet_additional_route_allowed(self): self.decorated_handler.assert_called_once_with(self.request) async def test_base_wallet_additional_route_denied(self): - self.profile.settings["multitenant.base_wallet_routes"] = "/wrong-extra-route" + self.profile.settings["multitenant.base_wallet_routes"] = "/extra-route" self.request = mock.MagicMock( __getitem__=lambda _, k: self.request_dict[k], headers={"x-api-key": "admin_api_key"}, method="POST", - path="/extra-route", + path="/extra-route-wrong", ) decor_func = tenant_authentication(self.decorated_handler) with self.assertRaises(web.HTTPUnauthorized): From 0257d78af7b23abeb77a7ee68ef06e6710c76f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emiliano=20Su=C3=B1=C3=A9?= Date: Thu, 21 Nov 2024 10:42:15 -0800 Subject: [PATCH 61/72] Correctly handle null value for --base-wallet-routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emiliano Suñé --- acapy_agent/admin/decorators/auth.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/acapy_agent/admin/decorators/auth.py b/acapy_agent/admin/decorators/auth.py index 6e9f1597a8..9c12d7f75c 100644 --- a/acapy_agent/admin/decorators/auth.py +++ b/acapy_agent/admin/decorators/auth.py @@ -97,8 +97,10 @@ def _base_wallet_route_access(additional_routes: str, request_path: str) -> bool def _build_additional_routes_pattern(pattern_string: str) -> Optional[Pattern]: """Build pattern from space delimited list of paths.""" # create array and add word boundary to avoid false positives - paths = pattern_string.split(" ") - return re.compile("^((?:)" + "|".join(paths) + ")$") + if pattern_string: + paths = pattern_string.split(" ") + return re.compile("^((?:)" + "|".join(paths) + ")$") + return None def _matches_additional_routes(pattern: Pattern, path: str) -> bool: From 88be79091ffbbe8ad06534953ba991d36fc50e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emiliano=20Su=C3=B1=C3=A9?= Date: Thu, 21 Nov 2024 11:34:00 -0800 Subject: [PATCH 62/72] Fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emiliano Suñé --- acapy_agent/admin/decorators/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acapy_agent/admin/decorators/auth.py b/acapy_agent/admin/decorators/auth.py index 9c12d7f75c..3d1f209893 100644 --- a/acapy_agent/admin/decorators/auth.py +++ b/acapy_agent/admin/decorators/auth.py @@ -50,7 +50,7 @@ def tenant_authentication(handler): - check for a valid bearer token in the Autorization header if running in multi-tenant mode - check for a valid x-api-key header if running in single-tenant mode - - check if the base wallet has access to teh requested path if running + - check if the base wallet has access to the requested path if running in multi-tenant mode """ From 2d4212ae2cc88ef885d61b0eae28997b4e2a7dd5 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:27:04 -0800 Subject: [PATCH 63/72] Fix subwallet anoncreds upgrade check (#3345) Signed-off-by: jamshale --- acapy_agent/core/conductor.py | 14 +------------- acapy_agent/wallet/anoncreds_upgrade.py | 1 + 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index d9db66ad7a..9935b6f745 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -856,19 +856,7 @@ async def check_for_valid_wallet_type(self, profile): async def check_for_wallet_upgrades_in_progress(self): """Check for upgrade and upgrade if needed.""" - - # We need to use the correct multitenant manager for single vs multiple wallets - # here because the multitenant provider hasn't been initialized yet. - manager_type = self.context.settings.get_value( - "multitenant.wallet_type", default="basic" - ).lower() - - manager_class = MultitenantManagerProvider.MANAGER_TYPES.get( - manager_type, manager_type - ) - - multitenant_mgr = self.context.inject_or(manager_class) - if multitenant_mgr: + if self.context.settings.get_value("multitenant.enabled"): subwallet_profiles = await get_subwallet_profiles_from_storage( self.root_profile ) diff --git a/acapy_agent/wallet/anoncreds_upgrade.py b/acapy_agent/wallet/anoncreds_upgrade.py index ce944c75d7..4261acf0eb 100644 --- a/acapy_agent/wallet/anoncreds_upgrade.py +++ b/acapy_agent/wallet/anoncreds_upgrade.py @@ -699,6 +699,7 @@ async def check_upgrade_completion_loop(profile: Profile, is_subwallet=False): UpgradeInProgressSingleton().remove_wallet(profile.name) if is_subwallet: await upgrade_subwallet(profile) + await finish_upgrade(profile) LOGGER.info( f"""Upgrade of subwallet {profile.settings.get('wallet.name')} has completed. Profile is now askar-anoncreds""" # noqa: E501 ) From 799cd646477264580e082a4ce315bff4093e9290 Mon Sep 17 00:00:00 2001 From: jamshale <31809382+jamshale@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:16:34 -0800 Subject: [PATCH 64/72] Fix/universal resolver (#3354) * Update universal resolver response handling Signed-off-by: jamshale * Update universal resolver unit test Signed-off-by: jamshale * Add reverse compatibility handling Signed-off-by: jamshale --------- Signed-off-by: jamshale --- .../resolver/default/tests/test_universal.py | 24 +++++++++++++++++++ acapy_agent/resolver/default/universal.py | 16 +++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/acapy_agent/resolver/default/tests/test_universal.py b/acapy_agent/resolver/default/tests/test_universal.py index 36b2cc73db..c516ac7068 100644 --- a/acapy_agent/resolver/default/tests/test_universal.py +++ b/acapy_agent/resolver/default/tests/test_universal.py @@ -119,6 +119,7 @@ async def test_fetch_resolver_props(mock_client_session: MockClientSession): @pytest.mark.asyncio async def test_get_supported_did_regex(): + # Old response format props = {"example": {"http": {"pattern": "match a test string"}}} with mock.patch.object( UniversalResolver, @@ -128,6 +129,29 @@ async def test_get_supported_did_regex(): pattern = await UniversalResolver()._get_supported_did_regex() assert pattern.fullmatch("match a test string") + # Example response from dev universal resolver 1.0 + props = { + "^(did:sov:(?:(?:\\w[-\\w]*(?::\\w[-\\w]*)*):)?(?:[1-9A-HJ-NP-Za-km-z]{21,22}))$": { + "libIndyPath": "", + "openParallel": "false", + "poolVersions": "_;2;test;2;builder;2;danube;2;idunion;2;idunion:test;2;indicio;2;indicio:test;2;indicio:demo;2;nxd;2;findy:test;2;bcovrin;2;bcovrin:test;2;bcovrin:dev;2;candy;2;candy:test;2;candy:dev;2", + "submitterDidSeeds": "_;_;test;_;builder;_;danube;_;idunion;_;idunion:test;_;indicio;_;indicio:test;_;indicio:demo;_;nxd;_;findy:test;_;bcovrin;_;bcovrin:test;_;bcovrin:dev;_;candy;_;candy:test;_;candy:dev;_", + "http": { + "resolveUri": "http://driver-did-sov:8080/1.0/identifiers/", + "propertiesUri": "http://driver-did-sov:8080/1.0/properties", + }, + "walletNames": "_;w1;test;w2;builder;w3;danube;w4;idunion;w5;idunion:test;w6;indicio;w7;indicio:test;w8;indicio:demo;w9;nxd;w11;findy:test;w12;bcovrin;w13;bcovrin:test;w14;bcovrin:dev;w15;candy;w16;candy:test;w17;candy:dev;w18", + "poolConfigs": "_;./sovrin/_.txn;test;./sovrin/test.txn;builder;./sovrin/builder.txn;danube;./sovrin/danube.txn;idunion;./sovrin/idunion.txn;idunion:test;./sovrin/idunion-test.txn;indicio;./sovrin/indicio.txn;indicio:test;./sovrin/indicio-test.txn;indicio:demo;./sovrin/indicio-demo.txn;nxd;./sovrin/nxd.txn;bcovrin:test;./sovrin/bcovrin-test.txn;candy;./sovrin/candy.txn;candy:test;./sovrin/candy-test.txn;candy:dev;./sovrin/candy-dev.txn", + } + } + with mock.patch.object( + UniversalResolver, + "_fetch_resolver_props", + mock.CoroutineMock(return_value=props), + ): + pattern = await UniversalResolver()._get_supported_did_regex() + assert pattern.match("did:sov:WRfXPg8dantKVubE3HX8pw") + def test_compile_supported_did_regex(): patterns = ["one", "two", "three"] diff --git a/acapy_agent/resolver/default/universal.py b/acapy_agent/resolver/default/universal.py index 4d359a9a6e..8d4b1eb1d8 100644 --- a/acapy_agent/resolver/default/universal.py +++ b/acapy_agent/resolver/default/universal.py @@ -110,8 +110,16 @@ async def _fetch_resolver_props(self) -> dict: "Failed to retrieve resolver properties: " + await resp.text() ) - async def _get_supported_did_regex(self) -> Pattern: + async def _get_supported_did_regex(self): props = await self._fetch_resolver_props() - return _compile_supported_did_regex( - driver["http"]["pattern"] for driver in props.values() - ) + + def _get_patterns(): + """Handle both old and new properties responses.""" + patterns = list(props.values())[0].get("http", {}).get("pattern") + if not patterns: + return props.keys() + else: + return [driver["http"]["pattern"] for driver in props.values()] + + patterns = _get_patterns() + return _compile_supported_did_regex(patterns) From b0a1e675bc04c2db6bd8a538a96081ae87fbaced Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 10:44:57 -0800 Subject: [PATCH 65/72] chore(deps-dev): Bump ruff from 0.7.4 to 0.8.0 (#3348) Bumps [ruff](https://github.com/astral-sh/ruff) from 0.7.4 to 0.8.0. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.7.4...0.8.0) --- updated-dependencies: - dependency-name: ruff dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jamshale <31809382+jamshale@users.noreply.github.com> --- poetry.lock | 44 +++++++++++++++++++++++--------------------- pyproject.toml | 2 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/poetry.lock b/poetry.lock index 465055db55..bd70d367bf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiofiles" @@ -1325,6 +1325,8 @@ optional = false python-versions = "*" files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, + {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, + {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -2598,29 +2600,29 @@ test = ["hypothesis (==5.19.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "ruff" -version = "0.7.4" +version = "0.8.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478"}, - {file = "ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63"}, - {file = "ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a"}, - {file = "ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac"}, - {file = "ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6"}, - {file = "ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f"}, - {file = "ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2"}, + {file = "ruff-0.8.0-py3-none-linux_armv6l.whl", hash = "sha256:fcb1bf2cc6706adae9d79c8d86478677e3bbd4ced796ccad106fd4776d395fea"}, + {file = "ruff-0.8.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:295bb4c02d58ff2ef4378a1870c20af30723013f441c9d1637a008baaf928c8b"}, + {file = "ruff-0.8.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7b1f1c76b47c18fa92ee78b60d2d20d7e866c55ee603e7d19c1e991fad933a9a"}, + {file = "ruff-0.8.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb0d4f250a7711b67ad513fde67e8870109e5ce590a801c3722580fe98c33a99"}, + {file = "ruff-0.8.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e55cce9aa93c5d0d4e3937e47b169035c7e91c8655b0974e61bb79cf398d49c"}, + {file = "ruff-0.8.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f4cd64916d8e732ce6b87f3f5296a8942d285bbbc161acee7fe561134af64f9"}, + {file = "ruff-0.8.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c5c1466be2a2ebdf7c5450dd5d980cc87c8ba6976fb82582fea18823da6fa362"}, + {file = "ruff-0.8.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2dabfd05b96b7b8f2da00d53c514eea842bff83e41e1cceb08ae1966254a51df"}, + {file = "ruff-0.8.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:facebdfe5a5af6b1588a1d26d170635ead6892d0e314477e80256ef4a8470cf3"}, + {file = "ruff-0.8.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87a8e86bae0dbd749c815211ca11e3a7bd559b9710746c559ed63106d382bd9c"}, + {file = "ruff-0.8.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:85e654f0ded7befe2d61eeaf3d3b1e4ef3894469cd664ffa85006c7720f1e4a2"}, + {file = "ruff-0.8.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:83a55679c4cb449fa527b8497cadf54f076603cc36779b2170b24f704171ce70"}, + {file = "ruff-0.8.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:812e2052121634cf13cd6fddf0c1871d0ead1aad40a1a258753c04c18bb71bbd"}, + {file = "ruff-0.8.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:780d5d8523c04202184405e60c98d7595bdb498c3c6abba3b6d4cdf2ca2af426"}, + {file = "ruff-0.8.0-py3-none-win32.whl", hash = "sha256:5fdb6efecc3eb60bba5819679466471fd7d13c53487df7248d6e27146e985468"}, + {file = "ruff-0.8.0-py3-none-win_amd64.whl", hash = "sha256:582891c57b96228d146725975fbb942e1f30a0c4ba19722e692ca3eb25cc9b4f"}, + {file = "ruff-0.8.0-py3-none-win_arm64.whl", hash = "sha256:ba93e6294e9a737cd726b74b09a6972e36bb511f9a102f1d9a7e1ce94dd206a6"}, + {file = "ruff-0.8.0.tar.gz", hash = "sha256:a7ccfe6331bf8c8dad715753e157457faf7351c2b69f62f32c165c2dbcbacd44"}, ] [[package]] @@ -3139,4 +3141,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "543d20028efad5a9d798071ba86e9d1ab39b202fe1afaa27f8f4c7f656f1d7cc" +content-hash = "bbb6160407926b8aceeceeb69268118c018e71a0857eefa9e3567b09d4088f15" diff --git a/pyproject.toml b/pyproject.toml index 7de97f37b3..557927eca2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,7 @@ canonicaljson = "^2.0.0" [tool.poetry.group.dev.dependencies] pre-commit = "~3.8.0" # Sync with version in .pre-commit-config.yaml -ruff = "0.7.4" +ruff = "0.8.0" sphinx = "^5.3.0" sphinx-rtd-theme = ">=0.4.3" From b5e79fb1c948a5873c57f7a3e04ef208640add46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 10:51:30 -0800 Subject: [PATCH 66/72] chore(deps): Bump mkdocs-material from 9.5.44 to 9.5.46 (#3352) Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.5.44 to 9.5.46. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.5.44...9.5.46) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mkdocs-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs-requirements.txt b/mkdocs-requirements.txt index eb1ee40600..a6d710f6af 100644 --- a/mkdocs-requirements.txt +++ b/mkdocs-requirements.txt @@ -1,3 +1,3 @@ -mkdocs-material==9.5.44 +mkdocs-material==9.5.46 mike==2.1.3 From 1613ed02c281ae5d6ac60673c7e4bdc65789202d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 11:18:27 -0800 Subject: [PATCH 67/72] chore(deps): Bump uuid-utils from 0.9.0 to 0.10.0 (#3351) Bumps [uuid-utils](https://github.com/aminalaee/uuid-utils) from 0.9.0 to 0.10.0. - [Release notes](https://github.com/aminalaee/uuid-utils/releases) - [Commits](https://github.com/aminalaee/uuid-utils/compare/0.9.0...0.10.0) --- updated-dependencies: - dependency-name: uuid-utils dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 109 ++++++++++++++----------------------------------- pyproject.toml | 2 +- 2 files changed, 31 insertions(+), 80 deletions(-) diff --git a/poetry.lock b/poetry.lock index bd70d367bf..1c0f343a8a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2901,87 +2901,38 @@ files = [ [[package]] name = "uuid-utils" -version = "0.9.0" +version = "0.10.0" description = "Drop-in replacement for Python UUID in Rust" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "uuid_utils-0.9.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:28da15c275ef06a759efe0fcba7c58eab8ae2217f7a7f66289dee6ae332605a0"}, - {file = "uuid_utils-0.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:81144165068e84a1ac8b92f23bfc961e5b5dbb89ddcff70c5e7d096ae07a439c"}, - {file = "uuid_utils-0.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:362695ed7756b1b89d9a2dd193fe2523ca1d4a31235606f7cb516a322789ffc4"}, - {file = "uuid_utils-0.9.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36cb70e29f5749b554ae06f1a88926c9b47d5b48004b6903fb7ea47e8b398080"}, - {file = "uuid_utils-0.9.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa39a95eb67e2b98a61d4e64ddf622ee902fe9142b579921ab3e9027472f5080"}, - {file = "uuid_utils-0.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9b7029044d40f66366cebb6a94ecb04d8c0a745029561552d527ac52dc0deb9"}, - {file = "uuid_utils-0.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c883c6f815d2af344dab585d7b16a77410fcb1f6c097e6ad0384bd12cd84e16e"}, - {file = "uuid_utils-0.9.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:be5f83e9002a43aac868fa9cbc73f28cfb0b4e8b14f5a449fef04fea31bf2904"}, - {file = "uuid_utils-0.9.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8f84b0fd38df8a211230b8bbd02d5e7e631f1d35c1ba67efb895f80c7d9215aa"}, - {file = "uuid_utils-0.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:89cc342b061d8e3f669b8aaeb8d9e2973407c93aaa675dc6a59e985feda2805c"}, - {file = "uuid_utils-0.9.0-cp310-none-win32.whl", hash = "sha256:3d5554f44aeab9706770169316897f79089b51a061800684b7f29bccf663ad0f"}, - {file = "uuid_utils-0.9.0-cp310-none-win_amd64.whl", hash = "sha256:db35df169f17617129cc070e3a8fba00598ee55adcbe22c79b2c2f306eeb3b9e"}, - {file = "uuid_utils-0.9.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:cdb7224fb8b1f18edcd4357f83fcbe33b9f82ac392095e5d9e0e05336d65d587"}, - {file = "uuid_utils-0.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5312449ea5427a94edab3aebf2cff8f99a3112f273dd9d5919e332bc4e6a031f"}, - {file = "uuid_utils-0.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6837677217b3d0aa375f8aa7b89935c3ebf2ee5e1667be50b2090741684baa"}, - {file = "uuid_utils-0.9.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:402e522f62ceb8344f579e37f9a25c9274d484675afd71ad725ddd61ced7cd36"}, - {file = "uuid_utils-0.9.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e24a27724b2289d66d75358ffecf698ae36816458897cfdec972e6ede1ead328"}, - {file = "uuid_utils-0.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db04420c0b1a99f3160ddc90ba52986484ce8304b54586ea161133f755a4605b"}, - {file = "uuid_utils-0.9.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:152f3c1a0634558e329b64ff4a9592ee83b722e3fdc214f648f851fa14163c36"}, - {file = "uuid_utils-0.9.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5710b6ca95966f80125f48dad9e3d70ef99f48dd892bec3cb38673d087a7d71a"}, - {file = "uuid_utils-0.9.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3b9b9cf0cc544ef552c955bc2caaecf5e38cc8ed65e23f208b0dcdb6d37719e"}, - {file = "uuid_utils-0.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6d715b6321d4728a1aa0d5e26a338c97aaba2bf337f3ef9804ef5027f07de61d"}, - {file = "uuid_utils-0.9.0-cp311-none-win32.whl", hash = "sha256:3b61b0543404c99f7f23fb556b69090bc58358e8bd9d570381722221281f3706"}, - {file = "uuid_utils-0.9.0-cp311-none-win_amd64.whl", hash = "sha256:b4bdd9e80c92b1f253e66392e1d6ad0ec4926d5c7e2de3d852ee6fed1939f58b"}, - {file = "uuid_utils-0.9.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9cfcfb222f62612bea58bdec32b6842d9636fca53ca4579f88c1b620b1c4cbf7"}, - {file = "uuid_utils-0.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7253039ecfa534b3177b3225764cede9c6dae5db572e17d8582dd7cc5b3af484"}, - {file = "uuid_utils-0.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fb6e792ae1e3a7bf9d357f87dcf628923d0881f1d13a9cba826b848ca1774b1"}, - {file = "uuid_utils-0.9.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fbea3bb9ad319de7f69d6a60b6921acaa97d577aaeceb247b1ff4a8a92b3aa6a"}, - {file = "uuid_utils-0.9.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09043b3f48e20d631c7a81030be8c4f6ea9a6d44cccda8cbbdc1ad18da301c89"}, - {file = "uuid_utils-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9ba2681f5f177f800e40f5a0f09ed03c49f4290a245e4273d21cb48a7e88969"}, - {file = "uuid_utils-0.9.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:866811473f3d9dc38c02dd08e076e333b9e4d41ce952353941b49d0724d2327b"}, - {file = "uuid_utils-0.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:14aa9917ef11bd0ee1648237dddbf33aa0459e609ebe2f9202ffb259ca80f763"}, - {file = "uuid_utils-0.9.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:22cae83bc486a6c12b38239eb0546f2f81c81c34fcf833f84c2c7cd0cab1ad8f"}, - {file = "uuid_utils-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9513399045169435563c284caba0f1802748b02f27c95769426b7a00ed246e1"}, - {file = "uuid_utils-0.9.0-cp312-none-win_amd64.whl", hash = "sha256:284e6d24ba659d003bd47fcfc404d374c7807983407d4d61f26c80a3b7f4cb41"}, - {file = "uuid_utils-0.9.0-cp38-cp38-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:fd3d09c53d5a96c78c77211786fa25bbdbe031566b927383c10ab81a27c7e431"}, - {file = "uuid_utils-0.9.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:2b052d01176d2d1afa476ebe158eae052e265c92110d987d5801f0c3c1c8852a"}, - {file = "uuid_utils-0.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85e636a9603dc04e15b8305129619b2b45843f883e58355c91dc6cc22d51dde8"}, - {file = "uuid_utils-0.9.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37d2f9ec3a99caf29531fe257b7906f8a5946a3ee7000c744d73e5187a2542a1"}, - {file = "uuid_utils-0.9.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ace932d10a83141d22c42287a0c707cfa41522ecb797f17e63820f09688c6d7"}, - {file = "uuid_utils-0.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:843ec54337233d5f99a99b156ba5be5659f5ea193db8287035bf85d6a6a00c58"}, - {file = "uuid_utils-0.9.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f16a60ef4ddf9fe16fcd4793f83932d2b5198af6873d0a0478acfe0bd19d8e2f"}, - {file = "uuid_utils-0.9.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:901da31d61f78ec8df96741326541ae7af156a2628ca82ccf2806bcee257de1a"}, - {file = "uuid_utils-0.9.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:fad20ba28a11f2b33f06b2d7e0e77be73a8c3a41de833a123c6d93025d463b4b"}, - {file = "uuid_utils-0.9.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c5c30716a0dcffd1a7a66853f5a8372a276d454510f48fc7e4c39c13212bb1f6"}, - {file = "uuid_utils-0.9.0-cp38-none-win32.whl", hash = "sha256:2912c9a810e74cb3abaebd0fdfa5b1f202cf60a8f0fec9cc76117dab6c42cb77"}, - {file = "uuid_utils-0.9.0-cp38-none-win_amd64.whl", hash = "sha256:b55bcffc260356c84a09ac3a391e2442ad4df0beaaf71670d4e8ffd8b7328e75"}, - {file = "uuid_utils-0.9.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:08aec826a8ed4d3baab29d144ad634091e5accabcb88dfa0a834b9ba9e74930f"}, - {file = "uuid_utils-0.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e7de8fcf3d22e299582ab61c67390abdf37cc7d5b330066c3f792a082167c419"}, - {file = "uuid_utils-0.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8de8da71bc5a6a527952648357acca8d6d1717bbbc044304c5a9cf53eb06568c"}, - {file = "uuid_utils-0.9.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ce3ef96aa6ba760e1d0481ed076fe9e8f0386e27c7039bc6ffa377c98979fae7"}, - {file = "uuid_utils-0.9.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69dd8c0d622e4e40b1b993a2e452bbed21127b97f8e4a3fdbde6e5f556253265"}, - {file = "uuid_utils-0.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4600d5dcd9d0759be4bc580daf6d521da99a825a25db3d492abcbb12f6dc98f6"}, - {file = "uuid_utils-0.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:067d5f36ccc70896c76a9dafc8220a942db0e42ab58b84c43208e0ff84c1bdf0"}, - {file = "uuid_utils-0.9.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7a23d20f08636899a1b24394a12a2c469262af56d5279dbac1c6b14b059e5d4b"}, - {file = "uuid_utils-0.9.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6a2cbc5da89f0e701d2b80df0e6b30da16a0adcd2883da3d3e1f7aac1f046c1c"}, - {file = "uuid_utils-0.9.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bbf93bdd3c8a3e3b2b2f82ad4dfafcd2aaecc1d6ec924fd5da2b712ab324ee51"}, - {file = "uuid_utils-0.9.0-cp39-none-win32.whl", hash = "sha256:9d9b3ba5be11a017c568e904eac76f6cd6f82f956ca65ffbaa73ee8d7cdbe13b"}, - {file = "uuid_utils-0.9.0-cp39-none-win_amd64.whl", hash = "sha256:b3e494547cfef124f0c51831a303bfc0278e3c33b9ab9d9db90d94728d9871c2"}, - {file = "uuid_utils-0.9.0-pp38-pypy38_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:98c7c7b414b405b547c9bc1f972513b3a0bfb3dca248c89c623ab60efdd36ad8"}, - {file = "uuid_utils-0.9.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7b75241666cae4bc5786e6c68e862ccf4e15b2f98c81e47a6b0a85c907b7b6fa"}, - {file = "uuid_utils-0.9.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf6b43723a2d4af21c07fec98385a97e2023a808fd6eaf4296a163bffca76cf5"}, - {file = "uuid_utils-0.9.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4c260bb9a9fdd484cadc437cdb26ad07d66c8049a365c4ef49c9f09d7ed9ac2e"}, - {file = "uuid_utils-0.9.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4605c6326a7914d1b59c548f0ae4ef119619fe09c3ab4f07d99f3fbec39d470"}, - {file = "uuid_utils-0.9.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d498673249826ce7c47aa481709a5dd647bbff764fb64370bc691c7e43c7a2a1"}, - {file = "uuid_utils-0.9.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a37c48cba2f4eb6182a3857d045aa1420fa9878bfd268f6855fce7293a006677"}, - {file = "uuid_utils-0.9.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:eeb9c56d401e4a422ae7fd818ef1376bda384ae0bed86e339c9a256c6b10d252"}, - {file = "uuid_utils-0.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:33dd97e9c59891fbfb4e4a11596c42cc3d10774b843daaf75316d036a0a07799"}, - {file = "uuid_utils-0.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5e67fc3c6def9d62de4caf19529bd8044e821eb2f5c39821cfd011940f96394"}, - {file = "uuid_utils-0.9.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:241ab8ddb76ef8d4294c09cd6045dd62a1aa46acf8ff0a017796a54a530a87ae"}, - {file = "uuid_utils-0.9.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a9a16d2af4b4ad59d4cef7f43ba33644353b12769fafabf6e1663aa230cca38"}, - {file = "uuid_utils-0.9.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:897a167659d30a8431a094533bcb58d2b16005f7456408bd40f3e5872e1b2f46"}, - {file = "uuid_utils-0.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b4f56ab5ce19697552df9689c24c742054e8fd8e2ef8c26f9b8393f6d7ae893"}, - {file = "uuid_utils-0.9.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b219d9341de117e2e608f3fe08e31480ad60fb6128f8fffd2151ba88e53508c"}, - {file = "uuid_utils-0.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b5c08de8a94181c0ba209a8b8275993499f424b57958bea6c39739311526fd18"}, - {file = "uuid_utils-0.9.0.tar.gz", hash = "sha256:239f45b7e71d0ea61e3a4957aa4b8f3b49bfb009cf768d11c3f464787dbb737f"}, + {file = "uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d5a4508feefec62456cd6a41bcdde458d56827d908f226803b886d22a3d5e63"}, + {file = "uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dbefc2b9113f9dfe56bdae58301a2b3c53792221410d422826f3d1e3e6555fe7"}, + {file = "uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffc49c33edf87d1ec8112a9b43e4cf55326877716f929c165a2cc307d31c73d5"}, + {file = "uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0636b6208f69d5a4e629707ad2a89a04dfa8d1023e1999181f6830646ca048a1"}, + {file = "uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc06452856b724df9dedfc161c3582199547da54aeb81915ec2ed54f92d19b0"}, + {file = "uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:263b2589111c61decdd74a762e8f850c9e4386fb78d2cf7cb4dfc537054cda1b"}, + {file = "uuid_utils-0.10.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a558db48b7096de6b4d2d2210d82bba8586a6d55f99106b03bb7d01dc5c5bcd6"}, + {file = "uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:807465067f3c892514230326ac71a79b28a8dfe2c88ecd2d5675fc844f3c76b5"}, + {file = "uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:57423d4a2b9d7b916de6dbd75ba85465a28f9578a89a97f7d3e098d9aa4e5d4a"}, + {file = "uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:76d8d660f18ff6b767e319b1b5f927350cd92eafa4831d7ef5b57fdd1d91f974"}, + {file = "uuid_utils-0.10.0-cp39-abi3-win32.whl", hash = "sha256:6c11a71489338837db0b902b75e1ba7618d5d29f05fde4f68b3f909177dbc226"}, + {file = "uuid_utils-0.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:11c55ae64f6c0a7a0c741deae8ca2a4eaa11e9c09dbb7bec2099635696034cf7"}, + {file = "uuid_utils-0.10.0-pp310-pypy310_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:acea543dfc7b87df749e3e814c54ac739a82ff5e3800d25bd25a3e00599e1554"}, + {file = "uuid_utils-0.10.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0767eefa7b1e96f06cfa9b95758d286240c01bbf19e9d8f1b6043cdbe76cc639"}, + {file = "uuid_utils-0.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973fe4bb5258fd2ccb144d8b40c2d3158f16cc856a20527f8b40d14b2ae1dee9"}, + {file = "uuid_utils-0.10.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:71b8505b67a0d77d0fbd765d8463094a8f447677125da7647bec7ea0b99406f0"}, + {file = "uuid_utils-0.10.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6bdcb1211bb61476cbef12a87101fa48243e20ed82b2bd324c816b1b5826bd5e"}, + {file = "uuid_utils-0.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c5247f1df040aae71ea313819b563debe69bca7086a2cc6a3ac0eaddd3dadac"}, + {file = "uuid_utils-0.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a50bd29ef89660b93aa07ffa95ac691a0e12832375030569a8bd5c9272f3b8e6"}, + {file = "uuid_utils-0.10.0-pp39-pypy39_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a778cd9d8f995b94bba6e51f3ebee5b338fd834b0c4ecc8f932bd23e29db3e19"}, + {file = "uuid_utils-0.10.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d3d5b5c5ed66ff923961b9ebb902232cd67f6a7ec6b6f7a58e05e00ff44e3c7f"}, + {file = "uuid_utils-0.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:789ed6335225326c66f5d6162649bed978105a85f232be7811387c395c226801"}, + {file = "uuid_utils-0.10.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:05d1aa7b944b719eb1ee472435ae5444a3f8a00eb6350e3b1d1217d738477d33"}, + {file = "uuid_utils-0.10.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa8d8559c2d25d6ac87e0adeee601d2c91ec40b357ab780bcf79061cc23324e6"}, + {file = "uuid_utils-0.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0badcbfe3c72b5b30d59c2b12f120923127abd95a0d2aa64ddc1234e495abc2"}, + {file = "uuid_utils-0.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a7c1c494012335113748815156c5b6234c59b0fe0d3a8eede1b1a46f7e25a69"}, + {file = "uuid_utils-0.10.0.tar.gz", hash = "sha256:5db0e1890e8f008657ffe6ded4d9459af724ab114cfe82af1557c87545301539"}, ] [[package]] @@ -3141,4 +3092,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "bbb6160407926b8aceeceeb69268118c018e71a0857eefa9e3567b09d4088f15" +content-hash = "0ad79fb5601c4fea9a3e7d4f978e0b0085a76b49f7934a1814e04922c2029d80" diff --git a/pyproject.toml b/pyproject.toml index 557927eca2..5ab3ec2d4a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ requests = "~2.32.3" rlp = "4.0.1" unflatten = "~0.2" sd-jwt = "^0.10.3" -uuid_utils = "^0.9.0" +uuid_utils = "^0.10.0" # did libraries did-peer-2 = "^0.1.2" From b8283d74262859311cd520df29739a6d44d8e736 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:59:05 -0800 Subject: [PATCH 68/72] chore(deps-dev): Bump debugpy from 1.8.8 to 1.8.9 (#3350) Bumps [debugpy](https://github.com/microsoft/debugpy) from 1.8.8 to 1.8.9. - [Release notes](https://github.com/microsoft/debugpy/releases) - [Commits](https://github.com/microsoft/debugpy/compare/v1.8.8...v1.8.9) --- updated-dependencies: - dependency-name: debugpy dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 56 +++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1c0f343a8a..4265229219 100644 --- a/poetry.lock +++ b/poetry.lock @@ -812,37 +812,37 @@ cython = ["cython"] [[package]] name = "debugpy" -version = "1.8.8" +version = "1.8.9" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.8-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:e59b1607c51b71545cb3496876544f7186a7a27c00b436a62f285603cc68d1c6"}, - {file = "debugpy-1.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6531d952b565b7cb2fbd1ef5df3d333cf160b44f37547a4e7cf73666aca5d8d"}, - {file = "debugpy-1.8.8-cp310-cp310-win32.whl", hash = "sha256:b01f4a5e5c5fb1d34f4ccba99a20ed01eabc45a4684f4948b5db17a319dfb23f"}, - {file = "debugpy-1.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:535f4fb1c024ddca5913bb0eb17880c8f24ba28aa2c225059db145ee557035e9"}, - {file = "debugpy-1.8.8-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:c399023146e40ae373753a58d1be0a98bf6397fadc737b97ad612886b53df318"}, - {file = "debugpy-1.8.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09cc7b162586ea2171eea055985da2702b0723f6f907a423c9b2da5996ad67ba"}, - {file = "debugpy-1.8.8-cp311-cp311-win32.whl", hash = "sha256:eea8821d998ebeb02f0625dd0d76839ddde8cbf8152ebbe289dd7acf2cdc6b98"}, - {file = "debugpy-1.8.8-cp311-cp311-win_amd64.whl", hash = "sha256:d4483836da2a533f4b1454dffc9f668096ac0433de855f0c22cdce8c9f7e10c4"}, - {file = "debugpy-1.8.8-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:0cc94186340be87b9ac5a707184ec8f36547fb66636d1029ff4f1cc020e53996"}, - {file = "debugpy-1.8.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64674e95916e53c2e9540a056e5f489e0ad4872645399d778f7c598eacb7b7f9"}, - {file = "debugpy-1.8.8-cp312-cp312-win32.whl", hash = "sha256:5c6e885dbf12015aed73770f29dec7023cb310d0dc2ba8bfbeb5c8e43f80edc9"}, - {file = "debugpy-1.8.8-cp312-cp312-win_amd64.whl", hash = "sha256:19ffbd84e757a6ca0113574d1bf5a2298b3947320a3e9d7d8dc3377f02d9f864"}, - {file = "debugpy-1.8.8-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:705cd123a773d184860ed8dae99becd879dfec361098edbefb5fc0d3683eb804"}, - {file = "debugpy-1.8.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890fd16803f50aa9cb1a9b9b25b5ec321656dd6b78157c74283de241993d086f"}, - {file = "debugpy-1.8.8-cp313-cp313-win32.whl", hash = "sha256:90244598214bbe704aa47556ec591d2f9869ff9e042e301a2859c57106649add"}, - {file = "debugpy-1.8.8-cp313-cp313-win_amd64.whl", hash = "sha256:4b93e4832fd4a759a0c465c967214ed0c8a6e8914bced63a28ddb0dd8c5f078b"}, - {file = "debugpy-1.8.8-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:143ef07940aeb8e7316de48f5ed9447644da5203726fca378f3a6952a50a9eae"}, - {file = "debugpy-1.8.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f95651bdcbfd3b27a408869a53fbefcc2bcae13b694daee5f1365b1b83a00113"}, - {file = "debugpy-1.8.8-cp38-cp38-win32.whl", hash = "sha256:26b461123a030e82602a750fb24d7801776aa81cd78404e54ab60e8b5fecdad5"}, - {file = "debugpy-1.8.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3cbf1833e644a3100eadb6120f25be8a532035e8245584c4f7532937edc652a"}, - {file = "debugpy-1.8.8-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:53709d4ec586b525724819dc6af1a7703502f7e06f34ded7157f7b1f963bb854"}, - {file = "debugpy-1.8.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a9c013077a3a0000e83d97cf9cc9328d2b0bbb31f56b0e99ea3662d29d7a6a2"}, - {file = "debugpy-1.8.8-cp39-cp39-win32.whl", hash = "sha256:ffe94dd5e9a6739a75f0b85316dc185560db3e97afa6b215628d1b6a17561cb2"}, - {file = "debugpy-1.8.8-cp39-cp39-win_amd64.whl", hash = "sha256:5c0e5a38c7f9b481bf31277d2f74d2109292179081f11108e668195ef926c0f9"}, - {file = "debugpy-1.8.8-py2.py3-none-any.whl", hash = "sha256:ec684553aba5b4066d4de510859922419febc710df7bba04fe9e7ef3de15d34f"}, - {file = "debugpy-1.8.8.zip", hash = "sha256:e6355385db85cbd666be703a96ab7351bc9e6c61d694893206f8001e22aee091"}, + {file = "debugpy-1.8.9-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:cfe1e6c6ad7178265f74981edf1154ffce97b69005212fbc90ca22ddfe3d017e"}, + {file = "debugpy-1.8.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada7fb65102a4d2c9ab62e8908e9e9f12aed9d76ef44880367bc9308ebe49a0f"}, + {file = "debugpy-1.8.9-cp310-cp310-win32.whl", hash = "sha256:c36856343cbaa448171cba62a721531e10e7ffb0abff838004701454149bc037"}, + {file = "debugpy-1.8.9-cp310-cp310-win_amd64.whl", hash = "sha256:17c5e0297678442511cf00a745c9709e928ea4ca263d764e90d233208889a19e"}, + {file = "debugpy-1.8.9-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:b74a49753e21e33e7cf030883a92fa607bddc4ede1aa4145172debc637780040"}, + {file = "debugpy-1.8.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62d22dacdb0e296966d7d74a7141aaab4bec123fa43d1a35ddcb39bf9fd29d70"}, + {file = "debugpy-1.8.9-cp311-cp311-win32.whl", hash = "sha256:8138efff315cd09b8dcd14226a21afda4ca582284bf4215126d87342bba1cc66"}, + {file = "debugpy-1.8.9-cp311-cp311-win_amd64.whl", hash = "sha256:ff54ef77ad9f5c425398efb150239f6fe8e20c53ae2f68367eba7ece1e96226d"}, + {file = "debugpy-1.8.9-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:957363d9a7a6612a37458d9a15e72d03a635047f946e5fceee74b50d52a9c8e2"}, + {file = "debugpy-1.8.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e565fc54b680292b418bb809f1386f17081d1346dca9a871bf69a8ac4071afe"}, + {file = "debugpy-1.8.9-cp312-cp312-win32.whl", hash = "sha256:3e59842d6c4569c65ceb3751075ff8d7e6a6ada209ceca6308c9bde932bcef11"}, + {file = "debugpy-1.8.9-cp312-cp312-win_amd64.whl", hash = "sha256:66eeae42f3137eb428ea3a86d4a55f28da9bd5a4a3d369ba95ecc3a92c1bba53"}, + {file = "debugpy-1.8.9-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:957ecffff80d47cafa9b6545de9e016ae8c9547c98a538ee96ab5947115fb3dd"}, + {file = "debugpy-1.8.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1efbb3ff61487e2c16b3e033bc8595aea578222c08aaf3c4bf0f93fadbd662ee"}, + {file = "debugpy-1.8.9-cp313-cp313-win32.whl", hash = "sha256:7c4d65d03bee875bcb211c76c1d8f10f600c305dbd734beaed4077e902606fee"}, + {file = "debugpy-1.8.9-cp313-cp313-win_amd64.whl", hash = "sha256:e46b420dc1bea64e5bbedd678148be512442bc589b0111bd799367cde051e71a"}, + {file = "debugpy-1.8.9-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:472a3994999fe6c0756945ffa359e9e7e2d690fb55d251639d07208dbc37caea"}, + {file = "debugpy-1.8.9-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365e556a4772d7d0d151d7eb0e77ec4db03bcd95f26b67b15742b88cacff88e9"}, + {file = "debugpy-1.8.9-cp38-cp38-win32.whl", hash = "sha256:54a7e6d3014c408eb37b0b06021366ee985f1539e12fe49ca2ee0d392d9ceca5"}, + {file = "debugpy-1.8.9-cp38-cp38-win_amd64.whl", hash = "sha256:8e99c0b1cc7bf86d83fb95d5ccdc4ad0586d4432d489d1f54e4055bcc795f693"}, + {file = "debugpy-1.8.9-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:7e8b079323a56f719977fde9d8115590cb5e7a1cba2fcee0986ef8817116e7c1"}, + {file = "debugpy-1.8.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6953b335b804a41f16a192fa2e7851bdcfd92173cbb2f9f777bb934f49baab65"}, + {file = "debugpy-1.8.9-cp39-cp39-win32.whl", hash = "sha256:7e646e62d4602bb8956db88b1e72fe63172148c1e25c041e03b103a25f36673c"}, + {file = "debugpy-1.8.9-cp39-cp39-win_amd64.whl", hash = "sha256:3d9755e77a2d680ce3d2c5394a444cf42be4a592caaf246dbfbdd100ffcf7ae5"}, + {file = "debugpy-1.8.9-py2.py3-none-any.whl", hash = "sha256:cc37a6c9987ad743d9c3a14fa1b1a14b7e4e6041f9dd0c8abf8895fe7a97b899"}, + {file = "debugpy-1.8.9.zip", hash = "sha256:1339e14c7d980407248f09824d1b25ff5c5616651689f1e0f0e51bdead3ea13e"}, ] [[package]] @@ -3092,4 +3092,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "0ad79fb5601c4fea9a3e7d4f978e0b0085a76b49f7934a1814e04922c2029d80" +content-hash = "abc6c8d75193033d767c0a9422a991ed7fd65a10deb77fe64377c0a3716cc99d" diff --git a/pyproject.toml b/pyproject.toml index 5ab3ec2d4a..5a505ccd5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,7 +84,7 @@ pytest-asyncio = "^0.24.0" pytest-cov = "^5.0.0" pytest-ruff = "^0.4.1" pytest-xdist = "^3.6.1" -debugpy = "^1.8.8" +debugpy = "^1.8.9" [tool.poetry.extras] askar = ["aries-askar", "indy-credx", "indy-vdr", "anoncreds"] From 249ac73b03d1a3039ee58225ac09091acdaf6bb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:28:57 -0800 Subject: [PATCH 69/72] chore(deps): Bump aiohttp from 3.11.2 to 3.11.7 (#3349) Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.11.2 to 3.11.7. - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.11.2...v3.11.7) --- updated-dependencies: - dependency-name: aiohttp dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 156 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4265229219..2ec25c70e1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -24,87 +24,87 @@ files = [ [[package]] name = "aiohttp" -version = "3.11.2" +version = "3.11.7" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" files = [ - {file = "aiohttp-3.11.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:783741f534c14957fbe657d62a34b947ec06db23d45a2fd4a8aeb73d9c84d7e6"}, - {file = "aiohttp-3.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:435f7a08d8aa42371a94e7c141205a9cb092ba551084b5e0c57492e6673601a3"}, - {file = "aiohttp-3.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c681f34e2814bc6e1eef49752b338061b94a42c92734d0be9513447d3f83718c"}, - {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73a664478ae1ea011b5a710fb100b115ca8b2146864fa0ce4143ff944df714b8"}, - {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1d06c8fd8b453c3e553c956bd3b8395100401060430572174bb7876dd95ad49"}, - {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b1f4844909321ef2c1cee50ddeccbd6018cd8c8d1ddddda3f553e94a5859497"}, - {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdc6f8dce09281ae534eaf08a54f0d38612398375f28dad733a8885f3bf9b978"}, - {file = "aiohttp-3.11.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2d942421cf3a1d1eceae8fa192f1fbfb74eb9d3e207d35ad2696bd2ce2c987c"}, - {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:08ebe7a1d6c1e5ca766d68407280d69658f5f98821c2ba6c41c63cabfed159af"}, - {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2793d3297f3e49015140e6d3ea26142c967e07998e2fb00b6ee8d041138fbc4e"}, - {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4a23475d8d5c56e447b7752a1e2ac267c1f723f765e406c81feddcd16cdc97bc"}, - {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:556564d89e2f4a6e8fe000894c03e4e84cf0b6cfa5674e425db122633ee244d1"}, - {file = "aiohttp-3.11.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:57993f406ce3f114b2a6756d7809be3ffd0cc40f33e8f8b9a4aa1b027fd4e3eb"}, - {file = "aiohttp-3.11.2-cp310-cp310-win32.whl", hash = "sha256:177b000efaf8d2f7012c649e8aee5b0bf488677b1162be5e7511aa4f9d567607"}, - {file = "aiohttp-3.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:ff5d22eece44528023254b595c670dfcf9733ac6af74c4b6cb4f6a784dc3870c"}, - {file = "aiohttp-3.11.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:50e0aee4adc9abcd2109c618a8d1b2c93b85ac277b24a003ab147d91e068b06d"}, - {file = "aiohttp-3.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9aa4e68f1e4f303971ec42976fb170204fb5092de199034b57199a1747e78a2d"}, - {file = "aiohttp-3.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d84930b4145991214602372edd7305fc76b700220db79ac0dd57d3afd0f0a1ca"}, - {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ec8afd362356b8798c8caa806e91deb3f0602d8ffae8e91d2d3ced2a90c35e"}, - {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb0544a0e8294a5a5e20d3cacdaaa9a911d7c0a9150f5264aef36e7d8fdfa07e"}, - {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7b0a1618060e3f5aa73d3526ca2108a16a1b6bf86612cd0bb2ddcbef9879d06"}, - {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d878a0186023ac391861958035174d0486f3259cabf8fd94e591985468da3ea"}, - {file = "aiohttp-3.11.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e33a7eddcd07545ccf5c3ab230f60314a17dc33e285475e8405e26e21f02660"}, - {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4d7fad8c456d180a6d2f44c41cfab4b80e2e81451815825097db48b8293f59d5"}, - {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d954ba0eae7f33884d27dc00629ca4389d249eb8d26ca07c30911257cae8c96"}, - {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:afa55e863224e664a782effa62245df73fdfc55aee539bed6efacf35f6d4e4b7"}, - {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:10a5f91c319d9d4afba812f72984816b5fcd20742232ff7ecc1610ffbf3fc64d"}, - {file = "aiohttp-3.11.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6e8e19a80ba194db5c06915a9df23c0c06e0e9ca9a4db9386a6056cca555a027"}, - {file = "aiohttp-3.11.2-cp311-cp311-win32.whl", hash = "sha256:9c8d1db4f65bbc9d75b7b271d68fb996f1c8c81a525263862477d93611856c2d"}, - {file = "aiohttp-3.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:2adb967454e10e69478ba4a8d8afbba48a7c7a8619216b7c807f8481cc66ddfb"}, - {file = "aiohttp-3.11.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f833a80d9de9307d736b6af58c235b17ef7f90ebea7b9c49cd274dec7a66a2f1"}, - {file = "aiohttp-3.11.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:382f853516664d2ebfc75dc01da4a10fdef5edcb335fe7b45cf471ce758ecb18"}, - {file = "aiohttp-3.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3a2bcf6c81639a165da93469e1e0aff67c956721f3fa9c0560f07dd1e505116"}, - {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de3b4d5fb5d69749104b880a157f38baeea7765c93d9cd3837cedd5b84729e10"}, - {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a90a0dc4b054b5af299a900bf950fe8f9e3e54322bc405005f30aa5cacc5c98"}, - {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32334f35824811dd20a12cc90825d000e6b50faaeaa71408d42269151a66140d"}, - {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cba0b8d25aa2d450762f3dd6df85498f5e7c3ad0ddeb516ef2b03510f0eea32"}, - {file = "aiohttp-3.11.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bbb2dbc2701ab7e9307ca3a8fa4999c5b28246968e0a0202a5afabf48a42e22"}, - {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97fba98fc5d9ccd3d33909e898d00f2494d6a9eec7cbda3d030632e2c8bb4d00"}, - {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0ebdf5087e2ce903d8220cc45dcece90c2199ae4395fd83ca616fcc81010db2c"}, - {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:122768e3ae9ce74f981b46edefea9c6e5a40aea38aba3ac50168e6370459bf20"}, - {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5587da333b7d280a312715b843d43e734652aa382cba824a84a67c81f75b338b"}, - {file = "aiohttp-3.11.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:85de9904bc360fd29a98885d2bfcbd4e02ab33c53353cb70607f2bea2cb92468"}, - {file = "aiohttp-3.11.2-cp312-cp312-win32.whl", hash = "sha256:b470de64d17156c37e91effc109d3b032b39867000e2c126732fe01d034441f9"}, - {file = "aiohttp-3.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:3f617a48b70f4843d54f52440ea1e58da6bdab07b391a3a6aed8d3b311a4cc04"}, - {file = "aiohttp-3.11.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5d90b5a3b0f32a5fecf5dd83d828713986c019585f5cddf40d288ff77f366615"}, - {file = "aiohttp-3.11.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d23854e5867650d40cba54d49956aad8081452aa80b2cf0d8c310633f4f48510"}, - {file = "aiohttp-3.11.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:486273d3b5af75a80c31c311988931bdd2a4b96a74d5c7f422bad948f99988ef"}, - {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9075313f8e41b481e4cb10af405054564b0247dc335db5398ed05f8ec38787e2"}, - {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44b69c69c194ffacbc50165911cf023a4b1b06422d1e1199d3aea82eac17004e"}, - {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b339d91ac9060bd6ecdc595a82dc151045e5d74f566e0864ef3f2ba0887fec42"}, - {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64e8f5178958a9954043bc8cd10a5ae97352c3f2fc99aa01f2aebb0026010910"}, - {file = "aiohttp-3.11.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3129151378f858cdc4a0a4df355c9a0d060ab49e2eea7e62e9f085bac100551b"}, - {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:14eb6c628432720e41b4fab1ada879d56cfe7034159849e083eb536b4c2afa99"}, - {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e57a10aacedcf24666f4c90d03e599f71d172d1c5e00dcf48205c445806745b0"}, - {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:66e58a2e8c7609a3545c4b38fb8b01a6b8346c4862e529534f7674c5265a97b8"}, - {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9b6d15adc9768ff167614ca853f7eeb6ee5f1d55d5660e3af85ce6744fed2b82"}, - {file = "aiohttp-3.11.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2914061f5ca573f990ec14191e6998752fa8fe50d518e3405410353c3f44aa5d"}, - {file = "aiohttp-3.11.2-cp313-cp313-win32.whl", hash = "sha256:1c2496182e577042e0e07a328d91c949da9e77a2047c7291071e734cd7a6e780"}, - {file = "aiohttp-3.11.2-cp313-cp313-win_amd64.whl", hash = "sha256:cccb2937bece1310c5c0163d0406aba170a2e5fb1f0444d7b0e7fdc9bd6bb713"}, - {file = "aiohttp-3.11.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:994cb893936dd2e1803655ae8667a45066bfd53360b148e22b4e3325cc5ea7a3"}, - {file = "aiohttp-3.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3666c750b73ce463a413692e3a57c60f7089e2d9116a2aa5a0f0eaf2ae325148"}, - {file = "aiohttp-3.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6ad9a7d2a3a0f235184426425f80bd3b26c66b24fd5fddecde66be30c01ebe6e"}, - {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c979fc92aba66730b66099cd5becb42d869a26c0011119bc1c2478408a8bf7a"}, - {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:766d0ebf8703d28f854f945982aa09224d5a27a29594c70d921c43c3930fe7ac"}, - {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79efd1ee3827b2f16797e14b1e45021206c3271249b4d0025014466d416d7413"}, - {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d6e069b882c1fdcbe5577dc4be372eda705180197140577a4cddb648c29d22e"}, - {file = "aiohttp-3.11.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e9a766c346b2ed7e88937919d84ed64b4ef489dad1d8939f806ee52901dc142"}, - {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2b02a68b9445c70d7f5c8b578c5f5e5866b1d67ca23eb9e8bc8658ae9e3e2c74"}, - {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:374baefcb1b6275f350da605951f5f02487a9bc84a574a7d5b696439fabd49a3"}, - {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d2f991c18132f3e505c108147925372ffe4549173b7c258cf227df1c5977a635"}, - {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:34f37c59b12bc3afc52bab6fcd9cd3be82ff01c4598a84cbea934ccb3a9c54a0"}, - {file = "aiohttp-3.11.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:33af11eca7bb0f5c6ffaf5e7d9d2336c2448f9c6279b93abdd6f3c35f9ee321f"}, - {file = "aiohttp-3.11.2-cp39-cp39-win32.whl", hash = "sha256:83a70e22e0f6222effe7f29fdeba6c6023f9595e59a0479edacfbd7de4b77bb7"}, - {file = "aiohttp-3.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:c28c1677ea33ccb8b14330560094cc44d3ff4fad617a544fd18beb90403fe0f1"}, - {file = "aiohttp-3.11.2.tar.gz", hash = "sha256:68d1f46f9387db3785508f5225d3acbc5825ca13d9c29f2b5cce203d5863eb79"}, + {file = "aiohttp-3.11.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8bedb1f6cb919af3b6353921c71281b1491f948ca64408871465d889b4ee1b66"}, + {file = "aiohttp-3.11.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f5022504adab881e2d801a88b748ea63f2a9d130e0b2c430824682a96f6534be"}, + {file = "aiohttp-3.11.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e22d1721c978a6494adc824e0916f9d187fa57baeda34b55140315fa2f740184"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e993676c71288618eb07e20622572b1250d8713e7e00ab3aabae28cb70f3640d"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e13a05db87d3b241c186d0936808d0e4e12decc267c617d54e9c643807e968b6"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ba8d043fed7ffa117024d7ba66fdea011c0e7602327c6d73cacaea38abe4491"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda3ed0a7869d2fa16aa41f9961ade73aa2c2e3b2fcb0a352524e7b744881889"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43bfd25113c1e98aec6c70e26d5f4331efbf4aa9037ba9ad88f090853bf64d7f"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3dd3e7e7c9ef3e7214f014f1ae260892286647b3cf7c7f1b644a568fd410f8ca"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:78c657ece7a73b976905ab9ec8be9ef2df12ed8984c24598a1791c58ce3b4ce4"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:db70a47987e34494b451a334605bee57a126fe8d290511349e86810b4be53b01"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9e67531370a3b07e49b280c1f8c2df67985c790ad2834d1b288a2f13cd341c5f"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9202f184cc0582b1db15056f2225ab4c1e3dac4d9ade50dd0613ac3c46352ac2"}, + {file = "aiohttp-3.11.7-cp310-cp310-win32.whl", hash = "sha256:2257bdd5cf54a4039a4337162cd8048f05a724380a2283df34620f55d4e29341"}, + {file = "aiohttp-3.11.7-cp310-cp310-win_amd64.whl", hash = "sha256:b7215bf2b53bc6cb35808149980c2ae80a4ae4e273890ac85459c014d5aa60ac"}, + {file = "aiohttp-3.11.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cea52d11e02123f125f9055dfe0ccf1c3857225fb879e4a944fae12989e2aef2"}, + {file = "aiohttp-3.11.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3ce18f703b7298e7f7633efd6a90138d99a3f9a656cb52c1201e76cb5d79cf08"}, + {file = "aiohttp-3.11.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:670847ee6aeb3a569cd7cdfbe0c3bec1d44828bbfbe78c5d305f7f804870ef9e"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dda726f89bfa5c465ba45b76515135a3ece0088dfa2da49b8bb278f3bdeea12"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25b74a811dba37c7ea6a14d99eb9402d89c8d739d50748a75f3cf994cf19c43"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5522ee72f95661e79db691310290c4618b86dff2d9b90baedf343fd7a08bf79"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fbf41a6bbc319a7816ae0f0177c265b62f2a59ad301a0e49b395746eb2a9884"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59ee1925b5a5efdf6c4e7be51deee93984d0ac14a6897bd521b498b9916f1544"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:24054fce8c6d6f33a3e35d1c603ef1b91bbcba73e3f04a22b4f2f27dac59b347"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:351849aca2c6f814575c1a485c01c17a4240413f960df1bf9f5deb0003c61a53"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:12724f3a211fa243570e601f65a8831372caf1a149d2f1859f68479f07efec3d"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7ea4490360b605804bea8173d2d086b6c379d6bb22ac434de605a9cbce006e7d"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e0bf378db07df0a713a1e32381a1b277e62ad106d0dbe17b5479e76ec706d720"}, + {file = "aiohttp-3.11.7-cp311-cp311-win32.whl", hash = "sha256:cd8d62cab363dfe713067027a5adb4907515861f1e4ce63e7be810b83668b847"}, + {file = "aiohttp-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:bf0e6cce113596377cadda4e3ac5fb89f095bd492226e46d91b4baef1dd16f60"}, + {file = "aiohttp-3.11.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4bb7493c3e3a36d3012b8564bd0e2783259ddd7ef3a81a74f0dbfa000fce48b7"}, + {file = "aiohttp-3.11.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e143b0ef9cb1a2b4f74f56d4fbe50caa7c2bb93390aff52f9398d21d89bc73ea"}, + {file = "aiohttp-3.11.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7c58a240260822dc07f6ae32a0293dd5bccd618bb2d0f36d51c5dbd526f89c0"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d20cfe63a1c135d26bde8c1d0ea46fd1200884afbc523466d2f1cf517d1fe33"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12e4d45847a174f77b2b9919719203769f220058f642b08504cf8b1cf185dacf"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf4efa2d01f697a7dbd0509891a286a4af0d86902fc594e20e3b1712c28c0106"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee6a4cdcbf54b8083dc9723cdf5f41f722c00db40ccf9ec2616e27869151129"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6095aaf852c34f42e1bd0cf0dc32d1e4b48a90bfb5054abdbb9d64b36acadcb"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1cf03d27885f8c5ebf3993a220cc84fc66375e1e6e812731f51aab2b2748f4a6"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1a17f6a230f81eb53282503823f59d61dff14fb2a93847bf0399dc8e87817307"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:481f10a1a45c5f4c4a578bbd74cff22eb64460a6549819242a87a80788461fba"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:db37248535d1ae40735d15bdf26ad43be19e3d93ab3f3dad8507eb0f85bb8124"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d18a8b44ec8502a7fde91446cd9c9b95ce7c49f1eacc1fb2358b8907d4369fd"}, + {file = "aiohttp-3.11.7-cp312-cp312-win32.whl", hash = "sha256:3d1c9c15d3999107cbb9b2d76ca6172e6710a12fda22434ee8bd3f432b7b17e8"}, + {file = "aiohttp-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:018f1b04883a12e77e7fc161934c0f298865d3a484aea536a6a2ca8d909f0ba0"}, + {file = "aiohttp-3.11.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:241a6ca732d2766836d62c58c49ca7a93d08251daef0c1e3c850df1d1ca0cbc4"}, + {file = "aiohttp-3.11.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aa3705a8d14de39898da0fbad920b2a37b7547c3afd2a18b9b81f0223b7d0f68"}, + {file = "aiohttp-3.11.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9acfc7f652b31853eed3b92095b0acf06fd5597eeea42e939bd23a17137679d5"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcefcf2915a2dbdbce37e2fc1622129a1918abfe3d06721ce9f6cdac9b6d2eaa"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c1f6490dd1862af5aae6cfcf2a274bffa9a5b32a8f5acb519a7ecf5a99a88866"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac5462582d6561c1c1708853a9faf612ff4e5ea5e679e99be36143d6eabd8e"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1a6309005acc4b2bcc577ba3b9169fea52638709ffacbd071f3503264620da"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b973cce96793725ef63eb449adfb74f99c043c718acb76e0d2a447ae369962"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ce91a24aac80de6be8512fb1c4838a9881aa713f44f4e91dd7bb3b34061b497d"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:875f7100ce0e74af51d4139495eec4025affa1a605280f23990b6434b81df1bd"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c171fc35d3174bbf4787381716564042a4cbc008824d8195eede3d9b938e29a8"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ee9afa1b0d2293c46954f47f33e150798ad68b78925e3710044e0d67a9487791"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8360c7cc620abb320e1b8d603c39095101391a82b1d0be05fb2225471c9c5c52"}, + {file = "aiohttp-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7a9318da4b4ada9a67c1dd84d1c0834123081e746bee311a16bb449f363d965e"}, + {file = "aiohttp-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:fc6da202068e0a268e298d7cd09b6e9f3997736cd9b060e2750963754552a0a9"}, + {file = "aiohttp-3.11.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:17829f37c0d31d89aa6b8b010475a10233774771f9b6dc2cc352ea4f8ce95d9a"}, + {file = "aiohttp-3.11.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d6177077a31b1aecfc3c9070bd2f11419dbb4a70f30f4c65b124714f525c2e48"}, + {file = "aiohttp-3.11.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:badda65ac99555791eed75e234afb94686ed2317670c68bff8a4498acdaee935"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0de6466b9d742b4ee56fe1b2440706e225eb48c77c63152b1584864a236e7a50"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04b0cc74d5a882c9dacaeeccc1444f0233212b6f5be8bc90833feef1e1ce14b9"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c7af3e50e5903d21d7b935aceed901cc2475463bc16ddd5587653548661fdb"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c63f898f683d1379b9be5afc3dd139e20b30b0b1e0bf69a3fc3681f364cf1629"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdadc3f6a32d6eca45f9a900a254757fd7855dfb2d8f8dcf0e88f0fae3ff8eb1"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d329300fb23e14ed1f8c6d688dfd867d1dcc3b1d7cd49b7f8c5b44e797ce0932"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5578cf40440eafcb054cf859964bc120ab52ebe0e0562d2b898126d868749629"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7b2f8107a3c329789f3c00b2daad0e35f548d0a55cda6291579136622099a46e"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:43dd89a6194f6ab02a3fe36b09e42e2df19c211fc2050ce37374d96f39604997"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d2fa6fc7cc865d26ff42480ac9b52b8c9b7da30a10a6442a9cdf429de840e949"}, + {file = "aiohttp-3.11.7-cp39-cp39-win32.whl", hash = "sha256:a7d9a606355655617fee25dd7e54d3af50804d002f1fd3118dd6312d26692d70"}, + {file = "aiohttp-3.11.7-cp39-cp39-win_amd64.whl", hash = "sha256:53c921b58fdc6485d6b2603e0132bb01cd59b8f0620ffc0907f525e0ba071687"}, + {file = "aiohttp-3.11.7.tar.gz", hash = "sha256:01a8aca4af3da85cea5c90141d23f4b0eee3cbecfd33b029a45a80f28c66c668"}, ] [package.dependencies] @@ -3092,4 +3092,4 @@ didcommv2 = ["didcomm-messaging"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "abc6c8d75193033d767c0a9422a991ed7fd65a10deb77fe64377c0a3716cc99d" +content-hash = "c9121c319eb42db81805bec50a15a153e7ef4f8bef5231a6b12a7a74b4ffe290" diff --git a/pyproject.toml b/pyproject.toml index 5a505ccd5c..de8a3531bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ repository = "https://github.com/openwallet-foundation/acapy" [tool.poetry.dependencies] python = "^3.12" -aiohttp = "~3.11.2" +aiohttp = "~3.11.7" aiohttp-apispec-acapy = "~3.0.2" aiohttp-cors = "~0.7.0" apispec = "^6.6.0" From 51ba3e7db127357a4b50d00834cbce9637fe5d23 Mon Sep 17 00:00:00 2001 From: ff137 Date: Wed, 27 Nov 2024 13:17:23 +0200 Subject: [PATCH 70/72] :rewind: Revert `trace` log changes, and move to debug level Signed-off-by: ff137 --- acapy_agent/config/default_context.py | 20 ++-- acapy_agent/config/logging/configurator.py | 5 - acapy_agent/config/logging/utils.py | 102 ---------------- acapy_agent/config/tests/test_logging.py | 130 --------------------- acapy_agent/core/conductor.py | 93 +++++++-------- acapy_agent/core/plugin_registry.py | 84 +++++++------ acapy_agent/utils/classloader.py | 54 ++++----- 7 files changed, 120 insertions(+), 368 deletions(-) delete mode 100644 acapy_agent/config/logging/utils.py diff --git a/acapy_agent/config/default_context.py b/acapy_agent/config/default_context.py index 35ee02a184..8f28b0eaee 100644 --- a/acapy_agent/config/default_context.py +++ b/acapy_agent/config/default_context.py @@ -5,7 +5,6 @@ from ..anoncreds.registry import AnonCredsRegistry from ..cache.base import BaseCache from ..cache.in_memory import InMemoryCache -from ..config.logging.utils import add_trace_level from ..core.event_bus import EventBus from ..core.goal_code_registry import GoalCodeRegistry from ..core.plugin_registry import PluginRegistry @@ -30,7 +29,6 @@ from .provider import CachedProvider, ClassProvider LOGGER = logging.getLogger(__name__) -add_trace_level() # Allow trace logs from this module class DefaultContextBuilder(ContextBuilder): @@ -38,14 +36,14 @@ class DefaultContextBuilder(ContextBuilder): async def build_context(self) -> InjectionContext: """Build the base injection context; set DIDComm prefix to emit.""" - LOGGER.trace("Building new injection context with settings: %s", self.settings) + LOGGER.debug("Building new injection context") context = InjectionContext(settings=self.settings) context.settings.set_default("default_label", "Aries Cloud Agent") if context.settings.get("timing.enabled"): timing_log = context.settings.get("timing.log_file") - LOGGER.trace("Enabling timing collector with log file: %s", timing_log) + LOGGER.debug("Enabling timing collector with log file: %s", timing_log) collector = Collector(log_path=timing_log) context.injector.bind_instance(Collector, collector) @@ -87,13 +85,13 @@ async def build_context(self) -> InjectionContext: async def bind_providers(self, context: InjectionContext): """Bind various class providers.""" - LOGGER.trace("Begin binding providers to context") + LOGGER.debug("Begin binding providers to context") context.injector.bind_provider(ProfileManager, ProfileManagerProvider()) wallet_type = self.settings.get("wallet.type") if wallet_type == "askar-anoncreds": - LOGGER.trace("Using AnonCreds tails server") + LOGGER.debug("Using AnonCreds tails server") context.injector.bind_provider( BaseTailsServer, ClassProvider( @@ -101,7 +99,7 @@ async def bind_providers(self, context: InjectionContext): ), ) else: - LOGGER.trace("Using Indy tails server") + LOGGER.debug("Using Indy tails server") context.injector.bind_provider( BaseTailsServer, ClassProvider( @@ -124,7 +122,7 @@ async def bind_providers(self, context: InjectionContext): async def load_plugins(self, context: InjectionContext): """Set up plugin registry and load plugins.""" - LOGGER.trace("Initializing plugin registry") + LOGGER.debug("Initializing plugin registry") plugin_registry = PluginRegistry( blocklist=self.settings.get("blocked_plugins", []) ) @@ -164,7 +162,7 @@ async def load_plugins(self, context: InjectionContext): def register_plugins(plugins: list[str], plugin_type: str): """Register a group of plugins with logging.""" - LOGGER.trace("Registering %s plugins", plugin_type) + LOGGER.debug("Registering %s plugins", plugin_type) for plugin in plugins: plugin_registry.register_plugin(plugin) @@ -177,7 +175,7 @@ def register_anoncreds_plugins(): register_plugins(default_plugins, "default") if context.settings.get("multitenant.admin_enabled"): - LOGGER.trace("Multitenant admin enabled - registering additional plugins") + LOGGER.debug("Multitenant admin enabled - registering additional plugins") plugin_registry.register_plugin("acapy_agent.multitenant.admin") register_askar_plugins() register_anoncreds_plugins() @@ -189,7 +187,7 @@ def register_anoncreds_plugins(): # Register external plugins for plugin_path in self.settings.get("external_plugins", []): - LOGGER.trace("Registering external plugin: %s", plugin_path) + LOGGER.debug("Registering external plugin: %s", plugin_path) plugin_registry.register_plugin(plugin_path) # Register message protocols diff --git a/acapy_agent/config/logging/configurator.py b/acapy_agent/config/logging/configurator.py index fb9e2cb347..128ccf5e49 100644 --- a/acapy_agent/config/logging/configurator.py +++ b/acapy_agent/config/logging/configurator.py @@ -31,14 +31,9 @@ from .timed_rotating_file_multi_process_handler import ( TimedRotatingFileMultiProcessHandler, ) -from .utils import add_trace_level - LOGGER = logging.getLogger(__name__) -# Add TRACE level to logging before any configuration -add_trace_level() - def load_resource(path: str, encoding: Optional[str] = None): """Open a resource file located in a python package or the local filesystem. diff --git a/acapy_agent/config/logging/utils.py b/acapy_agent/config/logging/utils.py deleted file mode 100644 index 10092d261a..0000000000 --- a/acapy_agent/config/logging/utils.py +++ /dev/null @@ -1,102 +0,0 @@ -"""Logging utilities.""" - -import logging -from functools import partial, partialmethod -from typing import Optional - -LOGGER = logging.getLogger(__name__) -_TRACE_LEVEL_ADDED = False - - -def add_logging_level( - level_name: str, level_num: int, method_name: Optional[str] = None -) -> None: - """Add a custom logging level to the `logging` module. - - Comprehensively adds a new logging level to the `logging` module and the - currently configured logging class. - - `level_name` becomes an attribute of the `logging` module with the value - `level_num`. - `methodName` becomes a convenience method for both `logging` itself - and the class returned by `logging.getLoggerClass()` (usually just - `logging.Logger`). - If `methodName` is not specified, `levelName.lower()` is used. - - To avoid accidental clobberings of existing attributes, this method will - raise an `AttributeError` if the level name is already an attribute of the - `logging` module or if the method name is already present - - Example: - ------- - >>> add_logging_level('TRACE', logging.DEBUG - 5) - >>> logging.getLogger(__name__).setLevel('TRACE') - >>> logging.getLogger(__name__).trace('that worked') - >>> logging.trace('so did this') - >>> logging.TRACE - 5 - - References: - - https://stackoverflow.com/a/35804945 - """ - if not method_name: - method_name = level_name.lower() - - if hasattr(logging, level_name): - raise AttributeError(f"{level_name} already defined in logging module") - if hasattr(logging, method_name): - raise AttributeError(f"{method_name} already defined in logging module") - if hasattr(logging.getLoggerClass(), method_name): - raise AttributeError(f"{method_name} already defined in logger class") - - # Add the new logging level - logging.addLevelName(level_num, level_name) - setattr(logging, level_name, level_num) - setattr( - logging.getLoggerClass(), - method_name, - partialmethod(logging.getLoggerClass().log, level_num), - ) - setattr(logging, method_name, partial(logging.log, level_num)) - - -def add_trace_level() -> None: - """Add the TRACE level to the logging module safely. - - This function adds a TRACE level to the logging module if it hasn't been added yet. - It handles the case where TRACE is already defined, avoiding duplicate additions. - - Returns: - None - """ - global _TRACE_LEVEL_ADDED - - if _TRACE_LEVEL_ADDED: - return - - TRACE_LEVEL_NUM = logging.DEBUG - 5 - TRACE_LEVEL_NAME = "TRACE" - TRACE_METHOD_NAME = "trace" - - # Check if TRACE level is already defined - level_exists = ( - hasattr(logging, TRACE_LEVEL_NAME) - and getattr(logging, TRACE_LEVEL_NAME) == TRACE_LEVEL_NUM - ) - - method_exists = hasattr(logging, TRACE_METHOD_NAME) and callable( - getattr(logging, TRACE_METHOD_NAME) - ) - - if not level_exists or not method_exists: - try: - add_logging_level(TRACE_LEVEL_NAME, TRACE_LEVEL_NUM, TRACE_METHOD_NAME) - LOGGER.debug("%s level added to logging module.", TRACE_LEVEL_NAME) - except AttributeError as e: - LOGGER.warning("%s level already exists: %s", TRACE_LEVEL_NAME, e) - else: - LOGGER.debug( - "%s level is already present in the logging module.", TRACE_LEVEL_NAME - ) - - _TRACE_LEVEL_ADDED = True diff --git a/acapy_agent/config/tests/test_logging.py b/acapy_agent/config/tests/test_logging.py index 446395003d..cf23074568 100644 --- a/acapy_agent/config/tests/test_logging.py +++ b/acapy_agent/config/tests/test_logging.py @@ -1,11 +1,9 @@ import contextlib -import logging from io import BufferedReader, StringIO, TextIOWrapper from tempfile import NamedTemporaryFile from unittest import IsolatedAsyncioTestCase, mock from ..logging import configurator as test_module -from ..logging import utils class TestLoggingConfigurator(IsolatedAsyncioTestCase): @@ -164,131 +162,3 @@ def test_load_resource(self): mock_files.return_value.joinpath.assert_called_once_with("def") mock_resource_path.open.assert_called_once_with("rb") assert result == mock_resource_handle # Verify the returned binary stream - - -class TestLoggingUtils(IsolatedAsyncioTestCase): - def setUp(self): - """Set up test environment by backing up logging states and resetting TRACE level.""" - # Backup existing logging attributes (e.g., DEBUG, INFO) - self.original_levels = { - attr: getattr(logging, attr) for attr in dir(logging) if attr.isupper() - } - - # Backup existing logger class methods (e.g., debug, info) - self.original_logger_methods = { - attr: getattr(logging.getLoggerClass(), attr, None) - for attr in dir(logging.getLoggerClass()) - if not attr.startswith("_") - } - - # Remove TRACE level and 'trace' method if they exist - if hasattr(logging, "TRACE"): - delattr(logging, "TRACE") - if hasattr(logging.getLoggerClass(), "trace"): - delattr(logging.getLoggerClass(), "trace") - - # Patch the TRACE_LEVEL_ADDED flag to False before each test - self.trace_level_added_patcher = mock.patch( - "acapy_agent.config.logging.utils._TRACE_LEVEL_ADDED", False - ) - self.mock_trace_level_added = self.trace_level_added_patcher.start() - - def tearDown(self): - """Restore original logging states after each test.""" - # Stop patching TRACE_LEVEL_ADDED - self.trace_level_added_patcher.stop() - - # Restore original logging level attributes - for attr, value in self.original_levels.items(): - setattr(logging, attr, value) - - # Identify and remove any new uppercase attributes added during tests (e.g., TRACE) - current_levels = {attr for attr in dir(logging) if attr.isupper()} - for attr in current_levels - set(self.original_levels.keys()): - delattr(logging, attr) - - # Restore original logger class methods - LoggerClass = logging.getLoggerClass() - for attr, value in self.original_logger_methods.items(): - if value is not None: - setattr(LoggerClass, attr, value) - else: - if hasattr(LoggerClass, attr): - delattr(LoggerClass, attr) - - # Identify and remove any new logger methods added during tests (e.g., trace) - current_methods = {attr for attr in dir(LoggerClass) if not attr.startswith("_")} - for attr in current_methods - set(self.original_logger_methods.keys()): - delattr(LoggerClass, attr) - - @mock.patch("acapy_agent.config.logging.utils.LOGGER") - @mock.patch("acapy_agent.config.logging.utils.logging.addLevelName") - def test_add_logging_level_success(self, mock_add_level_name, mock_logger): - utils.add_logging_level("CUSTOM", 2) - - mock_add_level_name.assert_called_once_with(2, "CUSTOM") - self.assertTrue(hasattr(logging, "CUSTOM")) - self.assertEqual(logging.CUSTOM, 2) - - logger = logging.getLogger(__name__) - self.assertTrue(hasattr(logger, "custom")) - self.assertTrue(callable(logger.custom)) - - self.assertTrue(hasattr(logging, "custom")) - self.assertTrue(callable(logging.custom)) - - def test_add_logging_level_existing_level_name(self): - # Add a level named 'DEBUG' which already exists - with self.assertRaises(AttributeError) as context: - utils.add_logging_level("DEBUG", 15) - self.assertIn("DEBUG already defined in logging module", str(context.exception)) - - def test_add_logging_level_existing_method_name(self): - # Add a logging method that already exists ('debug') - with self.assertRaises(AttributeError) as context: - utils.add_logging_level("CUSTOM", 25, method_name="debug") - self.assertIn("debug already defined in logging module", str(context.exception)) - - @mock.patch("acapy_agent.config.logging.utils.add_logging_level") - @mock.patch("acapy_agent.config.logging.utils.LOGGER") - def test_add_trace_level_new(self, mock_logger, mock_add_logging_level): - # Ensure _TRACE_LEVEL_ADDED is False - utils.add_trace_level() - - mock_add_logging_level.assert_called_once_with( - "TRACE", logging.DEBUG - 5, "trace" - ) - - # Verify logger.debug was called - mock_logger.debug.assert_called_with("%s level added to logging module.", "TRACE") - - # Check that _TRACE_LEVEL_ADDED is now True - self.assertTrue(utils._TRACE_LEVEL_ADDED) - - @mock.patch("acapy_agent.config.logging.utils.LOGGER") - @mock.patch( - "acapy_agent.config.logging.utils.add_logging_level", - side_effect=AttributeError("TRACE already exists"), - ) - def test_add_trace_level_already_exists_exception( - self, mock_add_logging_level, mock_logger - ): - utils.add_trace_level() - - # Verify logger.warning was called - mock_logger.warning.assert_called_with( - "%s level already exists: %s", "TRACE", mock_add_logging_level.side_effect - ) - - @mock.patch("acapy_agent.config.logging.utils.LOGGER") - @mock.patch("acapy_agent.config.logging.utils.add_logging_level") - def test_add_trace_level_already_present(self, mock_add_logging_level, mock_logger): - # Manually set _TRACE_LEVEL_ADDED to True to simulate already added TRACE level - with mock.patch("acapy_agent.config.logging.utils._TRACE_LEVEL_ADDED", True): - utils.add_trace_level() - - # add_logging_level should not be called since TRACE level is already added - mock_add_logging_level.assert_not_called() - - # Verify logger.debug was not called - mock_logger.debug.assert_not_called() diff --git a/acapy_agent/core/conductor.py b/acapy_agent/core/conductor.py index c3da908e49..fd04b4e36c 100644 --- a/acapy_agent/core/conductor.py +++ b/acapy_agent/core/conductor.py @@ -27,7 +27,6 @@ load_multiple_genesis_transactions_from_config, ) from ..config.logging import LoggingConfigurator -from ..config.logging.utils import add_trace_level from ..config.provider import ClassProvider from ..config.wallet import wallet_config from ..core.profile import Profile @@ -83,8 +82,6 @@ from .util import SHUTDOWN_EVENT_TOPIC, STARTUP_EVENT_TOPIC LOGGER = logging.getLogger(__name__) -add_trace_level() # Allow trace logs from this module - # Refer ACA-Py issue #2197 # When the from version is not found DEFAULT_ACAPY_VERSION = "v0.7.5" @@ -127,7 +124,7 @@ async def setup(self): LOGGER.debug("Starting setup of the Conductor") context = await self.context_builder.build_context() - LOGGER.trace("Context built successfully") + LOGGER.debug("Context built successfully") if self.force_agent_anoncreds: LOGGER.debug( @@ -153,15 +150,15 @@ async def setup(self): await get_genesis_transactions(context.settings) # Configure the root profile - LOGGER.trace("Configuring the root profile and setting up public DID") + LOGGER.debug("Configuring the root profile and setting up public DID") self.root_profile, self.setup_public_did = await wallet_config(context) context = self.root_profile.context - LOGGER.trace("Root profile configured successfully") + LOGGER.debug("Root profile configured successfully") # Multiledger Setup ledger_config_list = context.settings.get("ledger.ledger_config_list") if ledger_config_list and len(ledger_config_list) > 0: - LOGGER.trace("Setting up multiledger manager") + LOGGER.debug("Setting up multiledger manager") context.injector.bind_provider( BaseMultipleLedgerManager, MultiIndyLedgerManagerProvider(self.root_profile), @@ -177,7 +174,7 @@ async def setup(self): self.root_profile.BACKEND_NAME == "askar" and ledger.BACKEND_NAME == "indy-vdr" ): - LOGGER.trace("Binding IndyCredxVerifier for 'askar' backend.") + LOGGER.debug("Binding IndyCredxVerifier for 'askar' backend.") context.injector.bind_provider( IndyVerifier, ClassProvider( @@ -189,7 +186,7 @@ async def setup(self): self.root_profile.BACKEND_NAME == "askar-anoncreds" and ledger.BACKEND_NAME == "indy-vdr" ): - LOGGER.trace( + LOGGER.debug( "Binding IndyCredxVerifier for 'askar-anoncreds' backend." ) context.injector.bind_provider( @@ -228,7 +225,7 @@ async def setup(self): context.injector.bind_instance( InboundTransportManager, self.inbound_transport_manager ) - LOGGER.trace("Inbound transports registered successfully.") + LOGGER.debug("Inbound transports registered successfully.") # Register all outbound transports LOGGER.debug("Setting up outbound transports.") @@ -236,46 +233,46 @@ async def setup(self): self.root_profile, self.handle_not_delivered ) await self.outbound_transport_manager.setup() - LOGGER.trace("Outbound transports registered successfully.") + LOGGER.debug("Outbound transports registered successfully.") # Initialize dispatcher - LOGGER.trace("Initializing dispatcher.") + LOGGER.debug("Initializing dispatcher.") self.dispatcher = Dispatcher(self.root_profile) await self.dispatcher.setup() - LOGGER.trace("Dispatcher initialized successfully.") + LOGGER.debug("Dispatcher initialized successfully.") wire_format = context.inject_or(BaseWireFormat) if wire_format and hasattr(wire_format, "task_queue"): wire_format.task_queue = self.dispatcher.task_queue - LOGGER.trace("Wire format task queue bound to dispatcher.") + LOGGER.debug("Wire format task queue bound to dispatcher.") # Bind manager for multitenancy related tasks if context.settings.get("multitenant.enabled"): - LOGGER.trace("Multitenant is enabled. Binding MultitenantManagerProvider.") + LOGGER.debug("Multitenant is enabled. Binding MultitenantManagerProvider.") context.injector.bind_provider( BaseMultitenantManager, MultitenantManagerProvider(self.root_profile) ) # Bind route manager provider - LOGGER.trace("Binding RouteManagerProvider.") + LOGGER.debug("Binding RouteManagerProvider.") context.injector.bind_provider( RouteManager, RouteManagerProvider(self.root_profile) ) # Bind OobMessageProcessor to be able to receive and process unencrypted messages - LOGGER.trace("Binding OobMessageProcessor.") + LOGGER.debug("Binding OobMessageProcessor.") context.injector.bind_instance( OobMessageProcessor, OobMessageProcessor(inbound_message_router=self.inbound_message_router), ) # Bind default PyLD document loader - LOGGER.trace("Binding default DocumentLoader.") + LOGGER.debug("Binding default DocumentLoader.") context.injector.bind_instance(DocumentLoader, DocumentLoader(self.root_profile)) # Admin API if context.settings.get("admin.enabled"): - LOGGER.trace("Admin API is enabled. Attempting to register admin server.") + LOGGER.debug("Admin API is enabled. Attempting to register admin server.") try: admin_host = context.settings.get("admin.host", "0.0.0.0") admin_port = context.settings.get("admin.port", "80") @@ -299,7 +296,7 @@ async def setup(self): # Fetch stats collector, if any collector = context.inject_or(Collector) if collector: - LOGGER.trace("Stats collector found. Wrapping methods for collection.") + LOGGER.debug("Stats collector found. Wrapping methods for collection.") # add stats to our own methods collector.wrap( self, @@ -318,35 +315,35 @@ async def setup(self): "find_inbound_connection", ), ) - LOGGER.trace("Methods wrapped with stats collector.") + LOGGER.debug("Methods wrapped with stats collector.") async def start(self) -> None: """Start the agent.""" LOGGER.debug("Starting the Conductor agent.") context = self.root_profile.context await self.check_for_valid_wallet_type(self.root_profile) - LOGGER.trace("Wallet type validated.") + LOGGER.debug("Wallet type validated.") if not context.settings.get("transport.disabled"): # Start up transports if enabled try: - LOGGER.trace("Transport not disabled. Starting inbound transports.") + LOGGER.debug("Transport not disabled. Starting inbound transports.") await self.inbound_transport_manager.start() - LOGGER.trace("Inbound transports started successfully.") + LOGGER.debug("Inbound transports started successfully.") except Exception: LOGGER.exception("Unable to start inbound transports.") raise try: - LOGGER.trace("Starting outbound transports.") + LOGGER.debug("Starting outbound transports.") await self.outbound_transport_manager.start() - LOGGER.trace("Outbound transports started successfully.") + LOGGER.debug("Outbound transports started successfully.") except Exception: LOGGER.exception("Unable to start outbound transports.") raise # Start up Admin server if self.admin_server: - LOGGER.trace("Admin server present. Starting admin server.") + LOGGER.debug("Admin server present. Starting admin server.") try: await self.admin_server.start() LOGGER.debug("Admin server started successfully.") @@ -360,7 +357,7 @@ async def start(self) -> None: self.admin_server.outbound_message_router, ) context.injector.bind_instance(BaseResponder, responder) - LOGGER.trace("Admin responder bound to injector.") + LOGGER.debug("Admin responder bound to injector.") # Get agent label default_label = context.settings.get("default_label") @@ -389,7 +386,7 @@ async def start(self) -> None: from_version_storage = None from_version = None agent_version = f"v{__version__}" - LOGGER.trace("Recording ACA-Py version in wallet if needed.") + LOGGER.debug("Recording ACA-Py version in wallet if needed.") async with self.root_profile.session() as session: storage: BaseStorage = session.context.inject(BaseStorage) try: @@ -409,7 +406,7 @@ async def start(self) -> None: force_upgrade_flag = ( self.root_profile.settings.get("upgrade.force_upgrade") or False ) - LOGGER.trace( + LOGGER.debug( "Force upgrade flag: %s, From version config: %s", force_upgrade_flag, from_version_config, @@ -425,12 +422,12 @@ async def start(self) -> None: from_version = from_version_storage else: from_version = from_version_config - LOGGER.trace( + LOGGER.debug( "Determined from_version based on force_upgrade: %s", from_version ) else: from_version = from_version_storage or from_version_config - LOGGER.trace("Determined from_version: %s", from_version) + LOGGER.debug("Determined from_version: %s", from_version) if not from_version: LOGGER.warning( @@ -442,13 +439,13 @@ async def start(self) -> None: ) from_version = DEFAULT_ACAPY_VERSION self.root_profile.settings.set_value("upgrade.from_version", from_version) - LOGGER.trace("Set upgrade.from_version to default: %s", from_version) + LOGGER.debug("Set upgrade.from_version to default: %s", from_version) config_available_list = get_upgrade_version_list( config_path=self.root_profile.settings.get("upgrade.config_path"), from_version=from_version, ) - LOGGER.trace("Available upgrade versions: %s", config_available_list) + LOGGER.debug("Available upgrade versions: %s", config_available_list) if len(config_available_list) >= 1: LOGGER.info("Upgrade configurations available. Initiating upgrade.") @@ -521,7 +518,6 @@ async def start(self) -> None: qr.add_data(invite_url) qr.print_ascii(invert=True) del mgr - LOGGER.trace("Invitation created and QR code printed.") except Exception: LOGGER.exception("Error creating invitation.") @@ -548,9 +544,6 @@ async def start(self) -> None: qr.add_data(invite_url) qr.print_ascii(invert=True) del mgr - LOGGER.trace( - "Connections protocol invitation created and QR code printed." - ) except Exception: LOGGER.exception("Error creating connections protocol invitation.") @@ -579,7 +572,7 @@ async def start(self) -> None: mediation_connections_invite = context.settings.get( "mediation.connections_invite", False ) - LOGGER.trace( + LOGGER.debug( "Mediation connections invite flag: %s", mediation_connections_invite ) invitation_handler = ( @@ -590,7 +583,7 @@ async def start(self) -> None: if not mediation_invite_record.used: # clear previous mediator configuration before establishing a new one - LOGGER.trace( + LOGGER.debug( "Mediation invite not used. " "Clearing default mediator before accepting new invite." ) @@ -612,7 +605,7 @@ async def start(self) -> None: await MediationInviteStore( session.context.inject(BaseStorage) ).mark_default_invite_as_used() - LOGGER.trace("Marked mediation invite as used.") + LOGGER.debug("Marked mediation invite as used.") await record.metadata_set( session, MediationManager.SEND_REQ_AFTER_CONNECTION, True @@ -620,11 +613,11 @@ async def start(self) -> None: await record.metadata_set( session, MediationManager.SET_TO_DEFAULT_ON_GRANTED, True ) - LOGGER.trace("Set mediation metadata after connection.") + LOGGER.debug("Set mediation metadata after connection.") LOGGER.info("Attempting to connect to mediator...") del mgr - LOGGER.trace("Mediation manager deleted after setting up mediator.") + LOGGER.debug("Mediation manager deleted after setting up mediator.") except Exception: LOGGER.exception("Error accepting mediation invitation.") @@ -638,7 +631,7 @@ async def start(self) -> None: ) # notify protocols of startup status - LOGGER.trace("Notifying protocols of startup status.") + LOGGER.debug("Notifying protocols of startup status.") await self.root_profile.notify(STARTUP_EVENT_TOPIC, {}) LOGGER.debug("Startup notification sent.") @@ -653,16 +646,16 @@ async def stop(self, timeout=1.0): shutdown = TaskQueue() if self.dispatcher: - LOGGER.trace("Initiating shutdown of dispatcher.") + LOGGER.debug("Initiating shutdown of dispatcher.") shutdown.run(self.dispatcher.complete()) if self.admin_server: - LOGGER.trace("Initiating shutdown of admin server.") + LOGGER.debug("Initiating shutdown of admin server.") shutdown.run(self.admin_server.stop()) if self.inbound_transport_manager: - LOGGER.trace("Initiating shutdown of inbound transport manager.") + LOGGER.debug("Initiating shutdown of inbound transport manager.") shutdown.run(self.inbound_transport_manager.stop()) if self.outbound_transport_manager: - LOGGER.trace("Initiating shutdown of outbound transport manager.") + LOGGER.debug("Initiating shutdown of outbound transport manager.") shutdown.run(self.outbound_transport_manager.stop()) if self.root_profile: @@ -671,12 +664,12 @@ async def stop(self, timeout=1.0): if multitenant_mgr: LOGGER.debug("Closing multitenant profiles.") for profile in multitenant_mgr.open_profiles: - LOGGER.trace("Closing profile: %s", profile.name) + LOGGER.debug("Closing profile: %s", profile.name) shutdown.run(profile.close()) LOGGER.debug("Closing root profile.") shutdown.run(self.root_profile.close()) - LOGGER.trace("Waiting for shutdown tasks to complete with timeout=%f.", timeout) + LOGGER.debug("Waiting for shutdown tasks to complete with timeout=%f.", timeout) await shutdown.complete(timeout) LOGGER.info("Conductor agent stopped successfully.") diff --git a/acapy_agent/core/plugin_registry.py b/acapy_agent/core/plugin_registry.py index 542203c819..4b6b31d99e 100644 --- a/acapy_agent/core/plugin_registry.py +++ b/acapy_agent/core/plugin_registry.py @@ -6,7 +6,6 @@ from typing import Optional, Sequence, Set from ..config.injection_context import InjectionContext -from ..config.logging.utils import add_trace_level from ..core.event_bus import EventBus from ..utils.classloader import ClassLoader, ModuleLoadError from .error import ProtocolDefinitionValidationError @@ -14,7 +13,6 @@ from .protocol_registry import ProtocolRegistry LOGGER = logging.getLogger(__name__) -add_trace_level() # Allow trace logs from this module class PluginRegistry: @@ -132,7 +130,7 @@ def register_plugin(self, module_name: str) -> Optional[ModuleType]: if self._is_valid_plugin(mod, module_name): self._plugins[module_name] = mod - LOGGER.trace("Registered plugin: %s", module_name) + LOGGER.debug("Registered plugin: %s", module_name) return mod LOGGER.debug("Failed to register plugin: %s", module_name) @@ -141,7 +139,7 @@ def register_plugin(self, module_name: str) -> Optional[ModuleType]: def _is_already_registered(self, module_name: str) -> bool: """Check if the plugin is already registered.""" if module_name in self._plugins: - LOGGER.trace("Plugin %s is already registered.", module_name) + LOGGER.debug("Plugin %s is already registered.", module_name) return True return False @@ -165,7 +163,7 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: """Validate the plugin based on various criteria.""" # Check if the plugin has a 'setup' method if hasattr(mod, "setup"): - LOGGER.trace("Plugin %s has a 'setup' method.", module_name) + LOGGER.debug("Plugin %s has a 'setup' method.", module_name) return True # Check for 'routes' or 'message_types' modules @@ -174,7 +172,7 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: routes = ClassLoader.load_module("routes", module_name) message_types = ClassLoader.load_module("message_types", module_name) if routes or message_types: - LOGGER.trace("Plugin %s has 'routes' or 'message_types'.", module_name) + LOGGER.debug("Plugin %s has 'routes' or 'message_types'.", module_name) return True # Check for 'definition' module with 'versions' attribute @@ -196,7 +194,7 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: # Validate the 'versions' attribute try: self.validate_version(definition.versions, module_name) - LOGGER.trace("Plugin %s has valid versions.", module_name) + LOGGER.debug("Plugin %s has valid versions.", module_name) return True except ProtocolDefinitionValidationError as e: LOGGER.error( @@ -208,7 +206,7 @@ def _is_valid_plugin(self, mod: ModuleType, module_name: str) -> bool: def register_package(self, package_name: str) -> Sequence[ModuleType]: """Register all modules (sub-packages) under a given package name.""" - LOGGER.trace("Registering package: %s", package_name) + LOGGER.debug("Registering package: %s", package_name) try: module_names = ClassLoader.scan_subpackages(package_name) except ModuleLoadError: @@ -219,28 +217,28 @@ def register_package(self, package_name: str) -> Sequence[ModuleType]: for module_name in module_names: # Skip any module whose last segment is 'tests' if module_name.split(".")[-1] == "tests": - LOGGER.trace("Skipping test module: %s", module_name) + LOGGER.debug("Skipping test module: %s", module_name) continue plugin = self.register_plugin(module_name) if plugin: registered_plugins.append(plugin) else: - LOGGER.trace("Failed to register %s under %s", module_name, package_name) + LOGGER.debug("Failed to register %s under %s", module_name, package_name) return registered_plugins async def init_context(self, context: InjectionContext) -> None: """Call plugin setup methods on the current context.""" - LOGGER.trace("Initializing plugin context for %d plugins", len(self._plugins)) + LOGGER.debug("Initializing plugin context for %d plugins", len(self._plugins)) for plugin in self._plugins.values(): plugin_name = plugin.__name__ if hasattr(plugin, "setup"): - LOGGER.trace("Running setup for plugin: %s", plugin_name) + LOGGER.debug("Running setup for plugin: %s", plugin_name) await plugin.setup(context) else: - LOGGER.trace( + LOGGER.debug( "Loading protocols for plugin without setup: %s", plugin_name ) await self.load_protocols(context, plugin) @@ -259,55 +257,55 @@ async def load_protocol_version( goal_code_registry = context.inject(GoalCodeRegistry) module_name = mod.__name__ - LOGGER.trace("Loading protocol version for module: %s", module_name) + LOGGER.debug("Loading protocol version for module: %s", module_name) if hasattr(mod, "MESSAGE_TYPES"): - LOGGER.trace("Registering message types for: %s", module_name) + LOGGER.debug("Registering message types for: %s", module_name) protocol_registry.register_message_types( mod.MESSAGE_TYPES, version_definition=version_definition ) if hasattr(mod, "CONTROLLERS"): - LOGGER.trace("Registering controllers for: %s", module_name) + LOGGER.debug("Registering controllers for: %s", module_name) protocol_registry.register_controllers(mod.CONTROLLERS) goal_code_registry.register_controllers(mod.CONTROLLERS) async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> None: """For modules that don't implement setup, register protocols manually.""" plugin_name = plugin.__name__ - LOGGER.trace("Loading protocols for plugin: %s", plugin_name) + LOGGER.debug("Loading protocols for plugin: %s", plugin_name) # If this module contains message_types, then assume that # this is a valid module of the old style (not versioned) try: message_types_path = f"{plugin_name}.message_types" - LOGGER.trace("Attempting to load message types from: %s", message_types_path) + LOGGER.debug("Attempting to load message types from: %s", message_types_path) mod = ClassLoader.load_module(message_types_path) except ModuleLoadError as e: LOGGER.error("Error loading plugin module message types: %s", e) return if mod: - LOGGER.trace("Found non-versioned message types for: %s", plugin_name) + LOGGER.debug("Found non-versioned message types for: %s", plugin_name) await self.load_protocol_version(context, mod) else: # Otherwise, try check for definition.py for versioned protocol packages try: definition_path = f"{plugin_name}.definition" - LOGGER.trace("Attempting to load definition from: %s", definition_path) + LOGGER.debug("Attempting to load definition from: %s", definition_path) definition = ClassLoader.load_module(definition_path) except ModuleLoadError as e: LOGGER.error("Error loading plugin definition module: %s", e) return if definition: - LOGGER.trace("Loading versioned protocols for: %s", plugin_name) + LOGGER.debug("Loading versioned protocols for: %s", plugin_name) for protocol_version in definition.versions: version_path = ( f"{plugin_name}.{protocol_version['path']}.message_types" ) try: - LOGGER.trace("Loading message types from: %s", version_path) + LOGGER.debug("Loading message types from: %s", version_path) mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: LOGGER.error( @@ -324,20 +322,20 @@ async def load_protocols(self, context: InjectionContext, plugin: ModuleType) -> async def register_admin_routes(self, app) -> None: """Call route registration methods on the current context.""" - LOGGER.trace("Registering admin routes for %d plugins", len(self._plugins)) + LOGGER.debug("Registering admin routes for %d plugins", len(self._plugins)) for plugin in self._plugins.values(): plugin_name = plugin.__name__ - LOGGER.trace("Processing routes for plugin: %s", plugin_name) + LOGGER.debug("Processing routes for plugin: %s", plugin_name) mod = None definition = ClassLoader.load_module("definition", plugin_name) if definition: # Load plugin routes that are in a versioned package. - LOGGER.trace("Loading versioned routes for: %s", plugin_name) + LOGGER.debug("Loading versioned routes for: %s", plugin_name) for plugin_version in definition.versions: version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - LOGGER.trace("Loading routes from: %s", version_path) + LOGGER.debug("Loading routes from: %s", version_path) mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: LOGGER.error( @@ -346,25 +344,25 @@ async def register_admin_routes(self, app) -> None: continue if mod and hasattr(mod, "register"): - LOGGER.trace("Registering routes for: %s", plugin_name) + LOGGER.debug("Registering routes for: %s", plugin_name) await mod.register(app) else: # Load plugin routes that aren't in a versioned package. routes_path = f"{plugin_name}.routes" try: - LOGGER.trace("Loading non-versioned routes from: %s", routes_path) + LOGGER.debug("Loading non-versioned routes from: %s", routes_path) mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: LOGGER.error("Error loading admin routes from %s: %s", routes_path, e) continue if mod and hasattr(mod, "register"): - LOGGER.trace("Registering routes for: %s", plugin_name) + LOGGER.debug("Registering routes for: %s", plugin_name) await mod.register(app) def register_protocol_events(self, context: InjectionContext) -> None: """Call route register_events methods on the current context.""" - LOGGER.trace("Registering protocol events for %d plugins", len(self._plugins)) + LOGGER.debug("Registering protocol events for %d plugins", len(self._plugins)) event_bus = context.inject_or(EventBus) if not event_bus: @@ -373,74 +371,74 @@ def register_protocol_events(self, context: InjectionContext) -> None: for plugin in self._plugins.values(): plugin_name = plugin.__name__ - LOGGER.trace("Processing events for plugin: %s", plugin_name) + LOGGER.debug("Processing events for plugin: %s", plugin_name) mod = None definition = ClassLoader.load_module("definition", plugin_name) if definition: # Load plugin routes that are in a versioned package. - LOGGER.trace("Loading versioned events for: %s", plugin_name) + LOGGER.debug("Loading versioned events for: %s", plugin_name) for plugin_version in definition.versions: version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - LOGGER.trace("Loading events from: %s", version_path) + LOGGER.debug("Loading events from: %s", version_path) mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: LOGGER.error("Error loading events from %s: %s", version_path, e) continue if mod and hasattr(mod, "register_events"): - LOGGER.trace("Registering events from: %s", version_path) + LOGGER.debug("Registering events from: %s", version_path) mod.register_events(event_bus) else: # Load plugin routes that aren't in a versioned package. routes_path = f"{plugin_name}.routes" try: - LOGGER.trace("Loading non-versioned events from: %s", routes_path) + LOGGER.debug("Loading non-versioned events from: %s", routes_path) mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: LOGGER.error("Error loading events from %s: %s", routes_path, e) continue if mod and hasattr(mod, "register_events"): - LOGGER.trace("Registering events from: %s", version_path) + LOGGER.debug("Registering events from: %s", version_path) mod.register_events(event_bus) def post_process_routes(self, app) -> None: """Call route binary file response OpenAPI fixups if applicable.""" - LOGGER.trace("Post-processing routes for %d plugins", len(self._plugins)) + LOGGER.debug("Post-processing routes for %d plugins", len(self._plugins)) for plugin in self._plugins.values(): plugin_name = plugin.__name__ - LOGGER.trace("Post-processing routes for plugin: %s", plugin_name) + LOGGER.debug("Post-processing routes for plugin: %s", plugin_name) mod = None definition = ClassLoader.load_module("definition", plugin_name) if definition: # Set binary file responses for routes that are in a versioned package. - LOGGER.trace("Processing versioned routes for: %s", plugin_name) + LOGGER.debug("Processing versioned routes for: %s", plugin_name) for plugin_version in definition.versions: version_path = f"{plugin_name}.{plugin_version['path']}.routes" try: - LOGGER.trace("Loading routes from: %s", version_path) + LOGGER.debug("Loading routes from: %s", version_path) mod = ClassLoader.load_module(version_path) except ModuleLoadError as e: LOGGER.error("Error loading routes from %s: %s", version_path, e) continue if mod and hasattr(mod, "post_process_routes"): - LOGGER.trace("Post-processing routes for %s", plugin_name) + LOGGER.debug("Post-processing routes for %s", plugin_name) mod.post_process_routes(app) else: # Set binary file responses for routes not in a versioned package. routes_path = f"{plugin_name}.routes" try: - LOGGER.trace("Loading non-versioned routes from: %s", routes_path) + LOGGER.debug("Loading non-versioned routes from: %s", routes_path) mod = ClassLoader.load_module(routes_path) except ModuleLoadError as e: LOGGER.error("Error loading routes from %s: %s", routes_path, e) continue if mod and hasattr(mod, "post_process_routes"): - LOGGER.trace("Post-processing routes for %s", plugin_name) + LOGGER.debug("Post-processing routes for %s", plugin_name) mod.post_process_routes(app) def __repr__(self) -> str: diff --git a/acapy_agent/utils/classloader.py b/acapy_agent/utils/classloader.py index e257abdb3a..b91b65a630 100644 --- a/acapy_agent/utils/classloader.py +++ b/acapy_agent/utils/classloader.py @@ -8,11 +8,9 @@ from types import ModuleType from typing import Optional, Sequence, Type -from ..config.logging.utils import add_trace_level from ..core.error import BaseError LOGGER = logging.getLogger(__name__) -add_trace_level() # Allow trace logs from this module class ModuleLoadError(BaseError): @@ -43,49 +41,53 @@ def load_module( ModuleLoadError: If there was an error loading the module """ - LOGGER.trace("Attempting to load module: %s with package: %s", mod_path, package) + LOGGER.debug( + "Attempting to load module: %s%s", + mod_path, + f" with package: {package}" if package else "", + ) if package: - LOGGER.trace("Preloading parent package: %s", package) + LOGGER.debug("Preloading parent package: %s", package) # preload parent package if not cls.load_module(package): - LOGGER.trace("Failed to preload parent package: %s", package) + LOGGER.debug("Failed to preload parent package: %s", package) return None # must treat as a relative import if not mod_path.startswith("."): mod_path = f".{mod_path}" - LOGGER.trace("Adjusted mod_path for relative import: %s", mod_path) + LOGGER.debug("Adjusted mod_path for relative import: %s", mod_path) full_path = resolve_name(mod_path, package) - LOGGER.trace("Resolved full module path: %s", full_path) + LOGGER.debug("Resolved full module path: %s", full_path) if full_path in sys.modules: - LOGGER.trace("Module %s is already loaded", full_path) + LOGGER.debug("Module %s is already loaded", full_path) return sys.modules[full_path] if "." in mod_path: parent_mod_path, mod_name = mod_path.rsplit(".", 1) - LOGGER.trace( + LOGGER.debug( "Parent module path: %s, Module name: %s", parent_mod_path, mod_name ) if parent_mod_path and parent_mod_path[-1] != ".": parent_mod = cls.load_module(parent_mod_path, package) if not parent_mod: - LOGGER.trace("Failed to load parent module: %s", parent_mod_path) + LOGGER.debug("Failed to load parent module: %s", parent_mod_path) return None package = parent_mod.__name__ mod_path = f".{mod_name}" - LOGGER.trace("Adjusted mod_path after loading parent: %s", mod_path) + LOGGER.debug("Adjusted mod_path after loading parent: %s", mod_path) # Load the module spec first - LOGGER.trace("Finding spec for module: %s with package: %s", mod_path, package) + LOGGER.debug("Finding spec for module: %s with package: %s", mod_path, package) spec = find_spec(mod_path, package) if not spec: - LOGGER.trace("Module spec not found for: %s", mod_path) + LOGGER.debug("Module spec not found for: %s", mod_path) return None try: - LOGGER.trace("Importing module: %s with package: %s", mod_path, package) + LOGGER.debug("Importing module: %s with package: %s", mod_path, package) return import_module(mod_path, package) except ModuleNotFoundError as e: LOGGER.warning("Module %s not found during import", full_path) @@ -114,7 +116,7 @@ def load_class( """ - LOGGER.trace( + LOGGER.debug( "Attempting to load class: %s with default_module: %s and package: %s", class_name, default_module, @@ -124,14 +126,14 @@ def load_class( if "." in class_name: # import module and find class mod_path, class_name = class_name.rsplit(".", 1) - LOGGER.trace( + LOGGER.debug( "Extracted module path: %s, class name: %s from full class path", mod_path, class_name, ) elif default_module: mod_path = default_module - LOGGER.trace("No module in class name, using default_module: %s", mod_path) + LOGGER.debug("No module in class name, using default_module: %s", mod_path) else: LOGGER.warning( "Cannot resolve class name %s with no default module", class_name @@ -160,7 +162,7 @@ def load_class( raise ClassNotFoundError( f"Resolved value is not a class: {mod_path}.{class_name}" ) - LOGGER.trace("Successfully loaded class %s from module %s", class_name, mod_path) + LOGGER.debug("Successfully loaded class %s from module %s", class_name, mod_path) return resolved @classmethod @@ -183,7 +185,7 @@ def load_subclass_of( """ - LOGGER.trace( + LOGGER.debug( "Attempting to load subclass of %s from module %s with package %s", base_class.__name__, mod_path, @@ -201,7 +203,7 @@ def load_subclass_of( # Find the first declared class that inherits from the base_class try: - LOGGER.trace( + LOGGER.debug( "Inspecting classes in module %s for subclasses of %s", mod_path, base_class.__name__, @@ -211,13 +213,13 @@ def load_subclass_of( for name, obj in inspect.getmembers(mod, inspect.isclass) if issubclass(obj, base_class) and obj is not base_class ) - LOGGER.trace( + LOGGER.debug( "Found subclass %s of base class %s", imported_class.__name__, base_class.__name__, ) except StopIteration: - LOGGER.trace( + LOGGER.debug( "No subclass of %s found in module %s", base_class.__name__, mod_path, @@ -233,14 +235,14 @@ def scan_subpackages(cls, package: str) -> Sequence[str]: LOGGER.debug("Scanning subpackages under package %s", package) if "." in package: package, sub_pkg = package.split(".", 1) - LOGGER.trace("Extracted main package: %s, sub-package: %s", package, sub_pkg) + LOGGER.debug("Extracted main package: %s, sub-package: %s", package, sub_pkg) else: sub_pkg = "." - LOGGER.trace("No sub-package provided, defaulting to %s", sub_pkg) + LOGGER.debug("No sub-package provided, defaulting to %s", sub_pkg) try: package_path = resources.files(package) - LOGGER.trace("Found package path: %s", package_path) + LOGGER.debug("Found package path: %s", package_path) except FileNotFoundError: LOGGER.warning("Package %s not found during subpackage scan", package) raise ModuleLoadError(f"Undefined package {package}") @@ -252,12 +254,10 @@ def scan_subpackages(cls, package: str) -> Sequence[str]: found = [] joiner = "" if sub_pkg == "." else f"{sub_pkg}." sub_path = package_path / sub_pkg - LOGGER.trace("Iterating over items in sub-package path: %s", sub_path) for item in sub_path.iterdir(): if (item / "__init__.py").exists(): subpackage = f"{package}.{joiner}{item.name}" found.append(subpackage) - LOGGER.trace("Found sub-package: %s", subpackage) LOGGER.debug("Total sub-packages found under %s: %s", package, found) return found From 523d42944f11171edc45c3c1f15f2671d49d9802 Mon Sep 17 00:00:00 2001 From: ff137 Date: Wed, 27 Nov 2024 13:25:37 +0200 Subject: [PATCH 71/72] :sparkles: Add caching to ClassLoader.load_module Signed-off-by: ff137 --- acapy_agent/utils/classloader.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acapy_agent/utils/classloader.py b/acapy_agent/utils/classloader.py index b91b65a630..83c5648179 100644 --- a/acapy_agent/utils/classloader.py +++ b/acapy_agent/utils/classloader.py @@ -3,6 +3,7 @@ import inspect import logging import sys +from functools import lru_cache from importlib import import_module, resources from importlib.util import find_spec, resolve_name from types import ModuleType @@ -25,6 +26,7 @@ class ClassLoader: """Class used to load classes from modules dynamically.""" @classmethod + @lru_cache def load_module( cls, mod_path: str, package: Optional[str] = None ) -> Optional[ModuleType]: From a2b32ce5c96dd5e790c705c1252a7b6a1fc81b3d Mon Sep 17 00:00:00 2001 From: ff137 Date: Wed, 27 Nov 2024 13:41:16 +0200 Subject: [PATCH 72/72] :art: Improve log Signed-off-by: ff137 --- acapy_agent/utils/classloader.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acapy_agent/utils/classloader.py b/acapy_agent/utils/classloader.py index 83c5648179..ca40073cc2 100644 --- a/acapy_agent/utils/classloader.py +++ b/acapy_agent/utils/classloader.py @@ -119,10 +119,10 @@ def load_class( """ LOGGER.debug( - "Attempting to load class: %s with default_module: %s and package: %s", + "Attempting to load class: %s%s%s", class_name, - default_module, - package, + f", with default_module: {default_module}" if default_module else "", + f", with package: {package}" if package else "", ) if "." in class_name: