python-cq 0.19.0__tar.gz → 0.21.0__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.19.0 → python_cq-0.21.0}/PKG-INFO +1 -1
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/__init__.py +14 -15
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/cq.py +13 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/dispatchers/abc.py +10 -9
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/dispatchers/bus.py +3 -3
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/dispatchers/pipe.py +1 -1
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/handler.py +14 -1
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/middleware.py +0 -15
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/pump.py +8 -8
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/queues/abc.py +7 -6
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/queues/memory.py +5 -4
- {python_cq-0.19.0 → python_cq-0.21.0}/pyproject.toml +1 -1
- {python_cq-0.19.0 → python_cq-0.21.0}/.gitignore +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/LICENSE +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/__init__.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/common/__init__.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/common/typing.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/di.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/dispatchers/__init__.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/dispatchers/lazy.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/message.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/middlewares/__init__.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/middlewares/scope.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/pipetools.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/queues/__init__.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/_core/related_events.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/exceptions.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/ext/__init__.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/ext/injection.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/middlewares/__init__.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/middlewares/exc.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/middlewares/retry.py +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/cq/py.typed +0 -0
- {python_cq-0.19.0 → python_cq-0.21.0}/docs/index.md +0 -0
|
@@ -16,11 +16,12 @@ from ._core.message import (
|
|
|
16
16
|
from ._core.middleware import Middleware, MiddlewareResult, resolve_handler_source
|
|
17
17
|
from ._core.pipetools import ContextCommandPipeline as _ContextCommandPipeline
|
|
18
18
|
from ._core.pump import Pump
|
|
19
|
-
from ._core.queues.abc import Consumer, Producer, Queue
|
|
19
|
+
from ._core.queues.abc import Consumer, Delivery, Producer, Queue
|
|
20
20
|
from ._core.queues.memory import MemoryQueue
|
|
21
21
|
from ._core.related_events import AnyIORelatedEvents, RelatedEvents
|
|
22
22
|
|
|
23
23
|
__all__ = (
|
|
24
|
+
"__cq__",
|
|
24
25
|
"AnyCommandBus",
|
|
25
26
|
"AnyIORelatedEvents",
|
|
26
27
|
"Bus",
|
|
@@ -30,6 +31,7 @@ __all__ = (
|
|
|
30
31
|
"Consumer",
|
|
31
32
|
"ContextCommandPipeline",
|
|
32
33
|
"ContextPipeline",
|
|
34
|
+
"Delivery",
|
|
33
35
|
"DIAdapter",
|
|
34
36
|
"Dispatcher",
|
|
35
37
|
"Event",
|
|
@@ -54,30 +56,27 @@ __all__ = (
|
|
|
54
56
|
)
|
|
55
57
|
|
|
56
58
|
try:
|
|
57
|
-
from
|
|
59
|
+
from .ext.injection import InjectionAdapter as _InjectionAdapter
|
|
58
60
|
|
|
59
61
|
except ImportError: # pragma: no cover
|
|
60
|
-
|
|
62
|
+
__cq__ = CQ(_NoDI())
|
|
61
63
|
|
|
62
64
|
else:
|
|
63
|
-
|
|
65
|
+
__cq__ = CQ(_InjectionAdapter())
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
__cq__.register_defaults()
|
|
66
68
|
|
|
67
|
-
command_handler =
|
|
68
|
-
event_handler =
|
|
69
|
-
query_handler =
|
|
69
|
+
command_handler = __cq__.command_handler
|
|
70
|
+
event_handler = __cq__.event_handler
|
|
71
|
+
query_handler = __cq__.query_handler
|
|
70
72
|
|
|
71
|
-
new_command_bus =
|
|
72
|
-
new_event_bus =
|
|
73
|
-
new_query_bus =
|
|
73
|
+
new_command_bus = __cq__.new_command_bus
|
|
74
|
+
new_event_bus = __cq__.new_event_bus
|
|
75
|
+
new_query_bus = __cq__.new_query_bus
|
|
74
76
|
|
|
75
77
|
|
|
76
78
|
class ContextCommandPipeline[C: Command](_ContextCommandPipeline[C]):
|
|
77
79
|
__slots__ = ()
|
|
78
80
|
|
|
79
|
-
def __init__(self, di: DIAdapter =
|
|
81
|
+
def __init__(self, di: DIAdapter = __cq__.di) -> None:
|
|
80
82
|
super().__init__(di)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
del _default
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import KeysView
|
|
1
2
|
from typing import Any, Self
|
|
2
3
|
|
|
3
4
|
from cq._core.di import DIAdapter
|
|
@@ -34,14 +35,26 @@ class CQ:
|
|
|
34
35
|
def command_handler(self) -> HandlerDecorator[Command, Any]:
|
|
35
36
|
return HandlerDecorator(self.__command_registry, self.__di)
|
|
36
37
|
|
|
38
|
+
@property
|
|
39
|
+
def command_types(self) -> KeysView[type[Command]]:
|
|
40
|
+
return self.__command_registry.message_types
|
|
41
|
+
|
|
37
42
|
@property
|
|
38
43
|
def event_handler(self) -> HandlerDecorator[Event, Any]:
|
|
39
44
|
return HandlerDecorator(self.__event_registry, self.__di)
|
|
40
45
|
|
|
46
|
+
@property
|
|
47
|
+
def event_types(self) -> KeysView[type[Event]]:
|
|
48
|
+
return self.__event_registry.message_types
|
|
49
|
+
|
|
41
50
|
@property
|
|
42
51
|
def query_handler(self) -> HandlerDecorator[Query, Any]:
|
|
43
52
|
return HandlerDecorator(self.__query_registry, self.__di)
|
|
44
53
|
|
|
54
|
+
@property
|
|
55
|
+
def query_types(self) -> KeysView[type[Query]]:
|
|
56
|
+
return self.__query_registry.message_types
|
|
57
|
+
|
|
45
58
|
def new_command_bus(self) -> Bus[Command, Any]:
|
|
46
59
|
bus = SimpleBus(self.__command_registry)
|
|
47
60
|
command_middleware = CommandDispatchScopeMiddleware(self.__di)
|
|
@@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
|
|
|
2
2
|
from collections.abc import Awaitable, Callable
|
|
3
3
|
from typing import Protocol, Self, runtime_checkable
|
|
4
4
|
|
|
5
|
-
from cq._core.middleware import Middleware, MiddlewareGroup
|
|
5
|
+
from cq._core.middleware import Middleware, MiddlewareGroup
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
@runtime_checkable
|
|
@@ -29,16 +29,17 @@ class BaseDispatcher[I, O](Dispatcher[I, O], ABC):
|
|
|
29
29
|
self.__middleware_group.add(*middlewares)
|
|
30
30
|
return self
|
|
31
31
|
|
|
32
|
-
async def
|
|
32
|
+
async def _invoke(
|
|
33
33
|
self,
|
|
34
|
-
message: I,
|
|
35
34
|
handler: Callable[[I], Awaitable[O]],
|
|
35
|
+
message: I,
|
|
36
36
|
/,
|
|
37
37
|
fail_silently: bool = False,
|
|
38
38
|
) -> O:
|
|
39
|
-
|
|
40
|
-
message
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
try:
|
|
40
|
+
return await self.__middleware_group.invoke(handler, message)
|
|
41
|
+
except Exception:
|
|
42
|
+
if fail_silently:
|
|
43
|
+
return NotImplemented
|
|
44
|
+
|
|
45
|
+
raise
|
|
@@ -83,7 +83,7 @@ class SimpleBus[I, O](BaseBus[I, O]):
|
|
|
83
83
|
self._trigger_listeners(message, task_group)
|
|
84
84
|
|
|
85
85
|
for handler in self._handlers_from(type(message)):
|
|
86
|
-
return await self.
|
|
86
|
+
return await self._invoke(handler, message, handler.fail_silently)
|
|
87
87
|
|
|
88
88
|
return NotImplemented
|
|
89
89
|
|
|
@@ -100,8 +100,8 @@ class TaskBus[I](BaseBus[I, None]):
|
|
|
100
100
|
|
|
101
101
|
for handler in self._handlers_from(type(message)):
|
|
102
102
|
task_group.start_soon(
|
|
103
|
-
self.
|
|
104
|
-
message,
|
|
103
|
+
self._invoke,
|
|
105
104
|
handler,
|
|
105
|
+
message,
|
|
106
106
|
handler.fail_silently,
|
|
107
107
|
)
|
|
@@ -140,7 +140,7 @@ class Pipe[I, O](BaseDispatcher[I, O]):
|
|
|
140
140
|
return self
|
|
141
141
|
|
|
142
142
|
async def dispatch(self, message: I, /) -> O:
|
|
143
|
-
return await self.
|
|
143
|
+
return await self._invoke(self.__steps.execute, message)
|
|
144
144
|
|
|
145
145
|
|
|
146
146
|
class ContextPipeline[I]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
from collections import defaultdict
|
|
3
|
-
from collections.abc import Awaitable, Callable, Iterator
|
|
3
|
+
from collections.abc import Awaitable, Callable, Iterator, KeysView
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from functools import partial
|
|
6
6
|
from inspect import Parameter, isclass, unwrap
|
|
@@ -49,6 +49,11 @@ class HandleFunction[**P, T]:
|
|
|
49
49
|
class HandlerRegistry[I, O](Protocol):
|
|
50
50
|
__slots__ = ()
|
|
51
51
|
|
|
52
|
+
@property
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def message_types(self) -> KeysView[type[I]]:
|
|
55
|
+
raise NotImplementedError
|
|
56
|
+
|
|
52
57
|
@abstractmethod
|
|
53
58
|
def handlers_from(self, message_type: type[I]) -> Iterator[HandleFunction[[I], O]]:
|
|
54
59
|
raise NotImplementedError
|
|
@@ -71,6 +76,10 @@ class MultipleHandlerRegistry[I, O](HandlerRegistry[I, O]):
|
|
|
71
76
|
init=False,
|
|
72
77
|
)
|
|
73
78
|
|
|
79
|
+
@property
|
|
80
|
+
def message_types(self) -> KeysView[type[I]]:
|
|
81
|
+
return self.__values.keys()
|
|
82
|
+
|
|
74
83
|
def handlers_from(self, message_type: type[I]) -> Iterator[HandleFunction[[I], O]]:
|
|
75
84
|
for key_type in _iter_key_types(message_type):
|
|
76
85
|
yield from self.__values.get(key_type, ())
|
|
@@ -97,6 +106,10 @@ class SingleHandlerRegistry[I, O](HandlerRegistry[I, O]):
|
|
|
97
106
|
init=False,
|
|
98
107
|
)
|
|
99
108
|
|
|
109
|
+
@property
|
|
110
|
+
def message_types(self) -> KeysView[type[I]]:
|
|
111
|
+
return self.__values.keys()
|
|
112
|
+
|
|
100
113
|
def handlers_from(self, message_type: type[I]) -> Iterator[HandleFunction[[I], O]]:
|
|
101
114
|
for key_type in _iter_key_types(message_type):
|
|
102
115
|
function = self.__values.get(key_type, None)
|
|
@@ -115,21 +115,6 @@ class _GeneratorMiddleware[**P, T]:
|
|
|
115
115
|
return value
|
|
116
116
|
|
|
117
117
|
|
|
118
|
-
async def deliver_message[I, O](
|
|
119
|
-
message: I,
|
|
120
|
-
handler: Callable[[I], Awaitable[O]],
|
|
121
|
-
middleware_group: MiddlewareGroup[[I], O],
|
|
122
|
-
fail_silently: bool = False,
|
|
123
|
-
) -> O:
|
|
124
|
-
try:
|
|
125
|
-
return await middleware_group.invoke(handler, message)
|
|
126
|
-
except Exception:
|
|
127
|
-
if fail_silently:
|
|
128
|
-
return NotImplemented
|
|
129
|
-
|
|
130
|
-
raise
|
|
131
|
-
|
|
132
|
-
|
|
133
118
|
def _is_gen_middleware[**P, T](
|
|
134
119
|
middleware: Middleware[P, T],
|
|
135
120
|
) -> TypeGuard[GeneratorMiddleware[P, T]]:
|
|
@@ -5,7 +5,7 @@ from typing import Any, Self
|
|
|
5
5
|
|
|
6
6
|
import anyio
|
|
7
7
|
|
|
8
|
-
from cq._core.middleware import Middleware, MiddlewareGroup
|
|
8
|
+
from cq._core.middleware import Middleware, MiddlewareGroup
|
|
9
9
|
from cq._core.queues.abc import Consumer
|
|
10
10
|
|
|
11
11
|
|
|
@@ -24,13 +24,13 @@ class Pump[T]:
|
|
|
24
24
|
return self
|
|
25
25
|
|
|
26
26
|
async def drain(self) -> None:
|
|
27
|
-
async for
|
|
28
|
-
|
|
29
|
-
message
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
self.fail_silently
|
|
33
|
-
|
|
27
|
+
async for delivery in self.consumer:
|
|
28
|
+
try:
|
|
29
|
+
async with delivery as message:
|
|
30
|
+
await self.__middleware_group.invoke(self.dispatcher, message)
|
|
31
|
+
except Exception:
|
|
32
|
+
if not self.fail_silently:
|
|
33
|
+
raise
|
|
34
34
|
|
|
35
35
|
@asynccontextmanager
|
|
36
36
|
async def draining(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
-
from collections.abc import
|
|
3
|
-
from typing import Protocol, runtime_checkable
|
|
2
|
+
from collections.abc import AsyncIterable
|
|
3
|
+
from typing import AsyncContextManager, Protocol, runtime_checkable
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
@runtime_checkable
|
|
@@ -16,12 +16,13 @@ class Producer[T](Protocol):
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@runtime_checkable
|
|
19
|
-
class
|
|
19
|
+
class Delivery[T](AsyncContextManager[T], Protocol):
|
|
20
20
|
__slots__ = ()
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
|
|
23
|
+
@runtime_checkable
|
|
24
|
+
class Consumer[T](AsyncIterable[Delivery[T]], Protocol):
|
|
25
|
+
__slots__ = ()
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
@runtime_checkable
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
|
|
2
|
-
from contextlib import asynccontextmanager
|
|
2
|
+
from contextlib import asynccontextmanager, nullcontext
|
|
3
3
|
from types import TracebackType
|
|
4
4
|
from typing import Any, Self
|
|
5
5
|
|
|
@@ -8,7 +8,7 @@ from anyio.abc import ObjectReceiveStream, ObjectSendStream
|
|
|
8
8
|
|
|
9
9
|
from cq._core.middleware import Middleware
|
|
10
10
|
from cq._core.pump import Pump
|
|
11
|
-
from cq._core.queues.abc import Queue
|
|
11
|
+
from cq._core.queues.abc import Delivery, Queue
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class MemoryQueue[T](Queue[T]):
|
|
@@ -31,8 +31,9 @@ class MemoryQueue[T](Queue[T]):
|
|
|
31
31
|
) -> None:
|
|
32
32
|
await self.close()
|
|
33
33
|
|
|
34
|
-
def __aiter__(self) -> AsyncIterator[T]:
|
|
35
|
-
|
|
34
|
+
async def __aiter__(self) -> AsyncIterator[Delivery[T]]:
|
|
35
|
+
async for message in self.__consumer:
|
|
36
|
+
yield nullcontext(message)
|
|
36
37
|
|
|
37
38
|
async def close(self) -> None:
|
|
38
39
|
await self.__producer.aclose()
|
|
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
|
|
File without changes
|
|
File without changes
|