From a151623b2578f3430ec77c0fb0509a2cbec73983 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sat, 24 Jan 2026 21:45:00 +0300 Subject: [PATCH] allow setting context after container creation --- README.md | 5 +++++ packages/modern-di/modern_di/container.py | 3 +++ .../modern-di/modern_di/registries/context_registry.py | 10 ++++++---- packages/modern-di/modern_di/types.py | 1 + .../tests_core/providers/test_context_provider.py | 9 +++++++++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5848bab..e0515a5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,11 @@ supports the following: - Fully typed and tested - Integrations with `FastAPI`, `FastStream` and `LiteStar` +Usage examples: + +- with LiteStar - [litestar-sqlalchemy-template](https://github.com/modern-python/litestar-sqlalchemy-template) +- with FastAPI - [fastapi-sqlalchemy-template](https://github.com/modern-python/fastapi-sqlalchemy-template) + ## 📚 [Documentation](https://modern-di.readthedocs.io) ## 📦 [PyPi](https://pypi.org/project/modern-di) diff --git a/packages/modern-di/modern_di/container.py b/packages/modern-di/modern_di/container.py index 64a5703..f534b1b 100644 --- a/packages/modern-di/modern_di/container.py +++ b/packages/modern-di/modern_di/container.py @@ -122,6 +122,9 @@ def reset_override( self.cache_registry.clear_kwargs() return self.providers_registry.reset_override(dependency_name=dependency_name, dependency_type=dependency_type) + def set_context(self, context_type: type[types.T], obj: types.T) -> None: + self.context_registry.set_context(context_type, obj) + def __deepcopy__(self, *_: object, **__: object) -> "typing_extensions.Self": """Prevent cloning object.""" return self diff --git a/packages/modern-di/modern_di/registries/context_registry.py b/packages/modern-di/modern_di/registries/context_registry.py index 282db36..3c78256 100644 --- a/packages/modern-di/modern_di/registries/context_registry.py +++ b/packages/modern-di/modern_di/registries/context_registry.py @@ -1,16 +1,18 @@ import dataclasses import typing - -T = typing.TypeVar("T") +from modern_di import types @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) class ContextRegistry: context: dict[type[typing.Any], typing.Any] - def find_context(self, context_type: type[T]) -> T | None: + def find_context(self, context_type: type[types.T]) -> types.T | None: if context_type and (context := self.context.get(context_type)): - return typing.cast(T, context) + return typing.cast(types.T, context) return None + + def set_context(self, context_type: type[types.T], obj: types.T) -> None: + self.context[context_type] = obj diff --git a/packages/modern-di/modern_di/types.py b/packages/modern-di/modern_di/types.py index 69f155b..8d51f0e 100644 --- a/packages/modern-di/modern_di/types.py +++ b/packages/modern-di/modern_di/types.py @@ -2,5 +2,6 @@ T_co = typing.TypeVar("T_co", covariant=True) +T = typing.TypeVar("T") P = typing.ParamSpec("P") UNSET = object() diff --git a/packages/modern-di/tests_core/providers/test_context_provider.py b/packages/modern-di/tests_core/providers/test_context_provider.py index 1846658..4bb1047 100644 --- a/packages/modern-di/tests_core/providers/test_context_provider.py +++ b/packages/modern-di/tests_core/providers/test_context_provider.py @@ -15,6 +15,15 @@ def test_context_provider() -> None: assert instance1 is instance2 is now +def test_context_provider_set_context_after_creation() -> None: + now = datetime.datetime.now(tz=datetime.timezone.utc) + app_container = Container() + app_container.set_context(datetime.datetime, now) + instance1 = app_container.resolve_provider(context_provider) + instance2 = app_container.resolve_provider(context_provider) + assert instance1 is instance2 is now + + def test_context_provider_not_found() -> None: app_container = Container() assert app_container.resolve_provider(context_provider) is None