python-cqrs 4.14.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.14.0/src/python_cqrs.egg-info → python_cqrs-5.0.0}/PKG-INFO +84 -33
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/README.md +72 -28
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/pyproject.toml +14 -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-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/kafka.py +27 -6
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/protocol.py +7 -0
- python_cqrs-5.0.0/src/cqrs/bootstrap/__init__.py +5 -0
- python_cqrs-4.14.0/src/cqrs/requests/bootstrap.py → python_cqrs-5.0.0/src/cqrs/bootstrap/requests.py +23 -1
- python_cqrs-4.14.0/src/cqrs/saga/bootstrap.py → python_cqrs-5.0.0/src/cqrs/bootstrap/saga.py +12 -4
- python_cqrs-5.0.0/src/cqrs/deserializers/__init__.py +11 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/deserializers/exceptions.py +16 -0
- python_cqrs-5.0.0/src/cqrs/deserializers/protobuf.py +51 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/event.py +3 -3
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/models.py +3 -3
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/request.py +4 -4
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/saga.py +1 -1
- {python_cqrs-4.14.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.14.0 → python_cqrs-5.0.0}/src/cqrs/events/event_emitter.py +19 -2
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/events/event_processor.py +2 -2
- {python_cqrs-4.14.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.14.0/src/cqrs/requests/cor_request_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/cor.py +2 -2
- python_cqrs-4.14.0/src/cqrs/events/event_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/event.py +1 -1
- python_cqrs-4.14.0/src/cqrs/requests/request_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/request.py +2 -2
- python_cqrs-4.14.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.14.0/src/cqrs/events/map.py → python_cqrs-5.0.0/src/cqrs/mapping/events.py +2 -2
- python_cqrs-5.0.0/src/cqrs/mapping/outbox.py +103 -0
- python_cqrs-4.14.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.14.0/src/cqrs/requests/mermaid.py → python_cqrs-5.0.0/src/cqrs/mermaid/cor.py +1 -1
- python_cqrs-4.14.0/src/cqrs/saga/mermaid.py → python_cqrs-5.0.0/src/cqrs/mermaid/saga.py +1 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/amqp.py +10 -2
- python_cqrs-5.0.0/src/cqrs/message_brokers/kafka.py +45 -0
- {python_cqrs-4.14.0/src/cqrs → python_cqrs-5.0.0/src/cqrs/message_brokers}/producer.py +15 -4
- python_cqrs-5.0.0/src/cqrs/message_brokers/protocol.py +74 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/middlewares/base.py +1 -1
- {python_cqrs-4.14.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.14.0 → python_cqrs-5.0.0}/src/cqrs/outbox/mock.py +18 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/outbox/repository.py +5 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/outbox/sqlalchemy.py +54 -14
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/requests/fallback.py +1 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/circuit_breaker.py +1 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/compensation.py +1 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/execution.py +1 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/fallback.py +1 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/saga.py +1 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/validation.py +1 -1
- python_cqrs-5.0.0/src/cqrs/serializers/__init__.py +12 -0
- python_cqrs-5.0.0/src/cqrs/serializers/default.py +86 -0
- python_cqrs-5.0.0/src/cqrs/serializers/json.py +22 -0
- python_cqrs-5.0.0/src/cqrs/serializers/protobuf.py +48 -0
- python_cqrs-5.0.0/src/cqrs/serializers/protocol.py +21 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/types.py +1 -1
- {python_cqrs-4.14.0 → python_cqrs-5.0.0/src/python_cqrs.egg-info}/PKG-INFO +84 -33
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/SOURCES.txt +33 -17
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/requires.txt +11 -2
- python_cqrs-4.14.0/src/cqrs/__init__.py +0 -138
- python_cqrs-4.14.0/src/cqrs/deserializers/__init__.py +0 -8
- python_cqrs-4.14.0/src/cqrs/events/__init__.py +0 -50
- python_cqrs-4.14.0/src/cqrs/events/event.py +0 -393
- python_cqrs-4.14.0/src/cqrs/mediator.py +0 -423
- python_cqrs-4.14.0/src/cqrs/message_brokers/kafka.py +0 -18
- python_cqrs-4.14.0/src/cqrs/message_brokers/protocol.py +0 -44
- python_cqrs-4.14.0/src/cqrs/outbox/map.py +0 -24
- python_cqrs-4.14.0/src/cqrs/requests/request.py +0 -152
- python_cqrs-4.14.0/src/cqrs/response.py +0 -146
- python_cqrs-4.14.0/src/cqrs/serializers/__init__.py +0 -3
- python_cqrs-4.14.0/src/cqrs/serializers/default.py +0 -24
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/LICENSE +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/setup.cfg +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/amqp.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/circuit_breaker.py +0 -0
- /python_cqrs-4.14.0/src/cqrs/events/bootstrap.py → /python_cqrs-5.0.0/src/cqrs/bootstrap/events.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/circuit_breaker.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/compressors/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/compressors/protocol.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/compressors/zlib.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/dependency_injector.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/di.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/dishka.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/protocol.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/scope.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/deserializers/json.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/exceptions.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/generic_utils.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/devnull.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/middlewares/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/outbox/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/requests/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/models.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/recovery.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/__init__.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/enums.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/memory.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/models.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/protocol.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/sqlalchemy.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/sqlalchemy_types.py +0 -0
- {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/dependency_links.txt +0 -0
- {python_cqrs-4.14.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"
|
|
@@ -49,6 +51,9 @@ Requires-Dist: asyncpg>=0.29.0; extra == "dev"
|
|
|
49
51
|
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"
|
|
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"
|
|
52
57
|
Provides-Extra: examples
|
|
53
58
|
Requires-Dist: fastapi==0.109.*; extra == "examples"
|
|
54
59
|
Requires-Dist: faststream[kafka]==0.5.28; extra == "examples"
|
|
@@ -58,13 +63,15 @@ Requires-Dist: aiohttp==3.14.3; extra == "examples"
|
|
|
58
63
|
Requires-Dist: protobuf>=4.25.8; extra == "examples"
|
|
59
64
|
Requires-Dist: aiosqlite>=0.20.0; extra == "examples"
|
|
60
65
|
Requires-Dist: dishka>=1.0; extra == "examples"
|
|
66
|
+
Requires-Dist: pydantic==2.*; extra == "examples"
|
|
67
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "examples"
|
|
61
68
|
Provides-Extra: kafka
|
|
62
69
|
Requires-Dist: aiokafka==0.10.0; extra == "kafka"
|
|
63
70
|
Requires-Dist: retry-async==0.1.*; extra == "kafka"
|
|
71
|
+
Provides-Extra: protobuf
|
|
72
|
+
Requires-Dist: protobuf>=4.25.8; extra == "protobuf"
|
|
64
73
|
Provides-Extra: rabbit
|
|
65
74
|
Requires-Dist: aio-pika==9.3.0; extra == "rabbit"
|
|
66
|
-
Provides-Extra: sqlalchemy
|
|
67
|
-
Requires-Dist: sqlalchemy[asyncio]==2.0.*; extra == "sqlalchemy"
|
|
68
75
|
Provides-Extra: dishka
|
|
69
76
|
Requires-Dist: dishka>=1.0; extra == "dishka"
|
|
70
77
|
Dynamic: license-file
|
|
@@ -116,6 +123,7 @@ Dynamic: license-file
|
|
|
116
123
|
- [Overview](#overview)
|
|
117
124
|
- [When NOT to use python-cqrs](#when-not-to-use-python-cqrs)
|
|
118
125
|
- [Installation](#installation)
|
|
126
|
+
- [Version Support](#version-support)
|
|
119
127
|
- [Quick Start](#quick-start)
|
|
120
128
|
- [Request and Response Types](#request-and-response-types)
|
|
121
129
|
- [Request Handlers](#request-handlers)
|
|
@@ -181,14 +189,52 @@ Do not add a Saga for a single `UPDATE` in one service, and do not use a Saga as
|
|
|
181
189
|
pip install python-cqrs
|
|
182
190
|
```
|
|
183
191
|
|
|
184
|
-
Optional
|
|
192
|
+
Optional extras (5.0+ — pydantic and SQLAlchemy are no longer core dependencies):
|
|
185
193
|
|
|
186
194
|
```bash
|
|
187
|
-
pip install python-cqrs[
|
|
188
|
-
pip install python-cqrs[
|
|
189
|
-
pip install python-cqrs[
|
|
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
|
|
190
200
|
```
|
|
191
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:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
pip install "python-cqrs>=4,<5"
|
|
232
|
+
```
|
|
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
|
+
|
|
192
238
|
## Quick Start
|
|
193
239
|
|
|
194
240
|
Define a command, a handler, bind them, and run via the mediator:
|
|
@@ -196,7 +242,7 @@ Define a command, a handler, bind them, and run via the mediator:
|
|
|
196
242
|
```python
|
|
197
243
|
import di
|
|
198
244
|
import cqrs
|
|
199
|
-
from cqrs.
|
|
245
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
200
246
|
|
|
201
247
|
class CreateOrderCommand(cqrs.Request):
|
|
202
248
|
order_id: str
|
|
@@ -284,8 +330,8 @@ As a result of executing the command, an event may be produced to the broker.
|
|
|
284
330
|
> By default, the command handler does not return any result, but it is not mandatory.
|
|
285
331
|
|
|
286
332
|
```python
|
|
287
|
-
from cqrs.
|
|
288
|
-
from cqrs.
|
|
333
|
+
from cqrs.handlers.request import RequestHandler
|
|
334
|
+
from cqrs.models.event import Event
|
|
289
335
|
|
|
290
336
|
class JoinMeetingCommandHandler(RequestHandler[JoinMeetingCommand, None]):
|
|
291
337
|
|
|
@@ -312,8 +358,8 @@ the [read model](https://radekmaziarka.pl/2018/01/08/cqrs-third-step-simple-read
|
|
|
312
358
|
> The read model can be constructed based on domain events produced by the `Command Handler`.
|
|
313
359
|
|
|
314
360
|
```python
|
|
315
|
-
from cqrs.
|
|
316
|
-
from cqrs.
|
|
361
|
+
from cqrs.handlers.request import RequestHandler
|
|
362
|
+
from cqrs.models.event import Event
|
|
317
363
|
|
|
318
364
|
class ReadMeetingQueryHandler(RequestHandler[ReadMeetingQuery, ReadMeetingQueryResult]):
|
|
319
365
|
|
|
@@ -344,8 +390,8 @@ real-time progress updates.
|
|
|
344
390
|
|
|
345
391
|
```python
|
|
346
392
|
import typing
|
|
347
|
-
from cqrs.
|
|
348
|
-
from cqrs.
|
|
393
|
+
from cqrs.handlers.request import StreamingRequestHandler
|
|
394
|
+
from cqrs.models.event import Event
|
|
349
395
|
|
|
350
396
|
class ProcessFilesCommandHandler(StreamingRequestHandler[ProcessFilesCommand, FileProcessedResult]):
|
|
351
397
|
def __init__(self):
|
|
@@ -381,8 +427,8 @@ when a handler successfully processes the request or when all handlers have been
|
|
|
381
427
|
|
|
382
428
|
```python
|
|
383
429
|
import typing
|
|
384
|
-
from cqrs.
|
|
385
|
-
from cqrs.
|
|
430
|
+
from cqrs.handlers.cor import CORRequestHandler
|
|
431
|
+
from cqrs.models.event import Event
|
|
386
432
|
|
|
387
433
|
class CreditCardPaymentHandler(CORRequestHandler[ProcessPaymentCommand, PaymentResult]):
|
|
388
434
|
def __init__(self, payment_service: PaymentServiceProtocol) -> None:
|
|
@@ -438,7 +484,7 @@ the [documentation](https://github.com/vadikko2/python-cqrs/blob/master/examples
|
|
|
438
484
|
The package includes built-in support for generating Mermaid diagrams from Chain of Responsibility handler chains.
|
|
439
485
|
|
|
440
486
|
```python
|
|
441
|
-
from cqrs.
|
|
487
|
+
from cqrs.mermaid.cor import CoRMermaid
|
|
442
488
|
|
|
443
489
|
# Create Mermaid generator from handler chain
|
|
444
490
|
handlers = [CreditCardHandler, PayPalHandler, DefaultHandler]
|
|
@@ -608,8 +654,8 @@ application.
|
|
|
608
654
|
```python
|
|
609
655
|
import functools
|
|
610
656
|
|
|
611
|
-
from cqrs.
|
|
612
|
-
from cqrs.
|
|
657
|
+
from cqrs.bootstrap import events as event_bootstrap
|
|
658
|
+
from cqrs.bootstrap import requests as bootstrap as request_bootstrap
|
|
613
659
|
|
|
614
660
|
from app import dependencies, mapping, orm
|
|
615
661
|
|
|
@@ -665,7 +711,7 @@ import dataclasses
|
|
|
665
711
|
import uuid
|
|
666
712
|
from cqrs.saga.models import SagaContext
|
|
667
713
|
from cqrs.saga.saga import Saga
|
|
668
|
-
from cqrs.saga
|
|
714
|
+
from cqrs.handlers.saga import SagaStepHandler
|
|
669
715
|
|
|
670
716
|
@dataclasses.dataclass
|
|
671
717
|
class OrderContext(SagaContext):
|
|
@@ -687,7 +733,7 @@ class OrderSaga(Saga[OrderContext]):
|
|
|
687
733
|
context = OrderContext(order_id="123", user_id="user_1", items=["item_1"], total_amount=100.0)
|
|
688
734
|
saga_id = uuid.uuid4()
|
|
689
735
|
|
|
690
|
-
async for step_result in mediator.
|
|
736
|
+
async for step_result in mediator.execute(context, saga_id=saga_id):
|
|
691
737
|
print(f"Step completed: {step_result.step_type.__name__}")
|
|
692
738
|
# If any step fails, compensation happens automatically
|
|
693
739
|
```
|
|
@@ -700,7 +746,7 @@ The saga pattern supports fallback steps that execute automatically when primary
|
|
|
700
746
|
from cqrs.saga.fallback import Fallback
|
|
701
747
|
from cqrs.adapters.circuit_breaker import AioBreakerAdapter
|
|
702
748
|
from cqrs.response import Response
|
|
703
|
-
from cqrs.saga
|
|
749
|
+
from cqrs.handlers.saga import SagaStepHandler, SagaStepResult
|
|
704
750
|
|
|
705
751
|
class ReserveInventoryResponse(Response):
|
|
706
752
|
reservation_id: str
|
|
@@ -783,7 +829,7 @@ The recovery mechanism ensures eventual consistency by:
|
|
|
783
829
|
The package includes built-in support for generating Mermaid diagrams from Saga instances.
|
|
784
830
|
|
|
785
831
|
```python
|
|
786
|
-
from cqrs.saga
|
|
832
|
+
from cqrs.mermaid.saga import SagaMermaid
|
|
787
833
|
|
|
788
834
|
# Create Mermaid generator from saga class
|
|
789
835
|
saga = OrderSaga()
|
|
@@ -923,12 +969,9 @@ A runnable FastAPI flow (route → command → transactional outbox → publishe
|
|
|
923
969
|
> [Database Support](https://mkdocs.python-cqrs.dev/outbox/databases/) docs for the DDL, the Alembic recipe and
|
|
924
970
|
> how to register a native type for your own database.
|
|
925
971
|
> [!TIP]
|
|
926
|
-
> For Protobuf events, implement `proto()` / `from_proto()`
|
|
927
|
-
>
|
|
928
|
-
> [
|
|
929
|
-
> Outbox persistence is unchanged — use
|
|
930
|
-
> [save_events_into_outbox.py](https://github.com/vadikko2/python-cqrs/blob/master/examples/outbox/save_events_into_outbox.py);
|
|
931
|
-
> Protobuf applies when producing to the broker. Full guide:
|
|
972
|
+
> For Protobuf events, implement `proto()` / `from_proto()` and register a
|
|
973
|
+
> `ProtobufEventSerializer` on an `OutboxedEventMap`. JSON stays the default —
|
|
974
|
+
> see [Protobuf messaging](#protobuf-messaging) and the full guide:
|
|
932
975
|
> [Protobuf Integration](https://mkdocs.python-cqrs.dev/protobuf/).
|
|
933
976
|
|
|
934
977
|
## Producing Events from Outbox to Kafka
|
|
@@ -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(
|
|
@@ -1231,6 +1274,14 @@ class UserJoinedNotificationEvent(cqrs.NotificationEvent[UserJoinedPayload]):
|
|
|
1231
1274
|
)
|
|
1232
1275
|
```
|
|
1233
1276
|
|
|
1277
|
+
JSON remains the default. Opt-in Protobuf wiring (`ProtobufEventSerializer` on an
|
|
1278
|
+
`OutboxedEventMap`, `Message.payload_bytes`, consume via `ProtobufDeserializer`) is
|
|
1279
|
+
documented in the full guide:
|
|
1280
|
+
[Protobuf Integration](https://mkdocs.python-cqrs.dev/protobuf/).
|
|
1281
|
+
Runnable example:
|
|
1282
|
+
[protobuf_outbox.py](https://github.com/vadikko2/python-cqrs/blob/master/examples/outbox/protobuf_outbox.py)
|
|
1283
|
+
(`pip install "python-cqrs[protobuf]"`).
|
|
1284
|
+
|
|
1234
1285
|
## Contributing
|
|
1235
1286
|
|
|
1236
1287
|
Contributions are welcome. To develop locally:
|
|
@@ -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()
|
|
@@ -852,12 +891,9 @@ A runnable FastAPI flow (route → command → transactional outbox → publishe
|
|
|
852
891
|
> [Database Support](https://mkdocs.python-cqrs.dev/outbox/databases/) docs for the DDL, the Alembic recipe and
|
|
853
892
|
> how to register a native type for your own database.
|
|
854
893
|
> [!TIP]
|
|
855
|
-
> For Protobuf events, implement `proto()` / `from_proto()`
|
|
856
|
-
>
|
|
857
|
-
> [
|
|
858
|
-
> Outbox persistence is unchanged — use
|
|
859
|
-
> [save_events_into_outbox.py](https://github.com/vadikko2/python-cqrs/blob/master/examples/outbox/save_events_into_outbox.py);
|
|
860
|
-
> Protobuf applies when producing to the broker. Full guide:
|
|
894
|
+
> For Protobuf events, implement `proto()` / `from_proto()` and register a
|
|
895
|
+
> `ProtobufEventSerializer` on an `OutboxedEventMap`. JSON stays the default —
|
|
896
|
+
> see [Protobuf messaging](#protobuf-messaging) and the full guide:
|
|
861
897
|
> [Protobuf Integration](https://mkdocs.python-cqrs.dev/protobuf/).
|
|
862
898
|
|
|
863
899
|
## Producing Events from Outbox to Kafka
|
|
@@ -955,7 +991,7 @@ This feature is especially useful when:
|
|
|
955
991
|
**Configuration:**
|
|
956
992
|
|
|
957
993
|
```python
|
|
958
|
-
from cqrs.
|
|
994
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
959
995
|
|
|
960
996
|
mediator = bootstrap.bootstrap_streaming(
|
|
961
997
|
di_container=container,
|
|
@@ -1072,7 +1108,7 @@ This allows you to stream results to clients in real-time as they are processed.
|
|
|
1072
1108
|
```python
|
|
1073
1109
|
import fastapi
|
|
1074
1110
|
import json
|
|
1075
|
-
from cqrs.
|
|
1111
|
+
from cqrs.bootstrap import requests as bootstrap
|
|
1076
1112
|
|
|
1077
1113
|
def streaming_mediator_factory() -> cqrs.StreamingRequestMediator:
|
|
1078
1114
|
return bootstrap.bootstrap_streaming(
|
|
@@ -1160,6 +1196,14 @@ class UserJoinedNotificationEvent(cqrs.NotificationEvent[UserJoinedPayload]):
|
|
|
1160
1196
|
)
|
|
1161
1197
|
```
|
|
1162
1198
|
|
|
1199
|
+
JSON remains the default. Opt-in Protobuf wiring (`ProtobufEventSerializer` on an
|
|
1200
|
+
`OutboxedEventMap`, `Message.payload_bytes`, consume via `ProtobufDeserializer`) is
|
|
1201
|
+
documented in the full guide:
|
|
1202
|
+
[Protobuf Integration](https://mkdocs.python-cqrs.dev/protobuf/).
|
|
1203
|
+
Runnable example:
|
|
1204
|
+
[protobuf_outbox.py](https://github.com/vadikko2/python-cqrs/blob/master/examples/outbox/protobuf_outbox.py)
|
|
1205
|
+
(`pip install "python-cqrs[protobuf]"`).
|
|
1206
|
+
|
|
1163
1207
|
## Contributing
|
|
1164
1208
|
|
|
1165
1209
|
Contributions are welcome. To develop locally:
|
|
@@ -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",
|
|
@@ -60,6 +60,10 @@ dev = [
|
|
|
60
60
|
# Circuit breaker for tests
|
|
61
61
|
"aiobreaker>=0.3.0", # from aiobreaker
|
|
62
62
|
"dishka>=1.0", # scoped-deps dishka adapter tests / examples
|
|
63
|
+
"protobuf>=4.25.8", # protobuf codec / deserializer unit tests
|
|
64
|
+
# Full suite extras
|
|
65
|
+
"pydantic==2.*",
|
|
66
|
+
"sqlalchemy[asyncio]==2.0.*",
|
|
63
67
|
]
|
|
64
68
|
examples = [
|
|
65
69
|
"fastapi==0.109.*",
|
|
@@ -70,10 +74,12 @@ examples = [
|
|
|
70
74
|
"protobuf>=4.25.8",
|
|
71
75
|
"aiosqlite>=0.20.0",
|
|
72
76
|
"dishka>=1.0",
|
|
77
|
+
"pydantic==2.*",
|
|
78
|
+
"sqlalchemy[asyncio]==2.0.*",
|
|
73
79
|
]
|
|
74
80
|
kafka = ["aiokafka==0.10.0", "retry-async==0.1.*"]
|
|
81
|
+
protobuf = ["protobuf>=4.25.8"]
|
|
75
82
|
rabbit = ["aio-pika==9.3.0"]
|
|
76
|
-
sqlalchemy = ["sqlalchemy[asyncio]==2.0.*"]
|
|
77
83
|
dishka = ["dishka>=1.0"]
|
|
78
84
|
|
|
79
85
|
[project.urls]
|
|
@@ -86,6 +92,10 @@ addopts = "--junit-xml=report.xml"
|
|
|
86
92
|
asyncio_mode = "auto"
|
|
87
93
|
junit_family = "xunit1"
|
|
88
94
|
testpaths = ["tests"]
|
|
95
|
+
markers = [
|
|
96
|
+
"pydantic: tests that require the pydantic optional extra",
|
|
97
|
+
"sqlalchemy: tests that require the sqlalchemy optional extra",
|
|
98
|
+
]
|
|
89
99
|
|
|
90
100
|
[tool.setuptools.packages.find]
|
|
91
101
|
where = ["src"]
|