Skip to content

Commit 7b1aee7

Browse files
author
remimd
committed
docstring
1 parent 69c6688 commit 7b1aee7

2 files changed

Lines changed: 70 additions & 10 deletions

File tree

cq/_core/di.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,60 @@
66
from typing import TYPE_CHECKING, Any, AsyncContextManager, Protocol, runtime_checkable
77

88
if TYPE_CHECKING:
9-
from cq._core.message import CommandBus, EventBus, QueryBus
9+
from cq import CommandBus, EventBus, QueryBus
1010

1111

1212
@runtime_checkable
1313
class DIAdapter(Protocol):
14+
"""
15+
Protocol for integrating a dependency injection container with python-cq.
16+
17+
Implement this protocol to connect your DI framework to the CQ buses.
18+
A concrete implementation (``InjectionAdapter``) is provided via the
19+
``python-cq[injection]`` extra for projects that use *python-injection*.
20+
"""
21+
1422
__slots__ = ()
1523

1624
@abstractmethod
1725
def command_scope(self) -> AsyncContextManager[None]:
26+
"""
27+
Return an async context manager that delimits the lifetime of a
28+
command dispatch.
29+
30+
**Responsibilities**
31+
32+
The scope must at minimum manage the lifecycle of a ``RelatedEvents``
33+
instance and register it so that it is resolvable via injection for
34+
the duration of the scope.
35+
36+
**Nested calls**
37+
38+
``command_scope`` is entered in two distinct situations:
39+
40+
1. Around a standard command dispatch (via
41+
``CommandDispatchScopeMiddleware``).
42+
2. Around each step of a ``ContextCommandPipeline``, which itself
43+
wraps a command dispatch.
44+
45+
This means two nested calls can occur for a single logical command.
46+
Implementations must detect re-entrant activation (e.g. a scope
47+
already active on the current task) and silently ignore the inner
48+
call instead of opening a second, conflicting scope.
49+
"""
50+
1851
raise NotImplementedError
1952

2053
@abstractmethod
2154
def lazy[T](self, tp: type[T]) -> Callable[[], Awaitable[T]]:
55+
"""
56+
Return a callable that resolves an instance of ``tp`` in two steps.
57+
58+
1. ``lazy(tp)`` obtains a resolver from the DI framework for ``tp``.
59+
2. Calling and awaiting the returned callable performs the actual
60+
resolution and returns the instance.
61+
"""
62+
2263
raise NotImplementedError
2364

2465
def register_defaults(
@@ -27,10 +68,29 @@ def register_defaults(
2768
event_bus: Callable[..., EventBus],
2869
query_bus: Callable[..., QueryBus[Any]],
2970
) -> None:
71+
"""
72+
Register the CQ buses as default providers in the DI container.
73+
74+
Called once during setup so that handlers and middlewares can
75+
declare ``CommandBus``, ``EventBus``, or ``QueryBus`` as
76+
constructor dependencies and receive the configured instances.
77+
78+
The default implementation is a no-op for adapters that do not
79+
need automatic bus registration.
80+
"""
81+
3082
return
3183

3284
@abstractmethod
3385
def wire[T](self, tp: type[T]) -> Callable[..., Awaitable[T]]:
86+
"""
87+
Return an async factory that instantiates ``tp`` with injected
88+
dependencies.
89+
90+
Used internally to build handler instances whose dependencies are
91+
resolved by the container.
92+
"""
93+
3494
raise NotImplementedError
3595

3696

uv.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)