python-cq 0.15.0__tar.gz → 0.15.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_cq-0.15.0 → python_cq-0.15.2}/PKG-INFO +1 -1
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/__init__.py +2 -1
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/dispatcher/bus.py +13 -3
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/dispatcher/pipe.py +23 -18
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/handler.py +16 -7
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/middleware.py +15 -1
- {python_cq-0.15.0 → python_cq-0.15.2}/pyproject.toml +1 -1
- {python_cq-0.15.0 → python_cq-0.15.2}/.gitignore +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/LICENSE +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/__init__.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/common/__init__.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/common/typing.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/dispatcher/__init__.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/dispatcher/base.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/dispatcher/lazy.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/message.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/pipetools.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/related_events.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/_core/scope.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/exceptions.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/ext/__init__.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/ext/fastapi.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/middlewares/__init__.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/middlewares/retry.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/middlewares/scope.py +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/cq/py.typed +0 -0
- {python_cq-0.15.0 → python_cq-0.15.2}/docs/index.md +0 -0
|
@@ -17,7 +17,7 @@ from ._core.message import (
|
|
|
17
17
|
new_query_bus,
|
|
18
18
|
query_handler,
|
|
19
19
|
)
|
|
20
|
-
from ._core.middleware import Middleware, MiddlewareResult
|
|
20
|
+
from ._core.middleware import Middleware, MiddlewareResult, resolve_handler_source
|
|
21
21
|
from ._core.pipetools import ContextCommandPipeline
|
|
22
22
|
from ._core.related_events import RelatedEvents
|
|
23
23
|
from ._core.scope import CQScope
|
|
@@ -47,4 +47,5 @@ __all__ = (
|
|
|
47
47
|
"new_event_bus",
|
|
48
48
|
"new_query_bus",
|
|
49
49
|
"query_handler",
|
|
50
|
+
"resolve_handler_source",
|
|
50
51
|
)
|
|
@@ -31,7 +31,12 @@ class Bus[I, O](Dispatcher[I, O], Protocol):
|
|
|
31
31
|
raise NotImplementedError
|
|
32
32
|
|
|
33
33
|
@abstractmethod
|
|
34
|
-
def subscribe(
|
|
34
|
+
def subscribe(
|
|
35
|
+
self,
|
|
36
|
+
input_type: type[I],
|
|
37
|
+
factory: HandlerFactory[[I], O],
|
|
38
|
+
fail_silently: bool = ...,
|
|
39
|
+
) -> Self:
|
|
35
40
|
raise NotImplementedError
|
|
36
41
|
|
|
37
42
|
|
|
@@ -50,8 +55,13 @@ class BaseBus[I, O](BaseDispatcher[I, O], Bus[I, O], ABC):
|
|
|
50
55
|
self.__listeners.extend(listeners)
|
|
51
56
|
return self
|
|
52
57
|
|
|
53
|
-
def subscribe(
|
|
54
|
-
self
|
|
58
|
+
def subscribe(
|
|
59
|
+
self,
|
|
60
|
+
input_type: type[I],
|
|
61
|
+
factory: HandlerFactory[[I], O],
|
|
62
|
+
fail_silently: bool = False,
|
|
63
|
+
) -> Self:
|
|
64
|
+
self.__registry.subscribe(input_type, factory, fail_silently=fail_silently)
|
|
55
65
|
return self
|
|
56
66
|
|
|
57
67
|
def _handlers_from(self, input_type: type[I]) -> Iterator[HandleFunction[[I], O]]:
|
|
@@ -152,25 +152,30 @@ class ContextPipeline[I]:
|
|
|
152
152
|
if TYPE_CHECKING: # pragma: no cover
|
|
153
153
|
|
|
154
154
|
@overload
|
|
155
|
-
def __get__[
|
|
155
|
+
def __get__[Context](
|
|
156
|
+
self,
|
|
157
|
+
instance: None,
|
|
158
|
+
owner: type[Context],
|
|
159
|
+
/,
|
|
160
|
+
) -> Dispatcher[I, Context]: ...
|
|
156
161
|
|
|
157
162
|
@overload
|
|
158
|
-
def __get__[
|
|
163
|
+
def __get__[Context](
|
|
159
164
|
self,
|
|
160
|
-
instance:
|
|
161
|
-
owner: type[
|
|
165
|
+
instance: Context,
|
|
166
|
+
owner: type[Context] | None = ...,
|
|
162
167
|
/,
|
|
163
|
-
) -> Dispatcher[I,
|
|
168
|
+
) -> Dispatcher[I, Context]: ...
|
|
164
169
|
|
|
165
170
|
@overload
|
|
166
171
|
def __get__(self, instance: None = ..., owner: None = ..., /) -> Self: ...
|
|
167
172
|
|
|
168
|
-
def __get__[
|
|
173
|
+
def __get__[Context](
|
|
169
174
|
self,
|
|
170
|
-
instance:
|
|
171
|
-
owner: type[
|
|
175
|
+
instance: Context | None = None,
|
|
176
|
+
owner: type[Context] | None = None,
|
|
172
177
|
/,
|
|
173
|
-
) -> Self | Dispatcher[I,
|
|
178
|
+
) -> Self | Dispatcher[I, Context]:
|
|
174
179
|
if instance is None:
|
|
175
180
|
if owner is None:
|
|
176
181
|
return self
|
|
@@ -231,19 +236,19 @@ class ContextPipeline[I]:
|
|
|
231
236
|
|
|
232
237
|
return decorator(wrapped) if wrapped else decorator
|
|
233
238
|
|
|
234
|
-
async def __execute[
|
|
239
|
+
async def __execute[Context](
|
|
235
240
|
self,
|
|
236
241
|
input_value: I,
|
|
237
242
|
/,
|
|
238
243
|
*,
|
|
239
|
-
context:
|
|
240
|
-
context_type: type[
|
|
241
|
-
) ->
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return
|
|
244
|
+
context: Context,
|
|
245
|
+
context_type: type[Context] | None,
|
|
246
|
+
) -> Context:
|
|
247
|
+
async def handler(i: I, /) -> Context:
|
|
248
|
+
await self.__steps.execute(i, context, context_type)
|
|
249
|
+
return context
|
|
250
|
+
|
|
251
|
+
return await self.__middleware_group.invoke(handler, input_value)
|
|
247
252
|
|
|
248
253
|
|
|
249
254
|
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
@@ -3,7 +3,7 @@ from collections import defaultdict
|
|
|
3
3
|
from collections.abc import Awaitable, Callable, Iterator
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from functools import partial
|
|
6
|
-
from inspect import Parameter, isclass
|
|
6
|
+
from inspect import Parameter, isclass, unwrap
|
|
7
7
|
from inspect import signature as inspect_signature
|
|
8
8
|
from typing import TYPE_CHECKING, Any, Protocol, Self, overload, runtime_checkable
|
|
9
9
|
|
|
@@ -27,14 +27,23 @@ class Handler[**P, T](Protocol):
|
|
|
27
27
|
|
|
28
28
|
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
29
29
|
class HandleFunction[**P, T]:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
fail_silently: bool
|
|
30
|
+
factory: HandlerFactory[P, T]
|
|
31
|
+
source: HandlerType[P, T] | Any
|
|
32
|
+
fail_silently: bool
|
|
33
33
|
|
|
34
34
|
async def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
|
|
35
|
-
handler = await self.
|
|
35
|
+
handler = await self.factory()
|
|
36
36
|
return await handler.handle(*args, **kwargs)
|
|
37
37
|
|
|
38
|
+
@classmethod
|
|
39
|
+
def create(
|
|
40
|
+
cls,
|
|
41
|
+
factory: HandlerFactory[P, T],
|
|
42
|
+
source: HandlerType[P, T] | None = None,
|
|
43
|
+
fail_silently: bool = False,
|
|
44
|
+
) -> Self:
|
|
45
|
+
return cls(factory, source or unwrap(factory), fail_silently)
|
|
46
|
+
|
|
38
47
|
|
|
39
48
|
@runtime_checkable
|
|
40
49
|
class HandlerRegistry[I, O](Protocol):
|
|
@@ -73,7 +82,7 @@ class MultipleHandlerRegistry[I, O](HandlerRegistry[I, O]):
|
|
|
73
82
|
handler_type: HandlerType[[I], O] | None = None,
|
|
74
83
|
fail_silently: bool = False,
|
|
75
84
|
) -> Self:
|
|
76
|
-
function = HandleFunction(handler_factory, handler_type, fail_silently)
|
|
85
|
+
function = HandleFunction.create(handler_factory, handler_type, fail_silently)
|
|
77
86
|
|
|
78
87
|
for key_type in _build_key_types(input_type):
|
|
79
88
|
self.__values[key_type].append(function)
|
|
@@ -101,7 +110,7 @@ class SingleHandlerRegistry[I, O](HandlerRegistry[I, O]):
|
|
|
101
110
|
handler_type: HandlerType[[I], O] | None = None,
|
|
102
111
|
fail_silently: bool = False,
|
|
103
112
|
) -> Self:
|
|
104
|
-
function = HandleFunction(handler_factory, handler_type, fail_silently)
|
|
113
|
+
function = HandleFunction.create(handler_factory, handler_type, fail_silently)
|
|
105
114
|
entries = {key_type: function for key_type in _build_key_types(input_type)}
|
|
106
115
|
|
|
107
116
|
for key_type in entries:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from collections.abc import AsyncGenerator, Awaitable, Callable
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
from inspect import isasyncgenfunction
|
|
4
|
-
from typing import Concatenate, Self, TypeGuard
|
|
4
|
+
from typing import Any, Concatenate, Self, TypeGuard
|
|
5
5
|
|
|
6
|
+
from cq._core.handler import HandleFunction, HandlerType
|
|
6
7
|
from cq.exceptions import MiddlewareError
|
|
7
8
|
|
|
8
9
|
type MiddlewareResult[T] = AsyncGenerator[None, T]
|
|
@@ -63,6 +64,19 @@ class _BoundMiddleware[**P, T]:
|
|
|
63
64
|
return await self.middleware(self.call_next, *args, **kwargs)
|
|
64
65
|
|
|
65
66
|
|
|
67
|
+
def resolve_handler_source[**P, T](
|
|
68
|
+
call_next: Callable[P, Awaitable[T]]
|
|
69
|
+
| _BoundMiddleware[P, T]
|
|
70
|
+
| HandleFunction[P, T],
|
|
71
|
+
/,
|
|
72
|
+
) -> HandlerType[P, T] | Any:
|
|
73
|
+
while True:
|
|
74
|
+
try:
|
|
75
|
+
call_next = call_next.call_next # type: ignore[union-attr]
|
|
76
|
+
except AttributeError:
|
|
77
|
+
return call_next.source # type: ignore[union-attr]
|
|
78
|
+
|
|
79
|
+
|
|
66
80
|
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
67
81
|
class _GeneratorMiddleware[**P, T]:
|
|
68
82
|
middleware: GeneratorMiddleware[P, T]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|