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.
Files changed (119) hide show
  1. {python_cqrs-4.14.0/src/python_cqrs.egg-info → python_cqrs-5.0.0}/PKG-INFO +84 -33
  2. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/README.md +72 -28
  3. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/pyproject.toml +14 -4
  4. python_cqrs-5.0.0/src/cqrs/__init__.py +204 -0
  5. python_cqrs-5.0.0/src/cqrs/_dataclass_utils.py +99 -0
  6. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/kafka.py +27 -6
  7. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/protocol.py +7 -0
  8. python_cqrs-5.0.0/src/cqrs/bootstrap/__init__.py +5 -0
  9. python_cqrs-4.14.0/src/cqrs/requests/bootstrap.py → python_cqrs-5.0.0/src/cqrs/bootstrap/requests.py +23 -1
  10. python_cqrs-4.14.0/src/cqrs/saga/bootstrap.py → python_cqrs-5.0.0/src/cqrs/bootstrap/saga.py +12 -4
  11. python_cqrs-5.0.0/src/cqrs/deserializers/__init__.py +11 -0
  12. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/deserializers/exceptions.py +16 -0
  13. python_cqrs-5.0.0/src/cqrs/deserializers/protobuf.py +51 -0
  14. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/event.py +3 -3
  15. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/models.py +3 -3
  16. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/request.py +4 -4
  17. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/saga.py +1 -1
  18. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/streaming.py +3 -3
  19. python_cqrs-5.0.0/src/cqrs/events/__init__.py +63 -0
  20. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/events/event_emitter.py +19 -2
  21. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/events/event_processor.py +2 -2
  22. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/events/fallback.py +1 -1
  23. python_cqrs-5.0.0/src/cqrs/handlers/__init__.py +14 -0
  24. python_cqrs-4.14.0/src/cqrs/requests/cor_request_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/cor.py +2 -2
  25. python_cqrs-4.14.0/src/cqrs/events/event_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/event.py +1 -1
  26. python_cqrs-4.14.0/src/cqrs/requests/request_handler.py → python_cqrs-5.0.0/src/cqrs/handlers/request.py +2 -2
  27. python_cqrs-4.14.0/src/cqrs/saga/step.py → python_cqrs-5.0.0/src/cqrs/handlers/saga.py +2 -2
  28. python_cqrs-5.0.0/src/cqrs/mapping/__init__.py +5 -0
  29. python_cqrs-4.14.0/src/cqrs/events/map.py → python_cqrs-5.0.0/src/cqrs/mapping/events.py +2 -2
  30. python_cqrs-5.0.0/src/cqrs/mapping/outbox.py +103 -0
  31. python_cqrs-4.14.0/src/cqrs/requests/map.py → python_cqrs-5.0.0/src/cqrs/mapping/requests.py +3 -3
  32. python_cqrs-5.0.0/src/cqrs/mediators/__init__.py +11 -0
  33. python_cqrs-5.0.0/src/cqrs/mediators/_common.py +26 -0
  34. python_cqrs-5.0.0/src/cqrs/mediators/event.py +50 -0
  35. python_cqrs-5.0.0/src/cqrs/mediators/request.py +109 -0
  36. python_cqrs-5.0.0/src/cqrs/mediators/saga.py +152 -0
  37. python_cqrs-5.0.0/src/cqrs/mediators/streaming.py +128 -0
  38. python_cqrs-5.0.0/src/cqrs/mermaid/__init__.py +4 -0
  39. python_cqrs-4.14.0/src/cqrs/requests/mermaid.py → python_cqrs-5.0.0/src/cqrs/mermaid/cor.py +1 -1
  40. python_cqrs-4.14.0/src/cqrs/saga/mermaid.py → python_cqrs-5.0.0/src/cqrs/mermaid/saga.py +1 -1
  41. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/amqp.py +10 -2
  42. python_cqrs-5.0.0/src/cqrs/message_brokers/kafka.py +45 -0
  43. {python_cqrs-4.14.0/src/cqrs → python_cqrs-5.0.0/src/cqrs/message_brokers}/producer.py +15 -4
  44. python_cqrs-5.0.0/src/cqrs/message_brokers/protocol.py +74 -0
  45. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/middlewares/base.py +1 -1
  46. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/middlewares/logging.py +2 -2
  47. python_cqrs-5.0.0/src/cqrs/models/__init__.py +57 -0
  48. python_cqrs-5.0.0/src/cqrs/models/event.py +208 -0
  49. python_cqrs-5.0.0/src/cqrs/models/pydantic.py +130 -0
  50. python_cqrs-5.0.0/src/cqrs/models/request.py +81 -0
  51. python_cqrs-5.0.0/src/cqrs/models/response.py +74 -0
  52. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/outbox/mock.py +18 -1
  53. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/outbox/repository.py +5 -1
  54. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/outbox/sqlalchemy.py +54 -14
  55. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/requests/fallback.py +1 -1
  56. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/circuit_breaker.py +1 -1
  57. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/compensation.py +1 -1
  58. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/execution.py +1 -1
  59. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/fallback.py +1 -1
  60. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/saga.py +1 -1
  61. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/validation.py +1 -1
  62. python_cqrs-5.0.0/src/cqrs/serializers/__init__.py +12 -0
  63. python_cqrs-5.0.0/src/cqrs/serializers/default.py +86 -0
  64. python_cqrs-5.0.0/src/cqrs/serializers/json.py +22 -0
  65. python_cqrs-5.0.0/src/cqrs/serializers/protobuf.py +48 -0
  66. python_cqrs-5.0.0/src/cqrs/serializers/protocol.py +21 -0
  67. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/types.py +1 -1
  68. {python_cqrs-4.14.0 → python_cqrs-5.0.0/src/python_cqrs.egg-info}/PKG-INFO +84 -33
  69. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/SOURCES.txt +33 -17
  70. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/requires.txt +11 -2
  71. python_cqrs-4.14.0/src/cqrs/__init__.py +0 -138
  72. python_cqrs-4.14.0/src/cqrs/deserializers/__init__.py +0 -8
  73. python_cqrs-4.14.0/src/cqrs/events/__init__.py +0 -50
  74. python_cqrs-4.14.0/src/cqrs/events/event.py +0 -393
  75. python_cqrs-4.14.0/src/cqrs/mediator.py +0 -423
  76. python_cqrs-4.14.0/src/cqrs/message_brokers/kafka.py +0 -18
  77. python_cqrs-4.14.0/src/cqrs/message_brokers/protocol.py +0 -44
  78. python_cqrs-4.14.0/src/cqrs/outbox/map.py +0 -24
  79. python_cqrs-4.14.0/src/cqrs/requests/request.py +0 -152
  80. python_cqrs-4.14.0/src/cqrs/response.py +0 -146
  81. python_cqrs-4.14.0/src/cqrs/serializers/__init__.py +0 -3
  82. python_cqrs-4.14.0/src/cqrs/serializers/default.py +0 -24
  83. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/LICENSE +0 -0
  84. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/setup.cfg +0 -0
  85. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/__init__.py +0 -0
  86. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/amqp.py +0 -0
  87. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/adapters/circuit_breaker.py +0 -0
  88. /python_cqrs-4.14.0/src/cqrs/events/bootstrap.py → /python_cqrs-5.0.0/src/cqrs/bootstrap/events.py +0 -0
  89. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/circuit_breaker.py +0 -0
  90. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/compressors/__init__.py +0 -0
  91. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/compressors/protocol.py +0 -0
  92. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/compressors/zlib.py +0 -0
  93. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/__init__.py +0 -0
  94. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/dependency_injector.py +0 -0
  95. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/di.py +0 -0
  96. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/dishka.py +0 -0
  97. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/protocol.py +0 -0
  98. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/container/scope.py +0 -0
  99. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/deserializers/json.py +0 -0
  100. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/__init__.py +0 -0
  101. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/dispatcher/exceptions.py +0 -0
  102. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/generic_utils.py +0 -0
  103. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/__init__.py +0 -0
  104. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/message_brokers/devnull.py +0 -0
  105. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/middlewares/__init__.py +0 -0
  106. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/outbox/__init__.py +0 -0
  107. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/requests/__init__.py +0 -0
  108. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/__init__.py +0 -0
  109. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/models.py +0 -0
  110. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/recovery.py +0 -0
  111. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/__init__.py +0 -0
  112. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/enums.py +0 -0
  113. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/memory.py +0 -0
  114. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/models.py +0 -0
  115. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/protocol.py +0 -0
  116. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/saga/storage/sqlalchemy.py +0 -0
  117. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/cqrs/sqlalchemy_types.py +0 -0
  118. {python_cqrs-4.14.0 → python_cqrs-5.0.0}/src/python_cqrs.egg-info/dependency_links.txt +0 -0
  119. {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: 4.14.0
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 dependencies (see [pyproject.toml](https://github.com/vadikko2/python-cqrs/blob/master/pyproject.toml) for full list):
192
+ Optional extras (5.0+ — pydantic and SQLAlchemy are no longer core dependencies):
185
193
 
186
194
  ```bash
187
- pip install python-cqrs[kafka] # Kafka broker (aiokafka)
188
- pip install python-cqrs[examples] # FastAPI, FastStream, uvicorn, etc.
189
- pip install python-cqrs[aiobreaker] # Circuit breaker for saga fallbacks
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.requests import bootstrap
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.requests.request_handler import RequestHandler
288
- from cqrs.events.event import Event
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.requests.request_handler import RequestHandler
316
- from cqrs.events.event import Event
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.requests.request_handler import StreamingRequestHandler
348
- from cqrs.events.event import Event
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.requests.cor_request_handler import CORRequestHandler
385
- from cqrs.events.event import Event
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.requests.mermaid import CoRMermaid
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.events import bootstrap as event_bootstrap
612
- from cqrs.requests import bootstrap as request_bootstrap
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.step import SagaStepHandler
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.stream(context, saga_id=saga_id):
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.step import SagaStepHandler, SagaStepResult
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.mermaid import SagaMermaid
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()` on the notification
927
- > event (see [Protobuf messaging](#protobuf-messaging) and the schema assets in
928
- > [examples/proto/](https://github.com/vadikko2/python-cqrs/tree/master/examples/proto)).
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.requests import bootstrap
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.requests import bootstrap
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 dependencies (see [pyproject.toml](https://github.com/vadikko2/python-cqrs/blob/master/pyproject.toml) for full list):
114
+ Optional extras (5.0+ — pydantic and SQLAlchemy are no longer core dependencies):
114
115
 
115
116
  ```bash
116
- pip install python-cqrs[kafka] # Kafka broker (aiokafka)
117
- pip install python-cqrs[examples] # FastAPI, FastStream, uvicorn, etc.
118
- pip install python-cqrs[aiobreaker] # Circuit breaker for saga fallbacks
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.requests import bootstrap
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.requests.request_handler import RequestHandler
217
- from cqrs.events.event import Event
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.requests.request_handler import RequestHandler
245
- from cqrs.events.event import Event
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.requests.request_handler import StreamingRequestHandler
277
- from cqrs.events.event import Event
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.requests.cor_request_handler import CORRequestHandler
314
- from cqrs.events.event import Event
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.requests.mermaid import CoRMermaid
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.events import bootstrap as event_bootstrap
541
- from cqrs.requests import bootstrap as request_bootstrap
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.step import SagaStepHandler
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.stream(context, saga_id=saga_id):
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.step import SagaStepHandler, SagaStepResult
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.mermaid import SagaMermaid
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()` on the notification
856
- > event (see [Protobuf messaging](#protobuf-messaging) and the schema assets in
857
- > [examples/proto/](https://github.com/vadikko2/python-cqrs/tree/master/examples/proto)).
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.requests import bootstrap
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.requests import bootstrap
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 = "4.14.0"
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"]