From 43941999e4354c6e4a2deee9cb4fb0fc0c654e98 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Tue, 28 May 2024 22:42:18 -0400 Subject: [PATCH 1/3] feat: inject profile and session Signed-off-by: Daniel Bluhm --- aries_cloudagent/core/profile.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/aries_cloudagent/core/profile.py b/aries_cloudagent/core/profile.py index d3bdfe2aeb..8b8a49529f 100644 --- a/aries_cloudagent/core/profile.py +++ b/aries_cloudagent/core/profile.py @@ -1,8 +1,9 @@ """Classes for managing profile information within a request context.""" -import logging from abc import ABC, abstractmethod +import logging from typing import Any, Mapping, Optional, Type +from weakref import ref from ..config.base import InjectionError from ..config.injection_context import InjectionContext @@ -30,10 +31,16 @@ def __init__( created: bool = False, ): """Initialize a base profile.""" - self._context = context or InjectionContext() self._created = created self._name = name or Profile.DEFAULT_NAME + context = context or InjectionContext() + scope = "profile:" + self._name + if sub := context.settings.get("wallet.id"): + scope += ":" + sub + self._context = context.start_scope(scope) + self._context.injector.bind_instance(Profile, ref(self)) + @property def backend(self) -> str: """Accessor for the backend implementation name.""" @@ -163,6 +170,8 @@ def __init__( self._profile = profile self._events = [] + self._context.injector.bind_instance(ProfileSession, ref(self)) + async def _setup(self): """Create the underlying session or transaction.""" From 16d8169ad1c55d12da760ddd5053b03cdb3feafc Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Tue, 28 May 2024 22:54:43 -0400 Subject: [PATCH 2/3] fix: bad test value in didex Signed-off-by: Daniel Bluhm --- .../protocols/didexchange/v1_0/tests/test_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aries_cloudagent/protocols/didexchange/v1_0/tests/test_manager.py b/aries_cloudagent/protocols/didexchange/v1_0/tests/test_manager.py index f3c5d6d969..405f912a35 100644 --- a/aries_cloudagent/protocols/didexchange/v1_0/tests/test_manager.py +++ b/aries_cloudagent/protocols/didexchange/v1_0/tests/test_manager.py @@ -99,7 +99,7 @@ async def asyncSetUp(self): "debug.auto_accept_invites": True, "debug.auto_accept_requests": True, "multitenant.enabled": True, - "wallet.id": True, + "wallet.id": "test-wallet-id", }, bind={ BaseResponder: self.responder, From 94d41be80a518dfb3a864904bee3b4bbbac4c99f Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 29 May 2024 13:19:53 -0400 Subject: [PATCH 3/3] refactor: remove named scopes Signed-off-by: Daniel Bluhm --- aries_cloudagent/admin/request_context.py | 16 +++---- aries_cloudagent/config/injection_context.py | 47 +++---------------- aries_cloudagent/config/injector.py | 9 ++-- .../config/tests/test_injection_context.py | 32 ++----------- aries_cloudagent/core/profile.py | 7 +-- aries_cloudagent/messaging/request_context.py | 6 +-- 6 files changed, 29 insertions(+), 88 deletions(-) diff --git a/aries_cloudagent/admin/request_context.py b/aries_cloudagent/admin/request_context.py index 159334c685..215a64f3bb 100644 --- a/aries_cloudagent/admin/request_context.py +++ b/aries_cloudagent/admin/request_context.py @@ -21,13 +21,13 @@ def __init__( self, profile: Profile, *, - context: InjectionContext = None, - settings: Mapping[str, object] = None, - root_profile: Profile = None, - metadata: dict = None + context: Optional[InjectionContext] = None, + settings: Optional[Mapping[str, object]] = None, + root_profile: Optional[Profile] = None, + metadata: Optional[dict] = None ): """Initialize an instance of AdminRequestContext.""" - self._context = (context or profile.context).start_scope("admin", settings) + self._context = (context or profile.context).start_scope(settings) self._profile = profile self._root_profile = root_profile self._metadata = metadata @@ -72,7 +72,7 @@ def transaction(self) -> ProfileSession: def inject( self, base_cls: Type[InjectType], - settings: Mapping[str, object] = None, + settings: Optional[Mapping[str, object]] = None, ) -> InjectType: """Get the provided instance of a given class identifier. @@ -89,7 +89,7 @@ def inject( def inject_or( self, base_cls: Type[InjectType], - settings: Mapping[str, object] = None, + settings: Optional[Mapping[str, object]] = None, default: Optional[InjectType] = None, ) -> Optional[InjectType]: """Get the provided instance of a given class identifier or default if not found. @@ -111,7 +111,7 @@ def update_settings(self, settings: Mapping[str, object]): @classmethod def test_context( - cls, session_inject: dict = None, profile: Profile = None + cls, session_inject: Optional[dict] = None, profile: Optional[Profile] = None ) -> "AdminRequestContext": """Quickly set up a new admin request context for tests.""" ctx = AdminRequestContext(profile or IN_MEM.resolved.test_profile()) diff --git a/aries_cloudagent/config/injection_context.py b/aries_cloudagent/config/injection_context.py index fdadc88224..bdd91de149 100644 --- a/aries_cloudagent/config/injection_context.py +++ b/aries_cloudagent/config/injection_context.py @@ -21,12 +21,14 @@ class InjectionContext(BaseInjector): ROOT_SCOPE = "application" def __init__( - self, *, settings: Mapping[str, object] = None, enforce_typing: bool = True + self, + *, + settings: Optional[Mapping[str, object]] = None, + enforce_typing: bool = True ): """Initialize a `ServiceConfig`.""" self._injector = Injector(settings, enforce_typing=enforce_typing) self._scope_name = InjectionContext.ROOT_SCOPE - self._scopes = [] @property def injector(self) -> Injector: @@ -38,16 +40,6 @@ def injector(self, injector: Injector): """Setter for scope-specific injector.""" self._injector = injector - @property - def scope_name(self) -> str: - """Accessor for the current scope name.""" - return self._scope_name - - @scope_name.setter - def scope_name(self, scope_name: str): - """Accessor for the current scope name.""" - self._scope_name = scope_name - @property def settings(self) -> Settings: """Accessor for scope-specific settings.""" @@ -64,7 +56,7 @@ def update_settings(self, settings: Mapping[str, object]): self.injector.settings.update(settings) def start_scope( - self, scope_name: str, settings: Optional[Mapping[str, object]] = None + self, settings: Optional[Mapping[str, object]] = None ) -> "InjectionContext": """Begin a new named scope. @@ -76,39 +68,15 @@ def start_scope( A new injection context representing the scope """ - if not scope_name: - raise InjectionContextError("Scope name must be non-empty") - if self._scope_name == scope_name: - raise InjectionContextError("Cannot re-enter scope: {}".format(scope_name)) - for scope in self._scopes: - if scope.name == scope_name: - raise InjectionContextError( - "Cannot re-enter scope: {}".format(scope_name) - ) result = self.copy() - result._scopes.append(Scope(name=self.scope_name, injector=self.injector)) - result._scope_name = scope_name if settings: result.update_settings(settings) return result - def injector_for_scope(self, scope_name: str) -> Injector: - """Fetch the injector for a specific scope. - - Args: - scope_name: The unique scope identifier - """ - if scope_name == self.scope_name: - return self.injector - for scope in self._scopes: - if scope.name == scope_name: - return scope.injector - return None - def inject( self, base_cls: Type[InjectType], - settings: Mapping[str, object] = None, + settings: Optional[Mapping[str, object]] = None, ) -> InjectType: """Get the provided instance of a given class identifier. @@ -125,7 +93,7 @@ def inject( def inject_or( self, base_cls: Type[InjectType], - settings: Mapping[str, object] = None, + settings: Optional[Mapping[str, object]] = None, default: Optional[InjectType] = None, ) -> Optional[InjectType]: """Get the provided instance of a given class identifier or default if not found. @@ -145,5 +113,4 @@ def copy(self) -> "InjectionContext": """Produce a copy of the injector instance.""" result = copy.copy(self) result._injector = self.injector.copy() - result._scopes = self._scopes.copy() return result diff --git a/aries_cloudagent/config/injector.py b/aries_cloudagent/config/injector.py index 4d99f8d09c..9c47bd1ec5 100644 --- a/aries_cloudagent/config/injector.py +++ b/aries_cloudagent/config/injector.py @@ -11,7 +11,10 @@ class Injector(BaseInjector): """Injector implementation with static and dynamic bindings.""" def __init__( - self, settings: Mapping[str, object] = None, *, enforce_typing: bool = True + self, + settings: Optional[Mapping[str, object]] = None, + *, + enforce_typing: bool = True, ): """Initialize an `Injector`.""" self.enforce_typing = enforce_typing @@ -54,7 +57,7 @@ def get_provider(self, base_cls: Type[InjectType]): def inject_or( self, base_cls: Type[InjectType], - settings: Mapping[str, object] = None, + settings: Optional[Mapping[str, object]] = None, default: Optional[InjectType] = None, ) -> Optional[InjectType]: """Get the provided instance of a given class identifier or default if not found. @@ -92,7 +95,7 @@ def inject_or( def inject( self, base_cls: Type[InjectType], - settings: Mapping[str, object] = None, + settings: Optional[Mapping[str, object]] = None, ) -> InjectType: """Get the provided instance of a given class identifier. diff --git a/aries_cloudagent/config/tests/test_injection_context.py b/aries_cloudagent/config/tests/test_injection_context.py index e6bd1fd4f0..f68c7f6948 100644 --- a/aries_cloudagent/config/tests/test_injection_context.py +++ b/aries_cloudagent/config/tests/test_injection_context.py @@ -1,7 +1,7 @@ from unittest import IsolatedAsyncioTestCase from ..base import InjectionError -from ..injection_context import InjectionContext, InjectionContextError +from ..injection_context import InjectionContext class TestInjectionContext(IsolatedAsyncioTestCase): @@ -14,39 +14,16 @@ def setUp(self): def test_settings_init(self): """Test settings initialization.""" - assert self.test_instance.scope_name == self.test_instance.ROOT_SCOPE for key in self.test_settings: assert key in self.test_instance.settings assert self.test_instance.settings[key] == self.test_settings[key] - def test_simple_scope(self): - """Test scope entrance and exit.""" - with self.assertRaises(InjectionContextError): - self.test_instance.start_scope(None) - with self.assertRaises(InjectionContextError): - self.test_instance.start_scope(self.test_instance.ROOT_SCOPE) - - injector = self.test_instance.injector_for_scope(self.test_instance.ROOT_SCOPE) - assert injector == self.test_instance.injector - assert self.test_instance.injector_for_scope("no such scope") is None - - context = self.test_instance.start_scope(self.test_scope) - assert context.scope_name == self.test_scope - context.scope_name = "Bob" - assert context.scope_name == "Bob" - - with self.assertRaises(InjectionContextError): - context.start_scope(self.test_instance.ROOT_SCOPE) - assert self.test_instance.scope_name == self.test_instance.ROOT_SCOPE - def test_settings_scope(self): """Test scoped settings.""" upd_settings = {self.test_key: "NEWVAL"} - context = self.test_instance.start_scope(self.test_scope, upd_settings) + context = self.test_instance.start_scope(upd_settings) assert context.settings[self.test_key] == "NEWVAL" assert self.test_instance.settings[self.test_key] == self.test_value - root = context.injector_for_scope(context.ROOT_SCOPE) - assert root.settings[self.test_key] == self.test_value context.settings = upd_settings assert context.settings == upd_settings @@ -64,11 +41,8 @@ async def test_inject_simple(self): async def test_inject_scope(self): """Test a scoped injection.""" - context = self.test_instance.start_scope(self.test_scope) + context = self.test_instance.start_scope() assert context.inject_or(str) is None context.injector.bind_instance(str, self.test_value) assert context.inject(str) is self.test_value assert self.test_instance.inject_or(str) is None - root = context.injector_for_scope(context.ROOT_SCOPE) - assert root.inject_or(str) is None - assert self.test_instance.inject_or(str) is None diff --git a/aries_cloudagent/core/profile.py b/aries_cloudagent/core/profile.py index 8b8a49529f..7030769003 100644 --- a/aries_cloudagent/core/profile.py +++ b/aries_cloudagent/core/profile.py @@ -35,10 +35,7 @@ def __init__( self._name = name or Profile.DEFAULT_NAME context = context or InjectionContext() - scope = "profile:" + self._name - if sub := context.settings.get("wallet.id"): - scope += ":" + sub - self._context = context.start_scope(scope) + self._context = context.start_scope() self._context.injector.bind_instance(Profile, ref(self)) @property @@ -166,7 +163,7 @@ def __init__( self._active = False self._awaited = False self._entered = 0 - self._context = (context or profile.context).start_scope("session", settings) + self._context = (context or profile.context).start_scope(settings) self._profile = profile self._events = [] diff --git a/aries_cloudagent/messaging/request_context.py b/aries_cloudagent/messaging/request_context.py index c96fb2e334..171085c4bc 100644 --- a/aries_cloudagent/messaging/request_context.py +++ b/aries_cloudagent/messaging/request_context.py @@ -26,13 +26,13 @@ def __init__( self, profile: Profile, *, - context: InjectionContext = None, - settings: Mapping[str, object] = None + context: Optional[InjectionContext] = None, + settings: Optional[Mapping[str, object]] = None ): """Initialize an instance of RequestContext.""" self._connection_ready = False self._connection_record = None - self._context = (context or profile.context).start_scope("request", settings) + self._context = (context or profile.context).start_scope(settings) self._message = None self._message_receipt = None self._profile = profile