python-cqrs 4.15.1__tar.gz → 5.1.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_cqrs-4.15.1/src/python_cqrs.egg-info → python_cqrs-5.1.0}/PKG-INFO +44 -29
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/README.md +30 -24
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/pyproject.toml +16 -4
- python_cqrs-5.1.0/src/cqrs/__init__.py +218 -0
- python_cqrs-5.1.0/src/cqrs/_dataclass_utils.py +99 -0
- python_cqrs-5.1.0/src/cqrs/bootstrap/__init__.py +5 -0
- python_cqrs-4.15.1/src/cqrs/requests/bootstrap.py → python_cqrs-5.1.0/src/cqrs/bootstrap/requests.py +1 -1
- python_cqrs-4.15.1/src/cqrs/saga/bootstrap.py → python_cqrs-5.1.0/src/cqrs/bootstrap/saga.py +4 -4
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/dispatcher/event.py +3 -3
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/dispatcher/models.py +3 -3
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/dispatcher/request.py +4 -4
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/dispatcher/saga.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/dispatcher/streaming.py +3 -3
- python_cqrs-5.1.0/src/cqrs/events/__init__.py +63 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/events/event_emitter.py +3 -2
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/events/event_processor.py +2 -2
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/events/fallback.py +1 -1
- python_cqrs-5.1.0/src/cqrs/handlers/__init__.py +14 -0
- python_cqrs-4.15.1/src/cqrs/requests/cor_request_handler.py → python_cqrs-5.1.0/src/cqrs/handlers/cor.py +2 -2
- python_cqrs-4.15.1/src/cqrs/events/event_handler.py → python_cqrs-5.1.0/src/cqrs/handlers/event.py +1 -1
- python_cqrs-4.15.1/src/cqrs/requests/request_handler.py → python_cqrs-5.1.0/src/cqrs/handlers/request.py +2 -2
- python_cqrs-4.15.1/src/cqrs/saga/step.py → python_cqrs-5.1.0/src/cqrs/handlers/saga.py +2 -2
- python_cqrs-5.1.0/src/cqrs/mapping/__init__.py +5 -0
- python_cqrs-4.15.1/src/cqrs/events/map.py → python_cqrs-5.1.0/src/cqrs/mapping/events.py +2 -2
- python_cqrs-4.15.1/src/cqrs/outbox/map.py → python_cqrs-5.1.0/src/cqrs/mapping/outbox.py +1 -1
- python_cqrs-4.15.1/src/cqrs/requests/map.py → python_cqrs-5.1.0/src/cqrs/mapping/requests.py +3 -3
- python_cqrs-5.1.0/src/cqrs/mediators/__init__.py +11 -0
- python_cqrs-5.1.0/src/cqrs/mediators/_common.py +26 -0
- python_cqrs-5.1.0/src/cqrs/mediators/event.py +50 -0
- python_cqrs-5.1.0/src/cqrs/mediators/request.py +109 -0
- python_cqrs-5.1.0/src/cqrs/mediators/saga.py +152 -0
- python_cqrs-5.1.0/src/cqrs/mediators/streaming.py +128 -0
- python_cqrs-5.1.0/src/cqrs/mermaid/__init__.py +4 -0
- python_cqrs-4.15.1/src/cqrs/requests/mermaid.py → python_cqrs-5.1.0/src/cqrs/mermaid/cor.py +1 -1
- python_cqrs-4.15.1/src/cqrs/saga/mermaid.py → python_cqrs-5.1.0/src/cqrs/mermaid/saga.py +1 -1
- {python_cqrs-4.15.1/src/cqrs → python_cqrs-5.1.0/src/cqrs/message_brokers}/producer.py +7 -4
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/middlewares/base.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/middlewares/logging.py +2 -2
- python_cqrs-5.1.0/src/cqrs/models/__init__.py +57 -0
- python_cqrs-5.1.0/src/cqrs/models/event.py +208 -0
- python_cqrs-5.1.0/src/cqrs/models/pydantic.py +130 -0
- python_cqrs-5.1.0/src/cqrs/models/request.py +81 -0
- python_cqrs-5.1.0/src/cqrs/models/response.py +74 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/outbox/mock.py +2 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/outbox/repository.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/outbox/sqlalchemy.py +22 -8
- python_cqrs-5.1.0/src/cqrs/outbox/sqlmodel.py +189 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/requests/fallback.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/circuit_breaker.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/compensation.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/execution.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/fallback.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/saga.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/storage/sqlalchemy.py +72 -45
- python_cqrs-5.1.0/src/cqrs/saga/storage/sqlmodel.py +203 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/validation.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/serializers/default.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/serializers/json.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/serializers/protobuf.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/serializers/protocol.py +1 -1
- python_cqrs-5.1.0/src/cqrs/sqlmodel_base.py +45 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/types.py +1 -1
- {python_cqrs-4.15.1 → python_cqrs-5.1.0/src/python_cqrs.egg-info}/PKG-INFO +44 -29
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/python_cqrs.egg-info/SOURCES.txt +32 -18
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/python_cqrs.egg-info/requires.txt +13 -2
- python_cqrs-4.15.1/src/cqrs/__init__.py +0 -154
- python_cqrs-4.15.1/src/cqrs/_eol.py +0 -30
- python_cqrs-4.15.1/src/cqrs/events/__init__.py +0 -50
- python_cqrs-4.15.1/src/cqrs/events/event.py +0 -393
- python_cqrs-4.15.1/src/cqrs/mediator.py +0 -423
- python_cqrs-4.15.1/src/cqrs/requests/request.py +0 -152
- python_cqrs-4.15.1/src/cqrs/response.py +0 -146
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/LICENSE +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/setup.cfg +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/adapters/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/adapters/amqp.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/adapters/circuit_breaker.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/adapters/kafka.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/adapters/protocol.py +0 -0
- /python_cqrs-4.15.1/src/cqrs/events/bootstrap.py → /python_cqrs-5.1.0/src/cqrs/bootstrap/events.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/circuit_breaker.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/compressors/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/compressors/protocol.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/compressors/zlib.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/container/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/container/dependency_injector.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/container/di.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/container/dishka.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/container/protocol.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/container/scope.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/deserializers/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/deserializers/exceptions.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/deserializers/json.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/deserializers/protobuf.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/dispatcher/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/dispatcher/exceptions.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/generic_utils.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/message_brokers/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/message_brokers/amqp.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/message_brokers/devnull.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/message_brokers/kafka.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/message_brokers/protocol.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/middlewares/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/outbox/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/requests/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/models.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/recovery.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/storage/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/storage/enums.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/storage/memory.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/storage/models.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/saga/storage/protocol.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/serializers/__init__.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/cqrs/sqlalchemy_types.py +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/python_cqrs.egg-info/dependency_links.txt +0 -0
- {python_cqrs-4.15.1 → python_cqrs-5.1.0}/src/python_cqrs.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-cqrs
|
|
3
|
-
Version:
|
|
3
|
+
Version: 5.1.0
|
|
4
4
|
Summary: Event-Driven Architecture Framework for Distributed Systems
|
|
5
5
|
Author-email: Vadim Kozyrevskiy <vadikko2@mail.ru>, Dmitry Kutlubaev <kutlubaev00@mail.ru>
|
|
6
6
|
Maintainer-email: Vadim Kozyrevskiy <vadikko2@mail.ru>
|
|
@@ -21,12 +21,17 @@ Requires-Dist: dataclass-wizard==0.*
|
|
|
21
21
|
Requires-Dist: di[anyio]==0.*
|
|
22
22
|
Requires-Dist: dependency-injector>=4.0
|
|
23
23
|
Requires-Dist: orjson==3.*
|
|
24
|
-
Requires-Dist: pydantic==2.*
|
|
25
|
-
Requires-Dist: sqlalchemy[asyncio]==2.0.*
|
|
26
24
|
Requires-Dist: python-dotenv==1.*
|
|
27
25
|
Requires-Dist: typing-extensions>=4.0
|
|
28
26
|
Provides-Extra: aiobreaker
|
|
29
27
|
Requires-Dist: aiobreaker>=0.3.0; extra == "aiobreaker"
|
|
28
|
+
Provides-Extra: pydantic
|
|
29
|
+
Requires-Dist: pydantic==2.*; extra == "pydantic"
|
|
30
|
+
Provides-Extra: sqlalchemy
|
|
31
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "sqlalchemy"
|
|
32
|
+
Provides-Extra: sqlmodel
|
|
33
|
+
Requires-Dist: sqlmodel>=0.0.22; extra == "sqlmodel"
|
|
34
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "sqlmodel"
|
|
30
35
|
Provides-Extra: dev
|
|
31
36
|
Requires-Dist: pycln==2.5.0; extra == "dev"
|
|
32
37
|
Requires-Dist: pre-commit==3.8.0; extra == "dev"
|
|
@@ -50,6 +55,10 @@ Requires-Dist: redis>=5.0.0; extra == "dev"
|
|
|
50
55
|
Requires-Dist: aiobreaker>=0.3.0; extra == "dev"
|
|
51
56
|
Requires-Dist: dishka>=1.0; extra == "dev"
|
|
52
57
|
Requires-Dist: protobuf>=4.25.8; extra == "dev"
|
|
58
|
+
Requires-Dist: pydantic==2.*; extra == "dev"
|
|
59
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "dev"
|
|
60
|
+
Requires-Dist: sqlmodel>=0.0.22; extra == "dev"
|
|
61
|
+
Requires-Dist: aiosqlite>=0.20.0; extra == "dev"
|
|
53
62
|
Provides-Extra: examples
|
|
54
63
|
Requires-Dist: fastapi==0.109.*; extra == "examples"
|
|
55
64
|
Requires-Dist: faststream[kafka]==0.5.28; extra == "examples"
|
|
@@ -59,6 +68,8 @@ Requires-Dist: aiohttp==3.14.3; extra == "examples"
|
|
|
59
68
|
Requires-Dist: protobuf>=4.25.8; extra == "examples"
|
|
60
69
|
Requires-Dist: aiosqlite>=0.20.0; extra == "examples"
|
|
61
70
|
Requires-Dist: dishka>=1.0; extra == "examples"
|
|
71
|
+
Requires-Dist: pydantic==2.*; extra == "examples"
|
|
72
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "examples"
|
|
62
73
|
Provides-Extra: kafka
|
|
63
74
|
Requires-Dist: aiokafka==0.10.0; extra == "kafka"
|
|
64
75
|
Requires-Dist: retry-async==0.1.*; extra == "kafka"
|
|
@@ -66,8 +77,6 @@ Provides-Extra: protobuf
|
|
|
66
77
|
Requires-Dist: protobuf>=4.25.8; extra == "protobuf"
|
|
67
78
|
Provides-Extra: rabbit
|
|
68
79
|
Requires-Dist: aio-pika==9.3.0; extra == "rabbit"
|
|
69
|
-
Provides-Extra: sqlalchemy
|
|
70
|
-
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "sqlalchemy"
|
|
71
80
|
Provides-Extra: dishka
|
|
72
81
|
Requires-Dist: dishka>=1.0; extra == "dishka"
|
|
73
82
|
Dynamic: license-file
|
|
@@ -153,7 +162,7 @@ project ([documentation](https://akhundmurad.github.io/diator/)) with several en
|
|
|
153
162
|
|
|
154
163
|
- **Typing:** Pydantic [v2.*](https://docs.pydantic.dev/2.8/) and `IRequest`/`IResponse` interfaces — use Pydantic-based, dataclass-based, or custom Request/Response implementations.
|
|
155
164
|
- **Broker:** Kafka via [aiokafka](https://github.com/aio-libs/aiokafka).
|
|
156
|
-
- **Storage:** SQLAlchemy
|
|
165
|
+
- **Storage:** SQLAlchemy and SQLModel outbox and saga storage on MySQL/MariaDB and PostgreSQL.
|
|
157
166
|
- **Integration:** Ready for integration with FastAPI and FastStream.
|
|
158
167
|
- **Documentation:** Built-in Mermaid diagram generation (Sequence and Class diagrams).
|
|
159
168
|
- **Protobuf:** Interface-level support for converting Notification events to Protobuf and back.
|
|
@@ -176,15 +185,21 @@ Do not add a Saga for a single `UPDATE` in one service, and do not use a Saga as
|
|
|
176
185
|
pip install python-cqrs
|
|
177
186
|
```
|
|
178
187
|
|
|
179
|
-
Optional
|
|
188
|
+
Optional extras (5.0+ — pydantic and SQLAlchemy are no longer core dependencies; SQLModel storage is 5.1+):
|
|
180
189
|
|
|
181
190
|
```bash
|
|
182
|
-
pip install python-cqrs[
|
|
183
|
-
pip install python-cqrs[
|
|
184
|
-
pip install python-cqrs[
|
|
191
|
+
pip install "python-cqrs[pydantic]" # PydanticRequest / Pydantic* events
|
|
192
|
+
pip install "python-cqrs[sqlalchemy]" # Outbox / Saga SQLAlchemy storage
|
|
193
|
+
pip install "python-cqrs[sqlmodel]" # Outbox / Saga SQLModel storage
|
|
194
|
+
pip install "python-cqrs[kafka]" # Kafka broker (aiokafka)
|
|
195
|
+
pip install "python-cqrs[examples]" # FastAPI, FastStream, uvicorn, etc.
|
|
196
|
+
pip install "python-cqrs[aiobreaker]" # Circuit breaker for saga fallbacks
|
|
185
197
|
```
|
|
186
198
|
|
|
187
|
-
|
|
199
|
+
Default `Request` / `Response` / `Event` / `DomainEvent` / `NotificationEvent` aliases
|
|
200
|
+
are dataclass-based (`DC*`). Use `Pydantic*` types with the pydantic extra when you
|
|
201
|
+
need validation.
|
|
202
|
+
|
|
188
203
|
|
|
189
204
|
## Quick Start
|
|
190
205
|
|
|
@@ -193,7 +208,7 @@ Define a command, a handler, bind them, and run via the mediator:
|
|
|
193
208
|
```python
|
|
194
209
|
import di
|
|
195
210
|
import cqrs
|
|
196
|
-
from cqrs.
|
|
211
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
197
212
|
|
|
198
213
|
class CreateOrderCommand(cqrs.Request):
|
|
199
214
|
order_id: str
|
|
@@ -281,8 +296,8 @@ As a result of executing the command, an event may be produced to the broker.
|
|
|
281
296
|
> By default, the command handler does not return any result, but it is not mandatory.
|
|
282
297
|
|
|
283
298
|
```python
|
|
284
|
-
from cqrs.
|
|
285
|
-
from cqrs.
|
|
299
|
+
from cqrs.handlers.request import RequestHandler
|
|
300
|
+
from cqrs.models.event import Event
|
|
286
301
|
|
|
287
302
|
class JoinMeetingCommandHandler(RequestHandler[JoinMeetingCommand, None]):
|
|
288
303
|
|
|
@@ -309,8 +324,8 @@ the [read model](https://radekmaziarka.pl/2018/01/08/cqrs-third-step-simple-read
|
|
|
309
324
|
> The read model can be constructed based on domain events produced by the `Command Handler`.
|
|
310
325
|
|
|
311
326
|
```python
|
|
312
|
-
from cqrs.
|
|
313
|
-
from cqrs.
|
|
327
|
+
from cqrs.handlers.request import RequestHandler
|
|
328
|
+
from cqrs.models.event import Event
|
|
314
329
|
|
|
315
330
|
class ReadMeetingQueryHandler(RequestHandler[ReadMeetingQuery, ReadMeetingQueryResult]):
|
|
316
331
|
|
|
@@ -341,8 +356,8 @@ real-time progress updates.
|
|
|
341
356
|
|
|
342
357
|
```python
|
|
343
358
|
import typing
|
|
344
|
-
from cqrs.
|
|
345
|
-
from cqrs.
|
|
359
|
+
from cqrs.handlers.request import StreamingRequestHandler
|
|
360
|
+
from cqrs.models.event import Event
|
|
346
361
|
|
|
347
362
|
class ProcessFilesCommandHandler(StreamingRequestHandler[ProcessFilesCommand, FileProcessedResult]):
|
|
348
363
|
def __init__(self):
|
|
@@ -378,8 +393,8 @@ when a handler successfully processes the request or when all handlers have been
|
|
|
378
393
|
|
|
379
394
|
```python
|
|
380
395
|
import typing
|
|
381
|
-
from cqrs.
|
|
382
|
-
from cqrs.
|
|
396
|
+
from cqrs.handlers.cor import CORRequestHandler
|
|
397
|
+
from cqrs.models.event import Event
|
|
383
398
|
|
|
384
399
|
class CreditCardPaymentHandler(CORRequestHandler[ProcessPaymentCommand, PaymentResult]):
|
|
385
400
|
def __init__(self, payment_service: PaymentServiceProtocol) -> None:
|
|
@@ -435,7 +450,7 @@ the [documentation](https://github.com/vadikko2/python-cqrs/blob/master/examples
|
|
|
435
450
|
The package includes built-in support for generating Mermaid diagrams from Chain of Responsibility handler chains.
|
|
436
451
|
|
|
437
452
|
```python
|
|
438
|
-
from cqrs.
|
|
453
|
+
from cqrs.mermaid.cor import CoRMermaid
|
|
439
454
|
|
|
440
455
|
# Create Mermaid generator from handler chain
|
|
441
456
|
handlers = [CreditCardHandler, PayPalHandler, DefaultHandler]
|
|
@@ -605,8 +620,8 @@ application.
|
|
|
605
620
|
```python
|
|
606
621
|
import functools
|
|
607
622
|
|
|
608
|
-
from cqrs.
|
|
609
|
-
from cqrs.
|
|
623
|
+
from cqrs.bootstrap import events as event_bootstrap
|
|
624
|
+
from cqrs.bootstrap import requests as bootstrap as request_bootstrap
|
|
610
625
|
|
|
611
626
|
from app import dependencies, mapping, orm
|
|
612
627
|
|
|
@@ -662,7 +677,7 @@ import dataclasses
|
|
|
662
677
|
import uuid
|
|
663
678
|
from cqrs.saga.models import SagaContext
|
|
664
679
|
from cqrs.saga.saga import Saga
|
|
665
|
-
from cqrs.saga
|
|
680
|
+
from cqrs.handlers.saga import SagaStepHandler
|
|
666
681
|
|
|
667
682
|
@dataclasses.dataclass
|
|
668
683
|
class OrderContext(SagaContext):
|
|
@@ -684,7 +699,7 @@ class OrderSaga(Saga[OrderContext]):
|
|
|
684
699
|
context = OrderContext(order_id="123", user_id="user_1", items=["item_1"], total_amount=100.0)
|
|
685
700
|
saga_id = uuid.uuid4()
|
|
686
701
|
|
|
687
|
-
async for step_result in mediator.
|
|
702
|
+
async for step_result in mediator.execute(context, saga_id=saga_id):
|
|
688
703
|
print(f"Step completed: {step_result.step_type.__name__}")
|
|
689
704
|
# If any step fails, compensation happens automatically
|
|
690
705
|
```
|
|
@@ -697,7 +712,7 @@ The saga pattern supports fallback steps that execute automatically when primary
|
|
|
697
712
|
from cqrs.saga.fallback import Fallback
|
|
698
713
|
from cqrs.adapters.circuit_breaker import AioBreakerAdapter
|
|
699
714
|
from cqrs.response import Response
|
|
700
|
-
from cqrs.saga
|
|
715
|
+
from cqrs.handlers.saga import SagaStepHandler, SagaStepResult
|
|
701
716
|
|
|
702
717
|
class ReserveInventoryResponse(Response):
|
|
703
718
|
reservation_id: str
|
|
@@ -780,7 +795,7 @@ The recovery mechanism ensures eventual consistency by:
|
|
|
780
795
|
The package includes built-in support for generating Mermaid diagrams from Saga instances.
|
|
781
796
|
|
|
782
797
|
```python
|
|
783
|
-
from cqrs.saga
|
|
798
|
+
from cqrs.mermaid.saga import SagaMermaid
|
|
784
799
|
|
|
785
800
|
# Create Mermaid generator from saga class
|
|
786
801
|
saga = OrderSaga()
|
|
@@ -1020,7 +1035,7 @@ This feature is especially useful when:
|
|
|
1020
1035
|
**Configuration:**
|
|
1021
1036
|
|
|
1022
1037
|
```python
|
|
1023
|
-
from cqrs.
|
|
1038
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
1024
1039
|
|
|
1025
1040
|
mediator = bootstrap.bootstrap_streaming(
|
|
1026
1041
|
di_container=container,
|
|
@@ -1137,7 +1152,7 @@ This allows you to stream results to clients in real-time as they are processed.
|
|
|
1137
1152
|
```python
|
|
1138
1153
|
import fastapi
|
|
1139
1154
|
import json
|
|
1140
|
-
from cqrs.
|
|
1155
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
1141
1156
|
|
|
1142
1157
|
def streaming_mediator_factory() -> cqrs.StreamingRequestMediator:
|
|
1143
1158
|
return bootstrap.bootstrap_streaming(
|
|
@@ -79,7 +79,7 @@ project ([documentation](https://akhundmurad.github.io/diator/)) with several en
|
|
|
79
79
|
|
|
80
80
|
- **Typing:** Pydantic [v2.*](https://docs.pydantic.dev/2.8/) and `IRequest`/`IResponse` interfaces — use Pydantic-based, dataclass-based, or custom Request/Response implementations.
|
|
81
81
|
- **Broker:** Kafka via [aiokafka](https://github.com/aio-libs/aiokafka).
|
|
82
|
-
- **Storage:** SQLAlchemy
|
|
82
|
+
- **Storage:** SQLAlchemy and SQLModel outbox and saga storage on MySQL/MariaDB and PostgreSQL.
|
|
83
83
|
- **Integration:** Ready for integration with FastAPI and FastStream.
|
|
84
84
|
- **Documentation:** Built-in Mermaid diagram generation (Sequence and Class diagrams).
|
|
85
85
|
- **Protobuf:** Interface-level support for converting Notification events to Protobuf and back.
|
|
@@ -102,15 +102,21 @@ Do not add a Saga for a single `UPDATE` in one service, and do not use a Saga as
|
|
|
102
102
|
pip install python-cqrs
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
Optional
|
|
105
|
+
Optional extras (5.0+ — pydantic and SQLAlchemy are no longer core dependencies; SQLModel storage is 5.1+):
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
|
-
pip install python-cqrs[
|
|
109
|
-
pip install python-cqrs[
|
|
110
|
-
pip install python-cqrs[
|
|
108
|
+
pip install "python-cqrs[pydantic]" # PydanticRequest / Pydantic* events
|
|
109
|
+
pip install "python-cqrs[sqlalchemy]" # Outbox / Saga SQLAlchemy storage
|
|
110
|
+
pip install "python-cqrs[sqlmodel]" # Outbox / Saga SQLModel storage
|
|
111
|
+
pip install "python-cqrs[kafka]" # Kafka broker (aiokafka)
|
|
112
|
+
pip install "python-cqrs[examples]" # FastAPI, FastStream, uvicorn, etc.
|
|
113
|
+
pip install "python-cqrs[aiobreaker]" # Circuit breaker for saga fallbacks
|
|
111
114
|
```
|
|
112
115
|
|
|
113
|
-
|
|
116
|
+
Default `Request` / `Response` / `Event` / `DomainEvent` / `NotificationEvent` aliases
|
|
117
|
+
are dataclass-based (`DC*`). Use `Pydantic*` types with the pydantic extra when you
|
|
118
|
+
need validation.
|
|
119
|
+
|
|
114
120
|
|
|
115
121
|
## Quick Start
|
|
116
122
|
|
|
@@ -119,7 +125,7 @@ Define a command, a handler, bind them, and run via the mediator:
|
|
|
119
125
|
```python
|
|
120
126
|
import di
|
|
121
127
|
import cqrs
|
|
122
|
-
from cqrs.
|
|
128
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
123
129
|
|
|
124
130
|
class CreateOrderCommand(cqrs.Request):
|
|
125
131
|
order_id: str
|
|
@@ -207,8 +213,8 @@ As a result of executing the command, an event may be produced to the broker.
|
|
|
207
213
|
> By default, the command handler does not return any result, but it is not mandatory.
|
|
208
214
|
|
|
209
215
|
```python
|
|
210
|
-
from cqrs.
|
|
211
|
-
from cqrs.
|
|
216
|
+
from cqrs.handlers.request import RequestHandler
|
|
217
|
+
from cqrs.models.event import Event
|
|
212
218
|
|
|
213
219
|
class JoinMeetingCommandHandler(RequestHandler[JoinMeetingCommand, None]):
|
|
214
220
|
|
|
@@ -235,8 +241,8 @@ the [read model](https://radekmaziarka.pl/2018/01/08/cqrs-third-step-simple-read
|
|
|
235
241
|
> The read model can be constructed based on domain events produced by the `Command Handler`.
|
|
236
242
|
|
|
237
243
|
```python
|
|
238
|
-
from cqrs.
|
|
239
|
-
from cqrs.
|
|
244
|
+
from cqrs.handlers.request import RequestHandler
|
|
245
|
+
from cqrs.models.event import Event
|
|
240
246
|
|
|
241
247
|
class ReadMeetingQueryHandler(RequestHandler[ReadMeetingQuery, ReadMeetingQueryResult]):
|
|
242
248
|
|
|
@@ -267,8 +273,8 @@ real-time progress updates.
|
|
|
267
273
|
|
|
268
274
|
```python
|
|
269
275
|
import typing
|
|
270
|
-
from cqrs.
|
|
271
|
-
from cqrs.
|
|
276
|
+
from cqrs.handlers.request import StreamingRequestHandler
|
|
277
|
+
from cqrs.models.event import Event
|
|
272
278
|
|
|
273
279
|
class ProcessFilesCommandHandler(StreamingRequestHandler[ProcessFilesCommand, FileProcessedResult]):
|
|
274
280
|
def __init__(self):
|
|
@@ -304,8 +310,8 @@ when a handler successfully processes the request or when all handlers have been
|
|
|
304
310
|
|
|
305
311
|
```python
|
|
306
312
|
import typing
|
|
307
|
-
from cqrs.
|
|
308
|
-
from cqrs.
|
|
313
|
+
from cqrs.handlers.cor import CORRequestHandler
|
|
314
|
+
from cqrs.models.event import Event
|
|
309
315
|
|
|
310
316
|
class CreditCardPaymentHandler(CORRequestHandler[ProcessPaymentCommand, PaymentResult]):
|
|
311
317
|
def __init__(self, payment_service: PaymentServiceProtocol) -> None:
|
|
@@ -361,7 +367,7 @@ the [documentation](https://github.com/vadikko2/python-cqrs/blob/master/examples
|
|
|
361
367
|
The package includes built-in support for generating Mermaid diagrams from Chain of Responsibility handler chains.
|
|
362
368
|
|
|
363
369
|
```python
|
|
364
|
-
from cqrs.
|
|
370
|
+
from cqrs.mermaid.cor import CoRMermaid
|
|
365
371
|
|
|
366
372
|
# Create Mermaid generator from handler chain
|
|
367
373
|
handlers = [CreditCardHandler, PayPalHandler, DefaultHandler]
|
|
@@ -531,8 +537,8 @@ application.
|
|
|
531
537
|
```python
|
|
532
538
|
import functools
|
|
533
539
|
|
|
534
|
-
from cqrs.
|
|
535
|
-
from cqrs.
|
|
540
|
+
from cqrs.bootstrap import events as event_bootstrap
|
|
541
|
+
from cqrs.bootstrap import requests as bootstrap as request_bootstrap
|
|
536
542
|
|
|
537
543
|
from app import dependencies, mapping, orm
|
|
538
544
|
|
|
@@ -588,7 +594,7 @@ import dataclasses
|
|
|
588
594
|
import uuid
|
|
589
595
|
from cqrs.saga.models import SagaContext
|
|
590
596
|
from cqrs.saga.saga import Saga
|
|
591
|
-
from cqrs.saga
|
|
597
|
+
from cqrs.handlers.saga import SagaStepHandler
|
|
592
598
|
|
|
593
599
|
@dataclasses.dataclass
|
|
594
600
|
class OrderContext(SagaContext):
|
|
@@ -610,7 +616,7 @@ class OrderSaga(Saga[OrderContext]):
|
|
|
610
616
|
context = OrderContext(order_id="123", user_id="user_1", items=["item_1"], total_amount=100.0)
|
|
611
617
|
saga_id = uuid.uuid4()
|
|
612
618
|
|
|
613
|
-
async for step_result in mediator.
|
|
619
|
+
async for step_result in mediator.execute(context, saga_id=saga_id):
|
|
614
620
|
print(f"Step completed: {step_result.step_type.__name__}")
|
|
615
621
|
# If any step fails, compensation happens automatically
|
|
616
622
|
```
|
|
@@ -623,7 +629,7 @@ The saga pattern supports fallback steps that execute automatically when primary
|
|
|
623
629
|
from cqrs.saga.fallback import Fallback
|
|
624
630
|
from cqrs.adapters.circuit_breaker import AioBreakerAdapter
|
|
625
631
|
from cqrs.response import Response
|
|
626
|
-
from cqrs.saga
|
|
632
|
+
from cqrs.handlers.saga import SagaStepHandler, SagaStepResult
|
|
627
633
|
|
|
628
634
|
class ReserveInventoryResponse(Response):
|
|
629
635
|
reservation_id: str
|
|
@@ -706,7 +712,7 @@ The recovery mechanism ensures eventual consistency by:
|
|
|
706
712
|
The package includes built-in support for generating Mermaid diagrams from Saga instances.
|
|
707
713
|
|
|
708
714
|
```python
|
|
709
|
-
from cqrs.saga
|
|
715
|
+
from cqrs.mermaid.saga import SagaMermaid
|
|
710
716
|
|
|
711
717
|
# Create Mermaid generator from saga class
|
|
712
718
|
saga = OrderSaga()
|
|
@@ -946,7 +952,7 @@ This feature is especially useful when:
|
|
|
946
952
|
**Configuration:**
|
|
947
953
|
|
|
948
954
|
```python
|
|
949
|
-
from cqrs.
|
|
955
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
950
956
|
|
|
951
957
|
mediator = bootstrap.bootstrap_streaming(
|
|
952
958
|
di_container=container,
|
|
@@ -1063,7 +1069,7 @@ This allows you to stream results to clients in real-time as they are processed.
|
|
|
1063
1069
|
```python
|
|
1064
1070
|
import fastapi
|
|
1065
1071
|
import json
|
|
1066
|
-
from cqrs.
|
|
1072
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
1067
1073
|
|
|
1068
1074
|
def streaming_mediator_factory() -> cqrs.StreamingRequestMediator:
|
|
1069
1075
|
return bootstrap.bootstrap_streaming(
|
|
@@ -21,8 +21,6 @@ dependencies = [
|
|
|
21
21
|
"di[anyio]==0.*",
|
|
22
22
|
"dependency-injector>=4.0",
|
|
23
23
|
"orjson==3.*",
|
|
24
|
-
"pydantic==2.*",
|
|
25
|
-
"sqlalchemy[asyncio]==2.0.*",
|
|
26
24
|
"python-dotenv==1.*",
|
|
27
25
|
"typing-extensions>=4.0",
|
|
28
26
|
]
|
|
@@ -31,10 +29,13 @@ maintainers = [{ name = "Vadim Kozyrevskiy", email = "vadikko2@mail.ru" }]
|
|
|
31
29
|
name = "python-cqrs"
|
|
32
30
|
readme = "README.md"
|
|
33
31
|
requires-python = ">=3.10"
|
|
34
|
-
version = "
|
|
32
|
+
version = "5.1.0"
|
|
35
33
|
|
|
36
34
|
[project.optional-dependencies]
|
|
37
35
|
aiobreaker = ["aiobreaker>=0.3.0"]
|
|
36
|
+
pydantic = ["pydantic==2.*"]
|
|
37
|
+
sqlalchemy = ["sqlalchemy[asyncio]==2.0.*"]
|
|
38
|
+
sqlmodel = ["sqlmodel>=0.0.22", "sqlalchemy[asyncio]==2.0.*"]
|
|
38
39
|
dev = [
|
|
39
40
|
# Develope tools
|
|
40
41
|
"pycln==2.5.0",
|
|
@@ -61,6 +62,11 @@ dev = [
|
|
|
61
62
|
"aiobreaker>=0.3.0", # from aiobreaker
|
|
62
63
|
"dishka>=1.0", # scoped-deps dishka adapter tests / examples
|
|
63
64
|
"protobuf>=4.25.8", # protobuf codec / deserializer unit tests
|
|
65
|
+
# Full suite extras
|
|
66
|
+
"pydantic==2.*",
|
|
67
|
+
"sqlalchemy[asyncio]==2.0.*",
|
|
68
|
+
"sqlmodel>=0.0.22",
|
|
69
|
+
"aiosqlite>=0.20.0",
|
|
64
70
|
]
|
|
65
71
|
examples = [
|
|
66
72
|
"fastapi==0.109.*",
|
|
@@ -71,11 +77,12 @@ examples = [
|
|
|
71
77
|
"protobuf>=4.25.8",
|
|
72
78
|
"aiosqlite>=0.20.0",
|
|
73
79
|
"dishka>=1.0",
|
|
80
|
+
"pydantic==2.*",
|
|
81
|
+
"sqlalchemy[asyncio]==2.0.*",
|
|
74
82
|
]
|
|
75
83
|
kafka = ["aiokafka==0.10.0", "retry-async==0.1.*"]
|
|
76
84
|
protobuf = ["protobuf>=4.25.8"]
|
|
77
85
|
rabbit = ["aio-pika==9.3.0"]
|
|
78
|
-
sqlalchemy = ["sqlalchemy[asyncio]==2.0.*"]
|
|
79
86
|
dishka = ["dishka>=1.0"]
|
|
80
87
|
|
|
81
88
|
[project.urls]
|
|
@@ -88,6 +95,11 @@ addopts = "--junit-xml=report.xml"
|
|
|
88
95
|
asyncio_mode = "auto"
|
|
89
96
|
junit_family = "xunit1"
|
|
90
97
|
testpaths = ["tests"]
|
|
98
|
+
markers = [
|
|
99
|
+
"pydantic: tests that require the pydantic optional extra",
|
|
100
|
+
"sqlalchemy: tests that require the sqlalchemy optional extra",
|
|
101
|
+
"sqlmodel: tests that require the sqlmodel optional extra",
|
|
102
|
+
]
|
|
91
103
|
|
|
92
104
|
[tool.setuptools.packages.find]
|
|
93
105
|
where = ["src"]
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
if typing.TYPE_CHECKING:
|
|
4
|
+
from cqrs.models.pydantic import (
|
|
5
|
+
PydanticDomainEvent,
|
|
6
|
+
PydanticEvent,
|
|
7
|
+
PydanticNotificationEvent,
|
|
8
|
+
)
|
|
9
|
+
from cqrs.models.pydantic import PydanticRequest
|
|
10
|
+
from cqrs.models.pydantic import PydanticResponse
|
|
11
|
+
from cqrs.outbox.sqlalchemy import (
|
|
12
|
+
SqlAlchemyOutboxedEventRepository,
|
|
13
|
+
rebind_outbox_model,
|
|
14
|
+
)
|
|
15
|
+
from cqrs.outbox.sqlmodel import SqlModelOutboxedEventRepository
|
|
16
|
+
from cqrs.sqlalchemy_types import (
|
|
17
|
+
Binary16,
|
|
18
|
+
DialectAwareType,
|
|
19
|
+
DialectTypeHandler,
|
|
20
|
+
JSONType,
|
|
21
|
+
PayloadBinary,
|
|
22
|
+
UUIDBinary,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
from cqrs.compressors import Compressor, ZlibCompressor
|
|
27
|
+
from cqrs.container.di import DIContainer
|
|
28
|
+
from cqrs.container.protocol import Container, SupportsScope
|
|
29
|
+
from cqrs.container.scope import (
|
|
30
|
+
ScopeAwareContainer,
|
|
31
|
+
ScopeStrategy,
|
|
32
|
+
bind_scope,
|
|
33
|
+
current_container,
|
|
34
|
+
enter_scope,
|
|
35
|
+
)
|
|
36
|
+
from cqrs.circuit_breaker import ICircuitBreaker
|
|
37
|
+
from cqrs.events import EventMap
|
|
38
|
+
from cqrs.events.fallback import EventHandlerFallback
|
|
39
|
+
from cqrs.models.event import (
|
|
40
|
+
DCEvent,
|
|
41
|
+
DCDomainEvent,
|
|
42
|
+
DCNotificationEvent,
|
|
43
|
+
DomainEvent,
|
|
44
|
+
Event,
|
|
45
|
+
IDomainEvent,
|
|
46
|
+
IEvent,
|
|
47
|
+
INotificationEvent,
|
|
48
|
+
NotificationEvent,
|
|
49
|
+
)
|
|
50
|
+
from cqrs.events.event_emitter import EventEmitter
|
|
51
|
+
from cqrs.handlers.event import EventHandler
|
|
52
|
+
from cqrs.mediators import (
|
|
53
|
+
EventMediator,
|
|
54
|
+
RequestMediator,
|
|
55
|
+
SagaMediator,
|
|
56
|
+
StreamingRequestMediator,
|
|
57
|
+
)
|
|
58
|
+
from cqrs.mapping.outbox import OutboxedEventMap
|
|
59
|
+
from cqrs.outbox.repository import (
|
|
60
|
+
EventStatus,
|
|
61
|
+
OutboxedEvent,
|
|
62
|
+
OutboxedEventRepository,
|
|
63
|
+
)
|
|
64
|
+
from cqrs.message_brokers.producer import EventProducer
|
|
65
|
+
from cqrs.deserializers import DeserializeProtobufError, ProtobufDeserializer
|
|
66
|
+
from cqrs.serializers import (
|
|
67
|
+
EventCodec,
|
|
68
|
+
EventSerializer,
|
|
69
|
+
JsonEventSerializer,
|
|
70
|
+
ProtobufEventSerializer,
|
|
71
|
+
)
|
|
72
|
+
from cqrs.requests.fallback import RequestHandlerFallback
|
|
73
|
+
from cqrs.mapping.requests import RequestMap, SagaMap
|
|
74
|
+
from cqrs.mermaid.cor import CoRMermaid
|
|
75
|
+
from cqrs.models.request import DCRequest, IRequest, Request
|
|
76
|
+
from cqrs.handlers.request import (
|
|
77
|
+
RequestHandler,
|
|
78
|
+
StreamingRequestHandler,
|
|
79
|
+
)
|
|
80
|
+
from cqrs.models.response import DCResponse, IResponse, Response
|
|
81
|
+
from cqrs.mermaid.saga import SagaMermaid
|
|
82
|
+
from cqrs.saga.models import ContextT
|
|
83
|
+
from cqrs.saga.saga import Saga
|
|
84
|
+
from cqrs.handlers.saga import (
|
|
85
|
+
Resp,
|
|
86
|
+
SagaStepHandler,
|
|
87
|
+
SagaStepResult,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
from cqrs._dataclass_utils import pydantic_extra_error
|
|
92
|
+
|
|
93
|
+
__all__ = (
|
|
94
|
+
"ICircuitBreaker",
|
|
95
|
+
"EventHandlerFallback",
|
|
96
|
+
"RequestHandlerFallback",
|
|
97
|
+
"RequestMediator",
|
|
98
|
+
"SagaMediator",
|
|
99
|
+
"StreamingRequestMediator",
|
|
100
|
+
"EventMediator",
|
|
101
|
+
"DomainEvent",
|
|
102
|
+
"IDomainEvent",
|
|
103
|
+
"DCDomainEvent",
|
|
104
|
+
"PydanticDomainEvent",
|
|
105
|
+
"NotificationEvent",
|
|
106
|
+
"INotificationEvent",
|
|
107
|
+
"DCNotificationEvent",
|
|
108
|
+
"PydanticNotificationEvent",
|
|
109
|
+
"Event",
|
|
110
|
+
"IEvent",
|
|
111
|
+
"DCEvent",
|
|
112
|
+
"PydanticEvent",
|
|
113
|
+
"EventEmitter",
|
|
114
|
+
"EventHandler",
|
|
115
|
+
"EventMap",
|
|
116
|
+
"OutboxedEventMap",
|
|
117
|
+
"EventStatus",
|
|
118
|
+
"OutboxedEvent",
|
|
119
|
+
"Request",
|
|
120
|
+
"IRequest",
|
|
121
|
+
"DCRequest",
|
|
122
|
+
"PydanticRequest",
|
|
123
|
+
"RequestHandler",
|
|
124
|
+
"StreamingRequestHandler",
|
|
125
|
+
"RequestMap",
|
|
126
|
+
"SagaMap",
|
|
127
|
+
"Response",
|
|
128
|
+
"IResponse",
|
|
129
|
+
"DCResponse",
|
|
130
|
+
"PydanticResponse",
|
|
131
|
+
"OutboxedEventRepository",
|
|
132
|
+
"SqlAlchemyOutboxedEventRepository",
|
|
133
|
+
"SqlModelOutboxedEventRepository",
|
|
134
|
+
"EventProducer",
|
|
135
|
+
"EventSerializer",
|
|
136
|
+
"EventCodec",
|
|
137
|
+
"JsonEventSerializer",
|
|
138
|
+
"ProtobufEventSerializer",
|
|
139
|
+
"ProtobufDeserializer",
|
|
140
|
+
"DeserializeProtobufError",
|
|
141
|
+
"Container",
|
|
142
|
+
"SupportsScope",
|
|
143
|
+
"DIContainer",
|
|
144
|
+
"ScopeAwareContainer",
|
|
145
|
+
"ScopeStrategy",
|
|
146
|
+
"bind_scope",
|
|
147
|
+
"current_container",
|
|
148
|
+
"enter_scope",
|
|
149
|
+
"Compressor",
|
|
150
|
+
"ZlibCompressor",
|
|
151
|
+
"rebind_outbox_model",
|
|
152
|
+
"Saga",
|
|
153
|
+
"SagaStepHandler",
|
|
154
|
+
"SagaStepResult",
|
|
155
|
+
"Resp",
|
|
156
|
+
"ContextT",
|
|
157
|
+
"SagaMermaid",
|
|
158
|
+
"CoRMermaid",
|
|
159
|
+
"DialectAwareType",
|
|
160
|
+
"DialectTypeHandler",
|
|
161
|
+
"UUIDBinary",
|
|
162
|
+
"Binary16",
|
|
163
|
+
"JSONType",
|
|
164
|
+
"PayloadBinary",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
_LAZY_PYDANTIC = {
|
|
168
|
+
"PydanticEvent": ("cqrs.models.pydantic", "PydanticEvent"),
|
|
169
|
+
"PydanticDomainEvent": ("cqrs.models.pydantic", "PydanticDomainEvent"),
|
|
170
|
+
"PydanticNotificationEvent": (
|
|
171
|
+
"cqrs.models.pydantic",
|
|
172
|
+
"PydanticNotificationEvent",
|
|
173
|
+
),
|
|
174
|
+
"PydanticRequest": ("cqrs.models.pydantic", "PydanticRequest"),
|
|
175
|
+
"PydanticResponse": ("cqrs.models.pydantic", "PydanticResponse"),
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
_LAZY_SQLALCHEMY = {
|
|
179
|
+
"SqlAlchemyOutboxedEventRepository": (
|
|
180
|
+
"cqrs.outbox.sqlalchemy",
|
|
181
|
+
"SqlAlchemyOutboxedEventRepository",
|
|
182
|
+
),
|
|
183
|
+
"rebind_outbox_model": ("cqrs.outbox.sqlalchemy", "rebind_outbox_model"),
|
|
184
|
+
"DialectAwareType": ("cqrs.sqlalchemy_types", "DialectAwareType"),
|
|
185
|
+
"DialectTypeHandler": ("cqrs.sqlalchemy_types", "DialectTypeHandler"),
|
|
186
|
+
"UUIDBinary": ("cqrs.sqlalchemy_types", "UUIDBinary"),
|
|
187
|
+
"Binary16": ("cqrs.sqlalchemy_types", "Binary16"),
|
|
188
|
+
"JSONType": ("cqrs.sqlalchemy_types", "JSONType"),
|
|
189
|
+
"PayloadBinary": ("cqrs.sqlalchemy_types", "PayloadBinary"),
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
_LAZY_SQLMODEL = {
|
|
193
|
+
"SqlModelOutboxedEventRepository": (
|
|
194
|
+
"cqrs.outbox.sqlmodel",
|
|
195
|
+
"SqlModelOutboxedEventRepository",
|
|
196
|
+
),
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def __getattr__(name: str) -> typing.Any:
|
|
201
|
+
if name in _LAZY_PYDANTIC:
|
|
202
|
+
module_name, attr = _LAZY_PYDANTIC[name]
|
|
203
|
+
try:
|
|
204
|
+
module = __import__(module_name, fromlist=[attr])
|
|
205
|
+
except ImportError as exc:
|
|
206
|
+
raise pydantic_extra_error(name) from exc
|
|
207
|
+
return getattr(module, attr)
|
|
208
|
+
if name in _LAZY_SQLALCHEMY:
|
|
209
|
+
module_name, attr = _LAZY_SQLALCHEMY[name]
|
|
210
|
+
# ImportError message is raised by the sqlalchemy modules themselves.
|
|
211
|
+
module = __import__(module_name, fromlist=[attr])
|
|
212
|
+
return getattr(module, attr)
|
|
213
|
+
if name in _LAZY_SQLMODEL:
|
|
214
|
+
module_name, attr = _LAZY_SQLMODEL[name]
|
|
215
|
+
# ImportError message is raised by the sqlmodel modules themselves.
|
|
216
|
+
module = __import__(module_name, fromlist=[attr])
|
|
217
|
+
return getattr(module, attr)
|
|
218
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|