python-cq 0.13.0__tar.gz → 0.14.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.13.0 → python_cq-0.14.0}/PKG-INFO +1 -1
- python_cq-0.14.0/cq/_core/middleware.py +106 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/pyproject.toml +1 -1
- python_cq-0.13.0/cq/_core/middleware.py +0 -69
- {python_cq-0.13.0 → python_cq-0.14.0}/.gitignore +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/LICENSE +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/__init__.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/__init__.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/dispatcher/__init__.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/dispatcher/base.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/dispatcher/bus.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/dispatcher/lazy.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/dispatcher/pipe.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/handler.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/message.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/pipetools.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/related_events.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/_core/scope.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/exceptions.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/ext/__init__.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/ext/fastapi.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/middlewares/__init__.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/middlewares/retry.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/middlewares/scope.py +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/cq/py.typed +0 -0
- {python_cq-0.13.0 → python_cq-0.14.0}/docs/index.md +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from collections.abc import AsyncGenerator, Awaitable, Callable
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from inspect import isasyncgenfunction
|
|
4
|
+
from typing import Concatenate, Self, TypeGuard
|
|
5
|
+
|
|
6
|
+
from cq.exceptions import MiddlewareError
|
|
7
|
+
|
|
8
|
+
type MiddlewareResult[T] = AsyncGenerator[None, T]
|
|
9
|
+
type GeneratorMiddleware[**P, T] = Callable[P, MiddlewareResult[T]]
|
|
10
|
+
type ClassicMiddleware[**P, T] = Callable[
|
|
11
|
+
Concatenate[Callable[P, Awaitable[T]], P], Awaitable[T]
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
type Middleware[**P, T] = ClassicMiddleware[P, T] | GeneratorMiddleware[P, T]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
18
|
+
class MiddlewareGroup[**P, T]:
|
|
19
|
+
__middlewares: list[ClassicMiddleware[P, T]] = field(
|
|
20
|
+
default_factory=list,
|
|
21
|
+
init=False,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def add(self, *middlewares: Middleware[P, T]) -> Self:
|
|
25
|
+
classic_middlewares = reversed(
|
|
26
|
+
tuple(self.__normalize(middleware) for middleware in middlewares)
|
|
27
|
+
)
|
|
28
|
+
self.__middlewares.extend(classic_middlewares)
|
|
29
|
+
return self
|
|
30
|
+
|
|
31
|
+
async def invoke(
|
|
32
|
+
self,
|
|
33
|
+
handler: Callable[P, Awaitable[T]],
|
|
34
|
+
/,
|
|
35
|
+
*args: P.args,
|
|
36
|
+
**kwargs: P.kwargs,
|
|
37
|
+
) -> T:
|
|
38
|
+
return await self.__apply_stack(handler)(*args, **kwargs)
|
|
39
|
+
|
|
40
|
+
def __apply_stack(
|
|
41
|
+
self,
|
|
42
|
+
handler: Callable[P, Awaitable[T]],
|
|
43
|
+
) -> Callable[P, Awaitable[T]]:
|
|
44
|
+
for middleware in self.__middlewares:
|
|
45
|
+
handler = _BoundMiddleware(handler, middleware)
|
|
46
|
+
|
|
47
|
+
return handler
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def __normalize(middleware: Middleware[P, T]) -> ClassicMiddleware[P, T]:
|
|
51
|
+
if _is_gen_middleware(middleware):
|
|
52
|
+
return _GeneratorMiddleware(middleware)
|
|
53
|
+
|
|
54
|
+
return middleware # type: ignore[return-value]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
58
|
+
class _BoundMiddleware[**P, T]:
|
|
59
|
+
call_next: Callable[P, Awaitable[T]]
|
|
60
|
+
middleware: ClassicMiddleware[P, T]
|
|
61
|
+
|
|
62
|
+
async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
|
|
63
|
+
return await self.middleware(self.call_next, *args, **kwargs)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
67
|
+
class _GeneratorMiddleware[**P, T]:
|
|
68
|
+
middleware: GeneratorMiddleware[P, T]
|
|
69
|
+
|
|
70
|
+
async def __call__(
|
|
71
|
+
self,
|
|
72
|
+
call_next: Callable[P, Awaitable[T]],
|
|
73
|
+
/,
|
|
74
|
+
*args: P.args,
|
|
75
|
+
**kwargs: P.kwargs,
|
|
76
|
+
) -> T:
|
|
77
|
+
generator: MiddlewareResult[T] = self.middleware(*args, **kwargs)
|
|
78
|
+
value: T = NotImplemented
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
await anext(generator)
|
|
82
|
+
|
|
83
|
+
while True:
|
|
84
|
+
try:
|
|
85
|
+
value = await call_next(*args, **kwargs)
|
|
86
|
+
except BaseException as exc:
|
|
87
|
+
await generator.athrow(exc)
|
|
88
|
+
else:
|
|
89
|
+
await generator.asend(value)
|
|
90
|
+
raise MiddlewareError(
|
|
91
|
+
f"Too many `yield` keywords in `{self.middleware}`."
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
except StopAsyncIteration:
|
|
95
|
+
...
|
|
96
|
+
|
|
97
|
+
finally:
|
|
98
|
+
await generator.aclose()
|
|
99
|
+
|
|
100
|
+
return value
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _is_gen_middleware[**P, T](
|
|
104
|
+
middleware: Middleware[P, T],
|
|
105
|
+
) -> TypeGuard[GeneratorMiddleware[P, T]]:
|
|
106
|
+
return any(map(isasyncgenfunction, (middleware, middleware.__call__))) # type: ignore[operator]
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
from collections.abc import AsyncGenerator, Awaitable, Callable
|
|
2
|
-
from dataclasses import dataclass, field
|
|
3
|
-
from typing import Self
|
|
4
|
-
|
|
5
|
-
from cq.exceptions import MiddlewareError
|
|
6
|
-
|
|
7
|
-
type MiddlewareResult[T] = AsyncGenerator[None, T]
|
|
8
|
-
type Middleware[**P, T] = Callable[P, MiddlewareResult[T]]
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass(repr=False, eq=False, frozen=True, slots=True)
|
|
12
|
-
class MiddlewareGroup[**P, T]:
|
|
13
|
-
__middlewares: list[Middleware[P, T]] = field(default_factory=list, init=False)
|
|
14
|
-
|
|
15
|
-
def add(self, *middlewares: Middleware[P, T]) -> Self:
|
|
16
|
-
self.__middlewares.extend(reversed(middlewares))
|
|
17
|
-
return self
|
|
18
|
-
|
|
19
|
-
async def invoke(
|
|
20
|
-
self,
|
|
21
|
-
handler: Callable[P, Awaitable[T]],
|
|
22
|
-
/,
|
|
23
|
-
*args: P.args,
|
|
24
|
-
**kwargs: P.kwargs,
|
|
25
|
-
) -> T:
|
|
26
|
-
return await self.__apply_stack(handler)(*args, **kwargs)
|
|
27
|
-
|
|
28
|
-
def __apply_stack(
|
|
29
|
-
self,
|
|
30
|
-
handler: Callable[P, Awaitable[T]],
|
|
31
|
-
) -> Callable[P, Awaitable[T]]:
|
|
32
|
-
for middleware in self.__middlewares:
|
|
33
|
-
handler = self.__apply_middleware(handler, middleware)
|
|
34
|
-
|
|
35
|
-
return handler
|
|
36
|
-
|
|
37
|
-
@classmethod
|
|
38
|
-
def __apply_middleware(
|
|
39
|
-
cls,
|
|
40
|
-
handler: Callable[P, Awaitable[T]],
|
|
41
|
-
middleware: Middleware[P, T],
|
|
42
|
-
) -> Callable[P, Awaitable[T]]:
|
|
43
|
-
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
|
44
|
-
generator: MiddlewareResult[T] = middleware(*args, **kwargs)
|
|
45
|
-
value: T = NotImplemented
|
|
46
|
-
|
|
47
|
-
try:
|
|
48
|
-
await anext(generator)
|
|
49
|
-
|
|
50
|
-
while True:
|
|
51
|
-
try:
|
|
52
|
-
value = await handler(*args, **kwargs)
|
|
53
|
-
except BaseException as exc:
|
|
54
|
-
await generator.athrow(exc)
|
|
55
|
-
else:
|
|
56
|
-
await generator.asend(value)
|
|
57
|
-
raise MiddlewareError(
|
|
58
|
-
f"Too many `yield` keywords in `{middleware}`."
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
except StopAsyncIteration:
|
|
62
|
-
...
|
|
63
|
-
|
|
64
|
-
finally:
|
|
65
|
-
await generator.aclose()
|
|
66
|
-
|
|
67
|
-
return value
|
|
68
|
-
|
|
69
|
-
return wrapper
|
|
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
|