python-cqrs 4.15.0__tar.gz → 5.0.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.0/src/python_cqrs.egg-info → python_cqrs-5.0.0}/PKG-INFO +70 -27
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/README.md +61 -22
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/pyproject.toml +12 -4
- python_cqrs-5.0.0/src/cqrs/__init__.py +204 -0
- python_cqrs-5.0.0/src/cqrs/_dataclass_utils.py +99 -0
- python_cqrs-5.0.0/src/cqrs/bootstrap/__init__.py +5 -0
- python_cqrs-4.15.0/src/cqrs/requests/bootstrap.py → python_cqrs-5.0.0/src/cqrs/bootstrap/requests.py +1 -1
- python_cqrs-4.15.0/src/cqrs/saga/bootstrap.py → python_cqrs-5.0.0/src/cqrs/bootstrap/saga.py +4 -4
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/event.py +3 -3
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/models.py +3 -3
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/request.py +4 -4
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/saga.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/streaming.py +3 -3
- python_cqrs-5.0.0/src/cqrs/events/__init__.py +63 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/events/event_emitter.py +3 -2
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/events/event_processor.py +2 -2
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/events/fallback.py +1 -1
- python_cqrs-5.0.0/src/cqrs/handlers/__init__.py +14 -0
- python_cqrs-4.15.0/src/cqrs/requests/cor_request_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/cor.py +2 -2
- python_cqrs-4.15.0/src/cqrs/events/event_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/event.py +1 -1
- python_cqrs-4.15.0/src/cqrs/requests/request_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/request.py +2 -2
- python_cqrs-4.15.0/src/cqrs/saga/step.py → python_cqrs-5.0.0/src/cqrs/handlers/saga.py +2 -2
- python_cqrs-5.0.0/src/cqrs/mapping/__init__.py +5 -0
- python_cqrs-4.15.0/src/cqrs/events/map.py → python_cqrs-5.0.0/src/cqrs/mapping/events.py +2 -2
- python_cqrs-4.15.0/src/cqrs/outbox/map.py → python_cqrs-5.0.0/src/cqrs/mapping/outbox.py +1 -1
- python_cqrs-4.15.0/src/cqrs/requests/map.py → python_cqrs-5.0.0/src/cqrs/mapping/requests.py +3 -3
- python_cqrs-5.0.0/src/cqrs/mediators/__init__.py +11 -0
- python_cqrs-5.0.0/src/cqrs/mediators/_common.py +26 -0
- python_cqrs-5.0.0/src/cqrs/mediators/event.py +50 -0
- python_cqrs-5.0.0/src/cqrs/mediators/request.py +109 -0
- python_cqrs-5.0.0/src/cqrs/mediators/saga.py +152 -0
- python_cqrs-5.0.0/src/cqrs/mediators/streaming.py +128 -0
- python_cqrs-5.0.0/src/cqrs/mermaid/__init__.py +4 -0
- python_cqrs-4.15.0/src/cqrs/requests/mermaid.py → python_cqrs-5.0.0/src/cqrs/mermaid/cor.py +1 -1
- python_cqrs-4.15.0/src/cqrs/saga/mermaid.py → python_cqrs-5.0.0/src/cqrs/mermaid/saga.py +1 -1
- {python_cqrs-4.15.0/src/cqrs → python_cqrs-5.0.0/src/cqrs/message_brokers}/producer.py +7 -4
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/middlewares/base.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/middlewares/logging.py +2 -2
- python_cqrs-5.0.0/src/cqrs/models/__init__.py +57 -0
- python_cqrs-5.0.0/src/cqrs/models/event.py +208 -0
- python_cqrs-5.0.0/src/cqrs/models/pydantic.py +130 -0
- python_cqrs-5.0.0/src/cqrs/models/request.py +81 -0
- python_cqrs-5.0.0/src/cqrs/models/response.py +74 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/outbox/mock.py +2 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/outbox/repository.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/outbox/sqlalchemy.py +15 -3
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/requests/fallback.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/circuit_breaker.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/compensation.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/execution.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/fallback.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/saga.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/validation.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/serializers/default.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/serializers/json.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/serializers/protobuf.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/serializers/protocol.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/types.py +1 -1
- {python_cqrs-4.15.0 → python_cqrs-5.0.0/src/python_cqrs.egg-info}/PKG-INFO +70 -27
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/SOURCES.txt +29 -17
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/requires.txt +7 -2
- python_cqrs-4.15.0/src/cqrs/__init__.py +0 -151
- python_cqrs-4.15.0/src/cqrs/events/__init__.py +0 -50
- python_cqrs-4.15.0/src/cqrs/events/event.py +0 -393
- python_cqrs-4.15.0/src/cqrs/mediator.py +0 -423
- python_cqrs-4.15.0/src/cqrs/requests/request.py +0 -152
- python_cqrs-4.15.0/src/cqrs/response.py +0 -146
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/LICENSE +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/setup.cfg +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/adapters/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/adapters/amqp.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/adapters/circuit_breaker.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/adapters/kafka.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/adapters/protocol.py +0 -0
- /python_cqrs-4.15.0/src/cqrs/events/bootstrap.py → /python_cqrs-5.0.0/src/cqrs/bootstrap/events.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/circuit_breaker.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/compressors/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/compressors/protocol.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/compressors/zlib.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/container/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/container/dependency_injector.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/container/di.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/container/dishka.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/container/protocol.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/container/scope.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/deserializers/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/deserializers/exceptions.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/deserializers/json.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/deserializers/protobuf.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/exceptions.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/generic_utils.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/amqp.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/devnull.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/kafka.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/protocol.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/middlewares/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/outbox/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/requests/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/models.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/recovery.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/enums.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/memory.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/models.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/protocol.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/sqlalchemy.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/serializers/__init__.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/cqrs/sqlalchemy_types.py +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/dependency_links.txt +0 -0
- {python_cqrs-4.15.0 → python_cqrs-5.0.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.0.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,14 @@ 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"
|
|
30
32
|
Provides-Extra: dev
|
|
31
33
|
Requires-Dist: pycln==2.5.0; extra == "dev"
|
|
32
34
|
Requires-Dist: pre-commit==3.8.0; extra == "dev"
|
|
@@ -50,6 +52,8 @@ Requires-Dist: redis>=5.0.0; extra == "dev"
|
|
|
50
52
|
Requires-Dist: aiobreaker>=0.3.0; extra == "dev"
|
|
51
53
|
Requires-Dist: dishka>=1.0; extra == "dev"
|
|
52
54
|
Requires-Dist: protobuf>=4.25.8; extra == "dev"
|
|
55
|
+
Requires-Dist: pydantic==2.*; extra == "dev"
|
|
56
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "dev"
|
|
53
57
|
Provides-Extra: examples
|
|
54
58
|
Requires-Dist: fastapi==0.109.*; extra == "examples"
|
|
55
59
|
Requires-Dist: faststream[kafka]==0.5.28; extra == "examples"
|
|
@@ -59,6 +63,8 @@ Requires-Dist: aiohttp==3.14.3; extra == "examples"
|
|
|
59
63
|
Requires-Dist: protobuf>=4.25.8; extra == "examples"
|
|
60
64
|
Requires-Dist: aiosqlite>=0.20.0; extra == "examples"
|
|
61
65
|
Requires-Dist: dishka>=1.0; extra == "examples"
|
|
66
|
+
Requires-Dist: pydantic==2.*; extra == "examples"
|
|
67
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "examples"
|
|
62
68
|
Provides-Extra: kafka
|
|
63
69
|
Requires-Dist: aiokafka==0.10.0; extra == "kafka"
|
|
64
70
|
Requires-Dist: retry-async==0.1.*; extra == "kafka"
|
|
@@ -66,8 +72,6 @@ Provides-Extra: protobuf
|
|
|
66
72
|
Requires-Dist: protobuf>=4.25.8; extra == "protobuf"
|
|
67
73
|
Provides-Extra: rabbit
|
|
68
74
|
Requires-Dist: aio-pika==9.3.0; extra == "rabbit"
|
|
69
|
-
Provides-Extra: sqlalchemy
|
|
70
|
-
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "sqlalchemy"
|
|
71
75
|
Provides-Extra: dishka
|
|
72
76
|
Requires-Dist: dishka>=1.0; extra == "dishka"
|
|
73
77
|
Dynamic: license-file
|
|
@@ -119,6 +123,7 @@ Dynamic: license-file
|
|
|
119
123
|
- [Overview](#overview)
|
|
120
124
|
- [When NOT to use python-cqrs](#when-not-to-use-python-cqrs)
|
|
121
125
|
- [Installation](#installation)
|
|
126
|
+
- [Version Support](#version-support)
|
|
122
127
|
- [Quick Start](#quick-start)
|
|
123
128
|
- [Request and Response Types](#request-and-response-types)
|
|
124
129
|
- [Request Handlers](#request-handlers)
|
|
@@ -184,14 +189,52 @@ Do not add a Saga for a single `UPDATE` in one service, and do not use a Saga as
|
|
|
184
189
|
pip install python-cqrs
|
|
185
190
|
```
|
|
186
191
|
|
|
187
|
-
Optional
|
|
192
|
+
Optional extras (5.0+ — pydantic and SQLAlchemy are no longer core dependencies):
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
pip install "python-cqrs[pydantic]" # PydanticRequest / Pydantic* events
|
|
196
|
+
pip install "python-cqrs[sqlalchemy]" # Outbox / Saga SQLAlchemy storage
|
|
197
|
+
pip install "python-cqrs[kafka]" # Kafka broker (aiokafka)
|
|
198
|
+
pip install "python-cqrs[examples]" # FastAPI, FastStream, uvicorn, etc.
|
|
199
|
+
pip install "python-cqrs[aiobreaker]" # Circuit breaker for saga fallbacks
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Default `Request` / `Response` / `Event` / `DomainEvent` / `NotificationEvent` aliases
|
|
203
|
+
are dataclass-based (`DC*`). Use `Pydantic*` types with the pydantic extra when you
|
|
204
|
+
need validation.
|
|
205
|
+
|
|
206
|
+
### Import paths (5.0+)
|
|
207
|
+
|
|
208
|
+
| Area | Import |
|
|
209
|
+
|------|--------|
|
|
210
|
+
| Bootstrap | `from cqrs.bootstrap import requests, events, saga` |
|
|
211
|
+
| Mediators | `from cqrs.mediators import RequestMediator, SagaMediator, …` |
|
|
212
|
+
| Handlers | `from cqrs.handlers import RequestHandler, EventHandler, …` |
|
|
213
|
+
| Models | `from cqrs.models import Request, Event, …` / `cqrs.models.pydantic` |
|
|
214
|
+
| Maps | `from cqrs.mapping import RequestMap, EventMap, OutboxedEventMap` |
|
|
215
|
+
| Mermaid | `from cqrs.mermaid import CoRMermaid, SagaMermaid` |
|
|
216
|
+
| Outbox producer | `from cqrs.message_brokers.producer import EventProducer` |
|
|
217
|
+
|
|
218
|
+
`SagaMediator.execute(...)` replaces the former `SagaMediator.stream(...)`
|
|
219
|
+
(StreamingRequestMediator.stream is unchanged).
|
|
220
|
+
|
|
221
|
+
## Version Support
|
|
222
|
+
|
|
223
|
+
| Line | Git branch | What changes |
|
|
224
|
+
|------|------------|--------------|
|
|
225
|
+
| **4.x** | `4.x` | Bug fixes and security only (~12 months after 5.0.0) |
|
|
226
|
+
| **5.x** | `master` | Features and breaking changes |
|
|
227
|
+
|
|
228
|
+
Stay on 4.x until you migrate:
|
|
188
229
|
|
|
189
230
|
```bash
|
|
190
|
-
pip install python-cqrs
|
|
191
|
-
pip install python-cqrs[examples] # FastAPI, FastStream, uvicorn, etc.
|
|
192
|
-
pip install python-cqrs[aiobreaker] # Circuit breaker for saga fallbacks
|
|
231
|
+
pip install "python-cqrs>=4,<5"
|
|
193
232
|
```
|
|
194
233
|
|
|
234
|
+
Docs: [4.x](https://mkdocs.python-cqrs.dev/4.0/) and [5.x / latest](https://mkdocs.python-cqrs.dev/latest/) (version switcher after mike deploy). See [SECURITY.md](SECURITY.md) for the support window and vulnerability reporting, and [CONTRIBUTING.md](CONTRIBUTING.md#8-maintaining--fixing-4x) for how to contribute 4.x bugfixes.
|
|
235
|
+
|
|
236
|
+
A package-level EOL `DeprecationWarning` toward 5.x will be added on the **first 4.x patch after 5.0.0** — not before.
|
|
237
|
+
|
|
195
238
|
## Quick Start
|
|
196
239
|
|
|
197
240
|
Define a command, a handler, bind them, and run via the mediator:
|
|
@@ -199,7 +242,7 @@ Define a command, a handler, bind them, and run via the mediator:
|
|
|
199
242
|
```python
|
|
200
243
|
import di
|
|
201
244
|
import cqrs
|
|
202
|
-
from cqrs.
|
|
245
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
203
246
|
|
|
204
247
|
class CreateOrderCommand(cqrs.Request):
|
|
205
248
|
order_id: str
|
|
@@ -287,8 +330,8 @@ As a result of executing the command, an event may be produced to the broker.
|
|
|
287
330
|
> By default, the command handler does not return any result, but it is not mandatory.
|
|
288
331
|
|
|
289
332
|
```python
|
|
290
|
-
from cqrs.
|
|
291
|
-
from cqrs.
|
|
333
|
+
from cqrs.handlers.request import RequestHandler
|
|
334
|
+
from cqrs.models.event import Event
|
|
292
335
|
|
|
293
336
|
class JoinMeetingCommandHandler(RequestHandler[JoinMeetingCommand, None]):
|
|
294
337
|
|
|
@@ -315,8 +358,8 @@ the [read model](https://radekmaziarka.pl/2018/01/08/cqrs-third-step-simple-read
|
|
|
315
358
|
> The read model can be constructed based on domain events produced by the `Command Handler`.
|
|
316
359
|
|
|
317
360
|
```python
|
|
318
|
-
from cqrs.
|
|
319
|
-
from cqrs.
|
|
361
|
+
from cqrs.handlers.request import RequestHandler
|
|
362
|
+
from cqrs.models.event import Event
|
|
320
363
|
|
|
321
364
|
class ReadMeetingQueryHandler(RequestHandler[ReadMeetingQuery, ReadMeetingQueryResult]):
|
|
322
365
|
|
|
@@ -347,8 +390,8 @@ real-time progress updates.
|
|
|
347
390
|
|
|
348
391
|
```python
|
|
349
392
|
import typing
|
|
350
|
-
from cqrs.
|
|
351
|
-
from cqrs.
|
|
393
|
+
from cqrs.handlers.request import StreamingRequestHandler
|
|
394
|
+
from cqrs.models.event import Event
|
|
352
395
|
|
|
353
396
|
class ProcessFilesCommandHandler(StreamingRequestHandler[ProcessFilesCommand, FileProcessedResult]):
|
|
354
397
|
def __init__(self):
|
|
@@ -384,8 +427,8 @@ when a handler successfully processes the request or when all handlers have been
|
|
|
384
427
|
|
|
385
428
|
```python
|
|
386
429
|
import typing
|
|
387
|
-
from cqrs.
|
|
388
|
-
from cqrs.
|
|
430
|
+
from cqrs.handlers.cor import CORRequestHandler
|
|
431
|
+
from cqrs.models.event import Event
|
|
389
432
|
|
|
390
433
|
class CreditCardPaymentHandler(CORRequestHandler[ProcessPaymentCommand, PaymentResult]):
|
|
391
434
|
def __init__(self, payment_service: PaymentServiceProtocol) -> None:
|
|
@@ -441,7 +484,7 @@ the [documentation](https://github.com/vadikko2/python-cqrs/blob/master/examples
|
|
|
441
484
|
The package includes built-in support for generating Mermaid diagrams from Chain of Responsibility handler chains.
|
|
442
485
|
|
|
443
486
|
```python
|
|
444
|
-
from cqrs.
|
|
487
|
+
from cqrs.mermaid.cor import CoRMermaid
|
|
445
488
|
|
|
446
489
|
# Create Mermaid generator from handler chain
|
|
447
490
|
handlers = [CreditCardHandler, PayPalHandler, DefaultHandler]
|
|
@@ -611,8 +654,8 @@ application.
|
|
|
611
654
|
```python
|
|
612
655
|
import functools
|
|
613
656
|
|
|
614
|
-
from cqrs.
|
|
615
|
-
from cqrs.
|
|
657
|
+
from cqrs.bootstrap import events as event_bootstrap
|
|
658
|
+
from cqrs.bootstrap import requests as bootstrap as request_bootstrap
|
|
616
659
|
|
|
617
660
|
from app import dependencies, mapping, orm
|
|
618
661
|
|
|
@@ -668,7 +711,7 @@ import dataclasses
|
|
|
668
711
|
import uuid
|
|
669
712
|
from cqrs.saga.models import SagaContext
|
|
670
713
|
from cqrs.saga.saga import Saga
|
|
671
|
-
from cqrs.saga
|
|
714
|
+
from cqrs.handlers.saga import SagaStepHandler
|
|
672
715
|
|
|
673
716
|
@dataclasses.dataclass
|
|
674
717
|
class OrderContext(SagaContext):
|
|
@@ -690,7 +733,7 @@ class OrderSaga(Saga[OrderContext]):
|
|
|
690
733
|
context = OrderContext(order_id="123", user_id="user_1", items=["item_1"], total_amount=100.0)
|
|
691
734
|
saga_id = uuid.uuid4()
|
|
692
735
|
|
|
693
|
-
async for step_result in mediator.
|
|
736
|
+
async for step_result in mediator.execute(context, saga_id=saga_id):
|
|
694
737
|
print(f"Step completed: {step_result.step_type.__name__}")
|
|
695
738
|
# If any step fails, compensation happens automatically
|
|
696
739
|
```
|
|
@@ -703,7 +746,7 @@ The saga pattern supports fallback steps that execute automatically when primary
|
|
|
703
746
|
from cqrs.saga.fallback import Fallback
|
|
704
747
|
from cqrs.adapters.circuit_breaker import AioBreakerAdapter
|
|
705
748
|
from cqrs.response import Response
|
|
706
|
-
from cqrs.saga
|
|
749
|
+
from cqrs.handlers.saga import SagaStepHandler, SagaStepResult
|
|
707
750
|
|
|
708
751
|
class ReserveInventoryResponse(Response):
|
|
709
752
|
reservation_id: str
|
|
@@ -786,7 +829,7 @@ The recovery mechanism ensures eventual consistency by:
|
|
|
786
829
|
The package includes built-in support for generating Mermaid diagrams from Saga instances.
|
|
787
830
|
|
|
788
831
|
```python
|
|
789
|
-
from cqrs.saga
|
|
832
|
+
from cqrs.mermaid.saga import SagaMermaid
|
|
790
833
|
|
|
791
834
|
# Create Mermaid generator from saga class
|
|
792
835
|
saga = OrderSaga()
|
|
@@ -1026,7 +1069,7 @@ This feature is especially useful when:
|
|
|
1026
1069
|
**Configuration:**
|
|
1027
1070
|
|
|
1028
1071
|
```python
|
|
1029
|
-
from cqrs.
|
|
1072
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
1030
1073
|
|
|
1031
1074
|
mediator = bootstrap.bootstrap_streaming(
|
|
1032
1075
|
di_container=container,
|
|
@@ -1143,7 +1186,7 @@ This allows you to stream results to clients in real-time as they are processed.
|
|
|
1143
1186
|
```python
|
|
1144
1187
|
import fastapi
|
|
1145
1188
|
import json
|
|
1146
|
-
from cqrs.
|
|
1189
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
1147
1190
|
|
|
1148
1191
|
def streaming_mediator_factory() -> cqrs.StreamingRequestMediator:
|
|
1149
1192
|
return bootstrap.bootstrap_streaming(
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
- [Overview](#overview)
|
|
46
46
|
- [When NOT to use python-cqrs](#when-not-to-use-python-cqrs)
|
|
47
47
|
- [Installation](#installation)
|
|
48
|
+
- [Version Support](#version-support)
|
|
48
49
|
- [Quick Start](#quick-start)
|
|
49
50
|
- [Request and Response Types](#request-and-response-types)
|
|
50
51
|
- [Request Handlers](#request-handlers)
|
|
@@ -110,14 +111,52 @@ Do not add a Saga for a single `UPDATE` in one service, and do not use a Saga as
|
|
|
110
111
|
pip install python-cqrs
|
|
111
112
|
```
|
|
112
113
|
|
|
113
|
-
Optional
|
|
114
|
+
Optional extras (5.0+ — pydantic and SQLAlchemy are no longer core dependencies):
|
|
114
115
|
|
|
115
116
|
```bash
|
|
116
|
-
pip install python-cqrs[
|
|
117
|
-
pip install python-cqrs[
|
|
118
|
-
pip install python-cqrs[
|
|
117
|
+
pip install "python-cqrs[pydantic]" # PydanticRequest / Pydantic* events
|
|
118
|
+
pip install "python-cqrs[sqlalchemy]" # Outbox / Saga SQLAlchemy storage
|
|
119
|
+
pip install "python-cqrs[kafka]" # Kafka broker (aiokafka)
|
|
120
|
+
pip install "python-cqrs[examples]" # FastAPI, FastStream, uvicorn, etc.
|
|
121
|
+
pip install "python-cqrs[aiobreaker]" # Circuit breaker for saga fallbacks
|
|
119
122
|
```
|
|
120
123
|
|
|
124
|
+
Default `Request` / `Response` / `Event` / `DomainEvent` / `NotificationEvent` aliases
|
|
125
|
+
are dataclass-based (`DC*`). Use `Pydantic*` types with the pydantic extra when you
|
|
126
|
+
need validation.
|
|
127
|
+
|
|
128
|
+
### Import paths (5.0+)
|
|
129
|
+
|
|
130
|
+
| Area | Import |
|
|
131
|
+
|------|--------|
|
|
132
|
+
| Bootstrap | `from cqrs.bootstrap import requests, events, saga` |
|
|
133
|
+
| Mediators | `from cqrs.mediators import RequestMediator, SagaMediator, …` |
|
|
134
|
+
| Handlers | `from cqrs.handlers import RequestHandler, EventHandler, …` |
|
|
135
|
+
| Models | `from cqrs.models import Request, Event, …` / `cqrs.models.pydantic` |
|
|
136
|
+
| Maps | `from cqrs.mapping import RequestMap, EventMap, OutboxedEventMap` |
|
|
137
|
+
| Mermaid | `from cqrs.mermaid import CoRMermaid, SagaMermaid` |
|
|
138
|
+
| Outbox producer | `from cqrs.message_brokers.producer import EventProducer` |
|
|
139
|
+
|
|
140
|
+
`SagaMediator.execute(...)` replaces the former `SagaMediator.stream(...)`
|
|
141
|
+
(StreamingRequestMediator.stream is unchanged).
|
|
142
|
+
|
|
143
|
+
## Version Support
|
|
144
|
+
|
|
145
|
+
| Line | Git branch | What changes |
|
|
146
|
+
|------|------------|--------------|
|
|
147
|
+
| **4.x** | `4.x` | Bug fixes and security only (~12 months after 5.0.0) |
|
|
148
|
+
| **5.x** | `master` | Features and breaking changes |
|
|
149
|
+
|
|
150
|
+
Stay on 4.x until you migrate:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pip install "python-cqrs>=4,<5"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Docs: [4.x](https://mkdocs.python-cqrs.dev/4.0/) and [5.x / latest](https://mkdocs.python-cqrs.dev/latest/) (version switcher after mike deploy). See [SECURITY.md](SECURITY.md) for the support window and vulnerability reporting, and [CONTRIBUTING.md](CONTRIBUTING.md#8-maintaining--fixing-4x) for how to contribute 4.x bugfixes.
|
|
157
|
+
|
|
158
|
+
A package-level EOL `DeprecationWarning` toward 5.x will be added on the **first 4.x patch after 5.0.0** — not before.
|
|
159
|
+
|
|
121
160
|
## Quick Start
|
|
122
161
|
|
|
123
162
|
Define a command, a handler, bind them, and run via the mediator:
|
|
@@ -125,7 +164,7 @@ Define a command, a handler, bind them, and run via the mediator:
|
|
|
125
164
|
```python
|
|
126
165
|
import di
|
|
127
166
|
import cqrs
|
|
128
|
-
from cqrs.
|
|
167
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
129
168
|
|
|
130
169
|
class CreateOrderCommand(cqrs.Request):
|
|
131
170
|
order_id: str
|
|
@@ -213,8 +252,8 @@ As a result of executing the command, an event may be produced to the broker.
|
|
|
213
252
|
> By default, the command handler does not return any result, but it is not mandatory.
|
|
214
253
|
|
|
215
254
|
```python
|
|
216
|
-
from cqrs.
|
|
217
|
-
from cqrs.
|
|
255
|
+
from cqrs.handlers.request import RequestHandler
|
|
256
|
+
from cqrs.models.event import Event
|
|
218
257
|
|
|
219
258
|
class JoinMeetingCommandHandler(RequestHandler[JoinMeetingCommand, None]):
|
|
220
259
|
|
|
@@ -241,8 +280,8 @@ the [read model](https://radekmaziarka.pl/2018/01/08/cqrs-third-step-simple-read
|
|
|
241
280
|
> The read model can be constructed based on domain events produced by the `Command Handler`.
|
|
242
281
|
|
|
243
282
|
```python
|
|
244
|
-
from cqrs.
|
|
245
|
-
from cqrs.
|
|
283
|
+
from cqrs.handlers.request import RequestHandler
|
|
284
|
+
from cqrs.models.event import Event
|
|
246
285
|
|
|
247
286
|
class ReadMeetingQueryHandler(RequestHandler[ReadMeetingQuery, ReadMeetingQueryResult]):
|
|
248
287
|
|
|
@@ -273,8 +312,8 @@ real-time progress updates.
|
|
|
273
312
|
|
|
274
313
|
```python
|
|
275
314
|
import typing
|
|
276
|
-
from cqrs.
|
|
277
|
-
from cqrs.
|
|
315
|
+
from cqrs.handlers.request import StreamingRequestHandler
|
|
316
|
+
from cqrs.models.event import Event
|
|
278
317
|
|
|
279
318
|
class ProcessFilesCommandHandler(StreamingRequestHandler[ProcessFilesCommand, FileProcessedResult]):
|
|
280
319
|
def __init__(self):
|
|
@@ -310,8 +349,8 @@ when a handler successfully processes the request or when all handlers have been
|
|
|
310
349
|
|
|
311
350
|
```python
|
|
312
351
|
import typing
|
|
313
|
-
from cqrs.
|
|
314
|
-
from cqrs.
|
|
352
|
+
from cqrs.handlers.cor import CORRequestHandler
|
|
353
|
+
from cqrs.models.event import Event
|
|
315
354
|
|
|
316
355
|
class CreditCardPaymentHandler(CORRequestHandler[ProcessPaymentCommand, PaymentResult]):
|
|
317
356
|
def __init__(self, payment_service: PaymentServiceProtocol) -> None:
|
|
@@ -367,7 +406,7 @@ the [documentation](https://github.com/vadikko2/python-cqrs/blob/master/examples
|
|
|
367
406
|
The package includes built-in support for generating Mermaid diagrams from Chain of Responsibility handler chains.
|
|
368
407
|
|
|
369
408
|
```python
|
|
370
|
-
from cqrs.
|
|
409
|
+
from cqrs.mermaid.cor import CoRMermaid
|
|
371
410
|
|
|
372
411
|
# Create Mermaid generator from handler chain
|
|
373
412
|
handlers = [CreditCardHandler, PayPalHandler, DefaultHandler]
|
|
@@ -537,8 +576,8 @@ application.
|
|
|
537
576
|
```python
|
|
538
577
|
import functools
|
|
539
578
|
|
|
540
|
-
from cqrs.
|
|
541
|
-
from cqrs.
|
|
579
|
+
from cqrs.bootstrap import events as event_bootstrap
|
|
580
|
+
from cqrs.bootstrap import requests as bootstrap as request_bootstrap
|
|
542
581
|
|
|
543
582
|
from app import dependencies, mapping, orm
|
|
544
583
|
|
|
@@ -594,7 +633,7 @@ import dataclasses
|
|
|
594
633
|
import uuid
|
|
595
634
|
from cqrs.saga.models import SagaContext
|
|
596
635
|
from cqrs.saga.saga import Saga
|
|
597
|
-
from cqrs.saga
|
|
636
|
+
from cqrs.handlers.saga import SagaStepHandler
|
|
598
637
|
|
|
599
638
|
@dataclasses.dataclass
|
|
600
639
|
class OrderContext(SagaContext):
|
|
@@ -616,7 +655,7 @@ class OrderSaga(Saga[OrderContext]):
|
|
|
616
655
|
context = OrderContext(order_id="123", user_id="user_1", items=["item_1"], total_amount=100.0)
|
|
617
656
|
saga_id = uuid.uuid4()
|
|
618
657
|
|
|
619
|
-
async for step_result in mediator.
|
|
658
|
+
async for step_result in mediator.execute(context, saga_id=saga_id):
|
|
620
659
|
print(f"Step completed: {step_result.step_type.__name__}")
|
|
621
660
|
# If any step fails, compensation happens automatically
|
|
622
661
|
```
|
|
@@ -629,7 +668,7 @@ The saga pattern supports fallback steps that execute automatically when primary
|
|
|
629
668
|
from cqrs.saga.fallback import Fallback
|
|
630
669
|
from cqrs.adapters.circuit_breaker import AioBreakerAdapter
|
|
631
670
|
from cqrs.response import Response
|
|
632
|
-
from cqrs.saga
|
|
671
|
+
from cqrs.handlers.saga import SagaStepHandler, SagaStepResult
|
|
633
672
|
|
|
634
673
|
class ReserveInventoryResponse(Response):
|
|
635
674
|
reservation_id: str
|
|
@@ -712,7 +751,7 @@ The recovery mechanism ensures eventual consistency by:
|
|
|
712
751
|
The package includes built-in support for generating Mermaid diagrams from Saga instances.
|
|
713
752
|
|
|
714
753
|
```python
|
|
715
|
-
from cqrs.saga
|
|
754
|
+
from cqrs.mermaid.saga import SagaMermaid
|
|
716
755
|
|
|
717
756
|
# Create Mermaid generator from saga class
|
|
718
757
|
saga = OrderSaga()
|
|
@@ -952,7 +991,7 @@ This feature is especially useful when:
|
|
|
952
991
|
**Configuration:**
|
|
953
992
|
|
|
954
993
|
```python
|
|
955
|
-
from cqrs.
|
|
994
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
956
995
|
|
|
957
996
|
mediator = bootstrap.bootstrap_streaming(
|
|
958
997
|
di_container=container,
|
|
@@ -1069,7 +1108,7 @@ This allows you to stream results to clients in real-time as they are processed.
|
|
|
1069
1108
|
```python
|
|
1070
1109
|
import fastapi
|
|
1071
1110
|
import json
|
|
1072
|
-
from cqrs.
|
|
1111
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
1073
1112
|
|
|
1074
1113
|
def streaming_mediator_factory() -> cqrs.StreamingRequestMediator:
|
|
1075
1114
|
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,12 @@ 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.0.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
38
|
dev = [
|
|
39
39
|
# Develope tools
|
|
40
40
|
"pycln==2.5.0",
|
|
@@ -61,6 +61,9 @@ dev = [
|
|
|
61
61
|
"aiobreaker>=0.3.0", # from aiobreaker
|
|
62
62
|
"dishka>=1.0", # scoped-deps dishka adapter tests / examples
|
|
63
63
|
"protobuf>=4.25.8", # protobuf codec / deserializer unit tests
|
|
64
|
+
# Full suite extras
|
|
65
|
+
"pydantic==2.*",
|
|
66
|
+
"sqlalchemy[asyncio]==2.0.*",
|
|
64
67
|
]
|
|
65
68
|
examples = [
|
|
66
69
|
"fastapi==0.109.*",
|
|
@@ -71,11 +74,12 @@ examples = [
|
|
|
71
74
|
"protobuf>=4.25.8",
|
|
72
75
|
"aiosqlite>=0.20.0",
|
|
73
76
|
"dishka>=1.0",
|
|
77
|
+
"pydantic==2.*",
|
|
78
|
+
"sqlalchemy[asyncio]==2.0.*",
|
|
74
79
|
]
|
|
75
80
|
kafka = ["aiokafka==0.10.0", "retry-async==0.1.*"]
|
|
76
81
|
protobuf = ["protobuf>=4.25.8"]
|
|
77
82
|
rabbit = ["aio-pika==9.3.0"]
|
|
78
|
-
sqlalchemy = ["sqlalchemy[asyncio]==2.0.*"]
|
|
79
83
|
dishka = ["dishka>=1.0"]
|
|
80
84
|
|
|
81
85
|
[project.urls]
|
|
@@ -88,6 +92,10 @@ addopts = "--junit-xml=report.xml"
|
|
|
88
92
|
asyncio_mode = "auto"
|
|
89
93
|
junit_family = "xunit1"
|
|
90
94
|
testpaths = ["tests"]
|
|
95
|
+
markers = [
|
|
96
|
+
"pydantic: tests that require the pydantic optional extra",
|
|
97
|
+
"sqlalchemy: tests that require the sqlalchemy optional extra",
|
|
98
|
+
]
|
|
91
99
|
|
|
92
100
|
[tool.setuptools.packages.find]
|
|
93
101
|
where = ["src"]
|
|
@@ -0,0 +1,204 @@
|
|
|
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.sqlalchemy_types import (
|
|
16
|
+
Binary16,
|
|
17
|
+
DialectAwareType,
|
|
18
|
+
DialectTypeHandler,
|
|
19
|
+
JSONType,
|
|
20
|
+
PayloadBinary,
|
|
21
|
+
UUIDBinary,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from cqrs.compressors import Compressor, ZlibCompressor
|
|
26
|
+
from cqrs.container.di import DIContainer
|
|
27
|
+
from cqrs.container.protocol import Container, SupportsScope
|
|
28
|
+
from cqrs.container.scope import (
|
|
29
|
+
ScopeAwareContainer,
|
|
30
|
+
ScopeStrategy,
|
|
31
|
+
bind_scope,
|
|
32
|
+
current_container,
|
|
33
|
+
enter_scope,
|
|
34
|
+
)
|
|
35
|
+
from cqrs.circuit_breaker import ICircuitBreaker
|
|
36
|
+
from cqrs.events import EventMap
|
|
37
|
+
from cqrs.events.fallback import EventHandlerFallback
|
|
38
|
+
from cqrs.models.event import (
|
|
39
|
+
DCEvent,
|
|
40
|
+
DCDomainEvent,
|
|
41
|
+
DCNotificationEvent,
|
|
42
|
+
DomainEvent,
|
|
43
|
+
Event,
|
|
44
|
+
IDomainEvent,
|
|
45
|
+
IEvent,
|
|
46
|
+
INotificationEvent,
|
|
47
|
+
NotificationEvent,
|
|
48
|
+
)
|
|
49
|
+
from cqrs.events.event_emitter import EventEmitter
|
|
50
|
+
from cqrs.handlers.event import EventHandler
|
|
51
|
+
from cqrs.mediators import (
|
|
52
|
+
EventMediator,
|
|
53
|
+
RequestMediator,
|
|
54
|
+
SagaMediator,
|
|
55
|
+
StreamingRequestMediator,
|
|
56
|
+
)
|
|
57
|
+
from cqrs.mapping.outbox import OutboxedEventMap
|
|
58
|
+
from cqrs.outbox.repository import (
|
|
59
|
+
EventStatus,
|
|
60
|
+
OutboxedEvent,
|
|
61
|
+
OutboxedEventRepository,
|
|
62
|
+
)
|
|
63
|
+
from cqrs.message_brokers.producer import EventProducer
|
|
64
|
+
from cqrs.deserializers import DeserializeProtobufError, ProtobufDeserializer
|
|
65
|
+
from cqrs.serializers import (
|
|
66
|
+
EventCodec,
|
|
67
|
+
EventSerializer,
|
|
68
|
+
JsonEventSerializer,
|
|
69
|
+
ProtobufEventSerializer,
|
|
70
|
+
)
|
|
71
|
+
from cqrs.requests.fallback import RequestHandlerFallback
|
|
72
|
+
from cqrs.mapping.requests import RequestMap, SagaMap
|
|
73
|
+
from cqrs.mermaid.cor import CoRMermaid
|
|
74
|
+
from cqrs.models.request import DCRequest, IRequest, Request
|
|
75
|
+
from cqrs.handlers.request import (
|
|
76
|
+
RequestHandler,
|
|
77
|
+
StreamingRequestHandler,
|
|
78
|
+
)
|
|
79
|
+
from cqrs.models.response import DCResponse, IResponse, Response
|
|
80
|
+
from cqrs.mermaid.saga import SagaMermaid
|
|
81
|
+
from cqrs.saga.models import ContextT
|
|
82
|
+
from cqrs.saga.saga import Saga
|
|
83
|
+
from cqrs.handlers.saga import (
|
|
84
|
+
Resp,
|
|
85
|
+
SagaStepHandler,
|
|
86
|
+
SagaStepResult,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
from cqrs._dataclass_utils import pydantic_extra_error
|
|
91
|
+
|
|
92
|
+
__all__ = (
|
|
93
|
+
"ICircuitBreaker",
|
|
94
|
+
"EventHandlerFallback",
|
|
95
|
+
"RequestHandlerFallback",
|
|
96
|
+
"RequestMediator",
|
|
97
|
+
"SagaMediator",
|
|
98
|
+
"StreamingRequestMediator",
|
|
99
|
+
"EventMediator",
|
|
100
|
+
"DomainEvent",
|
|
101
|
+
"IDomainEvent",
|
|
102
|
+
"DCDomainEvent",
|
|
103
|
+
"PydanticDomainEvent",
|
|
104
|
+
"NotificationEvent",
|
|
105
|
+
"INotificationEvent",
|
|
106
|
+
"DCNotificationEvent",
|
|
107
|
+
"PydanticNotificationEvent",
|
|
108
|
+
"Event",
|
|
109
|
+
"IEvent",
|
|
110
|
+
"DCEvent",
|
|
111
|
+
"PydanticEvent",
|
|
112
|
+
"EventEmitter",
|
|
113
|
+
"EventHandler",
|
|
114
|
+
"EventMap",
|
|
115
|
+
"OutboxedEventMap",
|
|
116
|
+
"EventStatus",
|
|
117
|
+
"OutboxedEvent",
|
|
118
|
+
"Request",
|
|
119
|
+
"IRequest",
|
|
120
|
+
"DCRequest",
|
|
121
|
+
"PydanticRequest",
|
|
122
|
+
"RequestHandler",
|
|
123
|
+
"StreamingRequestHandler",
|
|
124
|
+
"RequestMap",
|
|
125
|
+
"SagaMap",
|
|
126
|
+
"Response",
|
|
127
|
+
"IResponse",
|
|
128
|
+
"DCResponse",
|
|
129
|
+
"PydanticResponse",
|
|
130
|
+
"OutboxedEventRepository",
|
|
131
|
+
"SqlAlchemyOutboxedEventRepository",
|
|
132
|
+
"EventProducer",
|
|
133
|
+
"EventSerializer",
|
|
134
|
+
"EventCodec",
|
|
135
|
+
"JsonEventSerializer",
|
|
136
|
+
"ProtobufEventSerializer",
|
|
137
|
+
"ProtobufDeserializer",
|
|
138
|
+
"DeserializeProtobufError",
|
|
139
|
+
"Container",
|
|
140
|
+
"SupportsScope",
|
|
141
|
+
"DIContainer",
|
|
142
|
+
"ScopeAwareContainer",
|
|
143
|
+
"ScopeStrategy",
|
|
144
|
+
"bind_scope",
|
|
145
|
+
"current_container",
|
|
146
|
+
"enter_scope",
|
|
147
|
+
"Compressor",
|
|
148
|
+
"ZlibCompressor",
|
|
149
|
+
"rebind_outbox_model",
|
|
150
|
+
"Saga",
|
|
151
|
+
"SagaStepHandler",
|
|
152
|
+
"SagaStepResult",
|
|
153
|
+
"Resp",
|
|
154
|
+
"ContextT",
|
|
155
|
+
"SagaMermaid",
|
|
156
|
+
"CoRMermaid",
|
|
157
|
+
"DialectAwareType",
|
|
158
|
+
"DialectTypeHandler",
|
|
159
|
+
"UUIDBinary",
|
|
160
|
+
"Binary16",
|
|
161
|
+
"JSONType",
|
|
162
|
+
"PayloadBinary",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
_LAZY_PYDANTIC = {
|
|
166
|
+
"PydanticEvent": ("cqrs.models.pydantic", "PydanticEvent"),
|
|
167
|
+
"PydanticDomainEvent": ("cqrs.models.pydantic", "PydanticDomainEvent"),
|
|
168
|
+
"PydanticNotificationEvent": (
|
|
169
|
+
"cqrs.models.pydantic",
|
|
170
|
+
"PydanticNotificationEvent",
|
|
171
|
+
),
|
|
172
|
+
"PydanticRequest": ("cqrs.models.pydantic", "PydanticRequest"),
|
|
173
|
+
"PydanticResponse": ("cqrs.models.pydantic", "PydanticResponse"),
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_LAZY_SQLALCHEMY = {
|
|
177
|
+
"SqlAlchemyOutboxedEventRepository": (
|
|
178
|
+
"cqrs.outbox.sqlalchemy",
|
|
179
|
+
"SqlAlchemyOutboxedEventRepository",
|
|
180
|
+
),
|
|
181
|
+
"rebind_outbox_model": ("cqrs.outbox.sqlalchemy", "rebind_outbox_model"),
|
|
182
|
+
"DialectAwareType": ("cqrs.sqlalchemy_types", "DialectAwareType"),
|
|
183
|
+
"DialectTypeHandler": ("cqrs.sqlalchemy_types", "DialectTypeHandler"),
|
|
184
|
+
"UUIDBinary": ("cqrs.sqlalchemy_types", "UUIDBinary"),
|
|
185
|
+
"Binary16": ("cqrs.sqlalchemy_types", "Binary16"),
|
|
186
|
+
"JSONType": ("cqrs.sqlalchemy_types", "JSONType"),
|
|
187
|
+
"PayloadBinary": ("cqrs.sqlalchemy_types", "PayloadBinary"),
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def __getattr__(name: str) -> typing.Any:
|
|
192
|
+
if name in _LAZY_PYDANTIC:
|
|
193
|
+
module_name, attr = _LAZY_PYDANTIC[name]
|
|
194
|
+
try:
|
|
195
|
+
module = __import__(module_name, fromlist=[attr])
|
|
196
|
+
except ImportError as exc:
|
|
197
|
+
raise pydantic_extra_error(name) from exc
|
|
198
|
+
return getattr(module, attr)
|
|
199
|
+
if name in _LAZY_SQLALCHEMY:
|
|
200
|
+
module_name, attr = _LAZY_SQLALCHEMY[name]
|
|
201
|
+
# ImportError message is raised by the sqlalchemy modules themselves.
|
|
202
|
+
module = __import__(module_name, fromlist=[attr])
|
|
203
|
+
return getattr(module, attr)
|
|
204
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|