Skip to content

Commit bd15555

Browse files
authored
refactoring: ♻️ Context instantiation is now optional
1 parent affa3c3 commit bd15555

File tree

6 files changed

+153
-127
lines changed

6 files changed

+153
-127
lines changed

cq/_core/dispatcher/pipe.py

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from collections import deque
22
from collections.abc import Awaitable, Callable
33
from dataclasses import dataclass, field
4-
from typing import Any, Protocol, Self, overload
4+
from typing import TYPE_CHECKING, Any, Protocol, Self, overload
55

66
from cq._core.dispatcher.base import BaseDispatcher, Dispatcher
77
from cq._core.middleware import Middleware
@@ -34,23 +34,25 @@ def __init__(self, dispatcher: Dispatcher[Any, Any]) -> None:
3434
self.__dispatcher = dispatcher
3535
self.__steps = []
3636

37-
@overload
38-
def step[T](
39-
self,
40-
wrapped: PipeConverter[T, Any],
41-
/,
42-
*,
43-
dispatcher: Dispatcher[T, Any] | None = ...,
44-
) -> PipeConverter[T, Any]: ...
45-
46-
@overload
47-
def step[T](
48-
self,
49-
wrapped: None = ...,
50-
/,
51-
*,
52-
dispatcher: Dispatcher[T, Any] | None = ...,
53-
) -> Callable[[PipeConverter[T, Any]], PipeConverter[T, Any]]: ...
37+
if TYPE_CHECKING: # pragma: no cover
38+
39+
@overload
40+
def step[T](
41+
self,
42+
wrapped: PipeConverter[T, Any],
43+
/,
44+
*,
45+
dispatcher: Dispatcher[T, Any] | None = ...,
46+
) -> PipeConverter[T, Any]: ...
47+
48+
@overload
49+
def step[T](
50+
self,
51+
wrapped: None = ...,
52+
/,
53+
*,
54+
dispatcher: Dispatcher[T, Any] | None = ...,
55+
) -> Callable[[PipeConverter[T, Any]], PipeConverter[T, Any]]: ...
5456

5557
def step[T](
5658
self,
@@ -114,23 +116,33 @@ def __init__(self, dispatcher: Dispatcher[Any, Any]) -> None:
114116
self.__middlewares = deque()
115117
self.__steps = []
116118

117-
@overload
118-
def __get__[O](
119-
self,
120-
instance: O,
121-
owner: type[O] | None = ...,
122-
) -> Dispatcher[I, O]: ...
119+
if TYPE_CHECKING: # pragma: no cover
120+
121+
@overload
122+
def __get__[O](self, instance: None, owner: type[O], /) -> Dispatcher[I, O]: ...
123123

124-
@overload
125-
def __get__(self, instance: None = ..., owner: type | None = ...) -> Self: ...
124+
@overload
125+
def __get__[O](
126+
self,
127+
instance: O,
128+
owner: type[O] | None = ...,
129+
/,
130+
) -> Dispatcher[I, O]: ...
131+
132+
@overload
133+
def __get__(self, instance: None = ..., owner: None = ..., /) -> Self: ...
126134

127135
def __get__[O](
128136
self,
129137
instance: O | None = None,
130138
owner: type[O] | None = None,
139+
/,
131140
) -> Self | Dispatcher[I, O]:
132141
if instance is None:
133-
return self
142+
if owner is None:
143+
return self
144+
145+
instance = owner()
134146

135147
pipeline = self.__new_pipeline(instance, owner)
136148
return BoundContextPipeline(instance, pipeline)
@@ -139,23 +151,25 @@ def add_middlewares(self, *middlewares: Middleware[[I], Any]) -> Self:
139151
self.__middlewares.extendleft(reversed(middlewares))
140152
return self
141153

142-
@overload
143-
def step[T](
144-
self,
145-
wrapped: PipeConverterMethod[T, Any],
146-
/,
147-
*,
148-
dispatcher: Dispatcher[T, Any] | None = ...,
149-
) -> PipeConverterMethod[T, Any]: ...
150-
151-
@overload
152-
def step[T](
153-
self,
154-
wrapped: None = ...,
155-
/,
156-
*,
157-
dispatcher: Dispatcher[T, Any] | None = ...,
158-
) -> Callable[[PipeConverterMethod[T, Any]], PipeConverterMethod[T, Any]]: ...
154+
if TYPE_CHECKING: # pragma: no cover
155+
156+
@overload
157+
def step[T](
158+
self,
159+
wrapped: PipeConverterMethod[T, Any],
160+
/,
161+
*,
162+
dispatcher: Dispatcher[T, Any] | None = ...,
163+
) -> PipeConverterMethod[T, Any]: ...
164+
165+
@overload
166+
def step[T](
167+
self,
168+
wrapped: None = ...,
169+
/,
170+
*,
171+
dispatcher: Dispatcher[T, Any] | None = ...,
172+
) -> Callable[[PipeConverterMethod[T, Any]], PipeConverterMethod[T, Any]]: ...
159173

160174
def step[T](
161175
self,

cq/_core/handler.py

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from functools import partial
66
from inspect import Parameter, getmro, isclass
77
from inspect import signature as inspect_signature
8-
from typing import Any, Protocol, Self, overload, runtime_checkable
8+
from typing import TYPE_CHECKING, Any, Protocol, Self, overload, runtime_checkable
99

1010
import injection
1111

@@ -89,32 +89,34 @@ class HandlerDecorator[I, O]:
8989
manager: HandlerManager[I, O]
9090
injection_module: injection.Module = field(default_factory=injection.mod)
9191

92-
@overload
93-
def __call__(
94-
self,
95-
input_or_handler_type: type[I],
96-
/,
97-
*,
98-
threadsafe: bool | None = ...,
99-
) -> Callable[[HandlerType[[I], O]], HandlerType[[I], O]]: ...
100-
101-
@overload
102-
def __call__(
103-
self,
104-
input_or_handler_type: HandlerType[[I], O],
105-
/,
106-
*,
107-
threadsafe: bool | None = ...,
108-
) -> HandlerType[[I], O]: ...
109-
110-
@overload
111-
def __call__(
112-
self,
113-
input_or_handler_type: None = ...,
114-
/,
115-
*,
116-
threadsafe: bool | None = ...,
117-
) -> Callable[[HandlerType[[I], O]], HandlerType[[I], O]]: ...
92+
if TYPE_CHECKING: # pragma: no cover
93+
94+
@overload
95+
def __call__(
96+
self,
97+
input_or_handler_type: type[I],
98+
/,
99+
*,
100+
threadsafe: bool | None = ...,
101+
) -> Callable[[HandlerType[[I], O]], HandlerType[[I], O]]: ...
102+
103+
@overload
104+
def __call__(
105+
self,
106+
input_or_handler_type: HandlerType[[I], O],
107+
/,
108+
*,
109+
threadsafe: bool | None = ...,
110+
) -> HandlerType[[I], O]: ...
111+
112+
@overload
113+
def __call__(
114+
self,
115+
input_or_handler_type: None = ...,
116+
/,
117+
*,
118+
threadsafe: bool | None = ...,
119+
) -> Callable[[HandlerType[[I], O]], HandlerType[[I], O]]: ...
118120

119121
def __call__(
120122
self,

cq/ext/fastapi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ async def new_deferred_query_bus[T](
5353
return FastAPIDeferredDispatcher(background_tasks, query_bus)
5454

5555

56-
if TYPE_CHECKING:
56+
if TYPE_CHECKING: # pragma: no cover
5757
type DeferredCommandBus = DeferredDispatcher[Command]
5858
type DeferredEventBus = DeferredDispatcher[Event]
5959
type DeferredQueryBus = DeferredDispatcher[Query]

documentation/pipeline.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,6 @@ class ContextExample:
6464

6565
async def how_to_dispatch() -> None:
6666
command = FirstCommand(...)
67-
context = await ContextExample().pipeline.dispatch(command)
67+
context = await ContextExample.pipeline.dispatch(command)
6868
# ...
6969
```

tests/test_context_command_pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ async def _(self, baz: Baz) -> None:
5656
self.baz = baz
5757

5858
cmd = Command1()
59-
ctx = await Context().pipeline.dispatch(cmd)
59+
ctx = await Context.pipeline.dispatch(cmd)
6060

6161
assert isinstance(ctx, Context)
6262
assert isinstance(ctx.foo, Foo)

0 commit comments

Comments
 (0)