python-event-sourcery 0.5.3a1__tar.gz → 0.5.3a3__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 (208) hide show
  1. python_event_sourcery-0.5.3a3/.adr-dir +1 -0
  2. python_event_sourcery-0.5.3a3/.github/workflows/bump-version-and-publish.yml +35 -0
  3. python_event_sourcery-0.5.3a3/.github/workflows/deploy-docs.yml +32 -0
  4. python_event_sourcery-0.5.3a3/.github/workflows/main.yml +58 -0
  5. python_event_sourcery-0.5.3a3/.github/workflows/publish-release.yml +24 -0
  6. python_event_sourcery-0.5.3a3/.gitignore +129 -0
  7. python_event_sourcery-0.5.3a3/AGENTS.md +45 -0
  8. python_event_sourcery-0.5.3a3/CHANGELOG.md +25 -0
  9. python_event_sourcery-0.5.3a3/CONTRIBUTING.md +40 -0
  10. python_event_sourcery-0.5.3a3/Makefile +20 -0
  11. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/PKG-INFO +11 -18
  12. python_event_sourcery-0.5.3a3/django_manage.py +23 -0
  13. python_event_sourcery-0.5.3a3/docker-compose.yml +26 -0
  14. python_event_sourcery-0.5.3a3/docs/adr/20220730-record-architecture-decisions.md +19 -0
  15. python_event_sourcery-0.5.3a3/docs/adr/20230903-explicit-init-arguments-for-sqlalchemy-s-models.md +129 -0
  16. python_event_sourcery-0.5.3a3/docs/adr/20231027_1-packaging-of-the-project.md +45 -0
  17. python_event_sourcery-0.5.3a3/docs/adr/20231027_2-leave-implementation-of-synchronous-dispatcher-to-users-of-the-library.md +34 -0
  18. python_event_sourcery-0.5.3a3/docs/adr/20231029-in-memory-event-store.md +23 -0
  19. python_event_sourcery-0.5.3a3/docs/adr/20231230-in_transaction_subscription.md +26 -0
  20. python_event_sourcery-0.5.3a3/docs/adr/20240726-dependencies-and-distribution.md +60 -0
  21. python_event_sourcery-0.5.3a3/docs/adr/20241007-multitenancy.md +86 -0
  22. python_event_sourcery-0.5.3a3/docs/adr/20250411-packaging-of-the-project-revised.md +21 -0
  23. python_event_sourcery-0.5.3a3/docs/adr/20250729-privacy-data-encryption-and-shredding.md +103 -0
  24. python_event_sourcery-0.5.3a3/docs/adr/20251004-packaging-of-the-event_store-package.md +17 -0
  25. python_event_sourcery-0.5.3a3/docs/adr/20260314-aggregate-metadata.md +143 -0
  26. python_event_sourcery-0.5.3a3/docs/code/recipes/__init__.py +1 -0
  27. python_event_sourcery-0.5.3a3/docs/code/recipes/integrate/kurrent_01.py +8 -0
  28. python_event_sourcery-0.5.3a3/docs/code/test_get_started.py +25 -0
  29. python_event_sourcery-0.5.3a3/docs/code/test_recipes.py +440 -0
  30. python_event_sourcery-0.5.3a3/docs/concepts/basics.md +278 -0
  31. python_event_sourcery-0.5.3a3/docs/get_started.md +41 -0
  32. python_event_sourcery-0.5.3a3/docs/index.md +3 -0
  33. python_event_sourcery-0.5.3a3/docs/recipes/data_privacy.md +149 -0
  34. python_event_sourcery-0.5.3a3/docs/recipes/defining_events.md +11 -0
  35. python_event_sourcery-0.5.3a3/docs/recipes/event_sourcing.md +49 -0
  36. python_event_sourcery-0.5.3a3/docs/recipes/integrate.md +69 -0
  37. python_event_sourcery-0.5.3a3/docs/recipes/multitenancy.md +75 -0
  38. python_event_sourcery-0.5.3a3/docs/recipes/outbox.md +112 -0
  39. python_event_sourcery-0.5.3a3/docs/recipes/saving_events.md +77 -0
  40. python_event_sourcery-0.5.3a3/docs/recipes/snapshots.md +43 -0
  41. python_event_sourcery-0.5.3a3/docs/recipes/subscriptions.md +59 -0
  42. python_event_sourcery-0.5.3a3/docs/reference/backends/django.md +5 -0
  43. python_event_sourcery-0.5.3a3/docs/reference/backends/in_memory.md +8 -0
  44. python_event_sourcery-0.5.3a3/docs/reference/backends/kurrentdb.md +5 -0
  45. python_event_sourcery-0.5.3a3/docs/reference/backends/sqlalchemy.md +26 -0
  46. python_event_sourcery-0.5.3a3/docs/reference/event_sourcing/Aggregate.md +1 -0
  47. python_event_sourcery-0.5.3a3/docs/reference/event_sourcing/Repository.md +1 -0
  48. python_event_sourcery-0.5.3a3/docs/reference/event_sourcing/WrappedAggregate.md +1 -0
  49. python_event_sourcery-0.5.3a3/docs/reference/event_store/DEFAULT_TENANT.md +3 -0
  50. python_event_sourcery-0.5.3a3/docs/reference/event_store/EventStore.md +1 -0
  51. python_event_sourcery-0.5.3a3/docs/reference/event_store/NO_VERSIONING.md +1 -0
  52. python_event_sourcery-0.5.3a3/docs/reference/event_store/StreamCategory.md +7 -0
  53. python_event_sourcery-0.5.3a3/docs/reference/event_store/StreamId.md +1 -0
  54. python_event_sourcery-0.5.3a3/docs/reference/event_store/StreamUUID.md +1 -0
  55. python_event_sourcery-0.5.3a3/docs/reference/event_store/TenantId.md +4 -0
  56. python_event_sourcery-0.5.3a3/docs/reference/event_store/backend/Backend.md +1 -0
  57. python_event_sourcery-0.5.3a3/docs/reference/event_store/backend/TransactionalBackend.md +1 -0
  58. python_event_sourcery-0.5.3a3/docs/reference/event_store/backend/not_configured.md +1 -0
  59. python_event_sourcery-0.5.3a3/docs/reference/event_store/backend/singleton.md +1 -0
  60. python_event_sourcery-0.5.3a3/docs/reference/event_store/encryption/DataSubject.md +7 -0
  61. python_event_sourcery-0.5.3a3/docs/reference/event_store/encryption/Encrypted.md +1 -0
  62. python_event_sourcery-0.5.3a3/docs/reference/event_store/encryption/Encryption.md +1 -0
  63. python_event_sourcery-0.5.3a3/docs/reference/event_store/encryption/NoEncryptionStrategy.md +1 -0
  64. python_event_sourcery-0.5.3a3/docs/reference/event_store/encryption/NoKeyStorageStrategy.md +1 -0
  65. python_event_sourcery-0.5.3a3/docs/reference/event_store/event/Context.md +1 -0
  66. python_event_sourcery-0.5.3a3/docs/reference/event_store/event/Entry.md +1 -0
  67. python_event_sourcery-0.5.3a3/docs/reference/event_store/event/Event.md +1 -0
  68. python_event_sourcery-0.5.3a3/docs/reference/event_store/event/Position.md +5 -0
  69. python_event_sourcery-0.5.3a3/docs/reference/event_store/event/RawEvent.md +1 -0
  70. python_event_sourcery-0.5.3a3/docs/reference/event_store/event/Recorded.md +1 -0
  71. python_event_sourcery-0.5.3a3/docs/reference/event_store/event/RecordedRaw.md +1 -0
  72. python_event_sourcery-0.5.3a3/docs/reference/event_store/event/WrappedEvent.md +1 -0
  73. python_event_sourcery-0.5.3a3/docs/reference/event_store/exceptions.md +36 -0
  74. python_event_sourcery-0.5.3a3/docs/reference/event_store/in_transaction/Dispatcher.md +1 -0
  75. python_event_sourcery-0.5.3a3/docs/reference/event_store/in_transaction/Listener.md +1 -0
  76. python_event_sourcery-0.5.3a3/docs/reference/event_store/in_transaction/Listeners.md +1 -0
  77. python_event_sourcery-0.5.3a3/docs/reference/event_store/interfaces/EncryptionKeyStorageStrategy.md +1 -0
  78. python_event_sourcery-0.5.3a3/docs/reference/event_store/interfaces/EncryptionStrategy.md +1 -0
  79. python_event_sourcery-0.5.3a3/docs/reference/event_store/interfaces/OutboxFiltererStrategy.md +1 -0
  80. python_event_sourcery-0.5.3a3/docs/reference/event_store/interfaces/OutboxStorageStrategy.md +1 -0
  81. python_event_sourcery-0.5.3a3/docs/reference/event_store/interfaces/StorageStrategy.md +1 -0
  82. python_event_sourcery-0.5.3a3/docs/reference/event_store/interfaces/SubscriptionStrategy.md +1 -0
  83. python_event_sourcery-0.5.3a3/docs/reference/event_store/outbox/NoOutboxStorageStrategy.md +1 -0
  84. python_event_sourcery-0.5.3a3/docs/reference/event_store/outbox/Outbox.md +1 -0
  85. python_event_sourcery-0.5.3a3/docs/reference/event_store/outbox/no_filter.md +1 -0
  86. python_event_sourcery-0.5.3a3/docs/reference/event_store/subscription/BuildPhase.md +1 -0
  87. python_event_sourcery-0.5.3a3/docs/reference/event_store/subscription/FilterPhase.md +1 -0
  88. python_event_sourcery-0.5.3a3/docs/reference/event_store/subscription/PositionPhase.md +1 -0
  89. python_event_sourcery-0.5.3a3/docs/reference/event_store/subscription/SubscriptionBuilder.md +1 -0
  90. python_event_sourcery-0.5.3a3/docs/res/eda_example.plantuml +13 -0
  91. python_event_sourcery-0.5.3a3/docs/res/eda_example.png +0 -0
  92. python_event_sourcery-0.5.3a3/event_sourcery_kurrentdb/py.typed +0 -0
  93. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/cursors_dao.py +3 -2
  94. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/event_store.py +3 -2
  95. python_event_sourcery-0.5.3a3/event_sourcery_sqlalchemy/py.typed +0 -0
  96. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/pyproject.toml +44 -41
  97. python_event_sourcery-0.5.3a3/tests/__init__.py +0 -0
  98. python_event_sourcery-0.5.3a3/tests/backend/__init__.py +0 -0
  99. python_event_sourcery-0.5.3a3/tests/backend/django.py +34 -0
  100. python_event_sourcery-0.5.3a3/tests/backend/in_memory.py +8 -0
  101. python_event_sourcery-0.5.3a3/tests/backend/kurrentdb.py +28 -0
  102. python_event_sourcery-0.5.3a3/tests/backend/sqlalchemy.py +94 -0
  103. python_event_sourcery-0.5.3a3/tests/backend/test_sqlalchemy.py +88 -0
  104. python_event_sourcery-0.5.3a3/tests/bdd.py +309 -0
  105. python_event_sourcery-0.5.3a3/tests/conftest.py +47 -0
  106. python_event_sourcery-0.5.3a3/tests/event_sourcing/__init__.py +0 -0
  107. python_event_sourcery-0.5.3a3/tests/event_sourcing/conftest.py +10 -0
  108. python_event_sourcery-0.5.3a3/tests/event_sourcing/light_switch.py +45 -0
  109. python_event_sourcery-0.5.3a3/tests/event_sourcing/test_aggregate.py +101 -0
  110. python_event_sourcery-0.5.3a3/tests/event_sourcing/test_wrapped_aggregate.py +153 -0
  111. python_event_sourcery-0.5.3a3/tests/event_store/__init__.py +0 -0
  112. python_event_sourcery-0.5.3a3/tests/event_store/conftest.py +63 -0
  113. python_event_sourcery-0.5.3a3/tests/event_store/event/__init__.py +0 -0
  114. python_event_sourcery-0.5.3a3/tests/event_store/event/test_dto.py +30 -0
  115. python_event_sourcery-0.5.3a3/tests/event_store/event/test_privacy.py +312 -0
  116. python_event_sourcery-0.5.3a3/tests/event_store/event/test_registry.py +87 -0
  117. python_event_sourcery-0.5.3a3/tests/event_store/outbox/__init__.py +0 -0
  118. python_event_sourcery-0.5.3a3/tests/event_store/outbox/conftest.py +83 -0
  119. python_event_sourcery-0.5.3a3/tests/event_store/outbox/test_filters.py +31 -0
  120. python_event_sourcery-0.5.3a3/tests/event_store/outbox/test_multitenancy.py +32 -0
  121. python_event_sourcery-0.5.3a3/tests/event_store/outbox/test_outbox.py +75 -0
  122. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/__init__.py +0 -0
  123. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/other_client.py +128 -0
  124. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/test_batch.py +68 -0
  125. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/test_from_position.py +77 -0
  126. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/test_handling_uncommitted_messages_from_other_clients.py +240 -0
  127. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/test_in_transaction_subscription.py +185 -0
  128. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/test_subscriptions.py +74 -0
  129. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/test_to_category.py +106 -0
  130. python_event_sourcery-0.5.3a3/tests/event_store/subscriptions/test_to_event_types.py +107 -0
  131. python_event_sourcery-0.5.3a3/tests/event_store/test_category.py +65 -0
  132. python_event_sourcery-0.5.3a3/tests/event_store/test_concurrency_control.py +42 -0
  133. python_event_sourcery-0.5.3a3/tests/event_store/test_multitenancy.py +44 -0
  134. python_event_sourcery-0.5.3a3/tests/event_store/test_named_streams.py +66 -0
  135. python_event_sourcery-0.5.3a3/tests/event_store/test_no_outbox.py +11 -0
  136. python_event_sourcery-0.5.3a3/tests/event_store/test_no_versioning.py +62 -0
  137. python_event_sourcery-0.5.3a3/tests/event_store/test_removing_stream.py +15 -0
  138. python_event_sourcery-0.5.3a3/tests/event_store/test_save_retrieval.py +85 -0
  139. python_event_sourcery-0.5.3a3/tests/event_store/test_snapshots.py +76 -0
  140. python_event_sourcery-0.5.3a3/tests/event_store/test_stream_id.py +105 -0
  141. python_event_sourcery-0.5.3a3/tests/factories.py +45 -0
  142. python_event_sourcery-0.5.3a3/tests/mark.py +33 -0
  143. python_event_sourcery-0.5.3a3/tests/matchers.py +42 -0
  144. python_event_sourcery-0.5.3a3/tests/read_model/__init__.py +0 -0
  145. python_event_sourcery-0.5.3a3/tests/read_model/test_projector.py +252 -0
  146. python_event_sourcery-0.5.3a3/uv.lock +1675 -0
  147. python_event_sourcery-0.5.3a3/zensical.toml +126 -0
  148. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/LICENSE +0 -0
  149. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/README.md +0 -0
  150. {python_event_sourcery-0.5.3a1/event_sourcery/_event_store → python_event_sourcery-0.5.3a3/docs/code}/__init__.py +0 -0
  151. {python_event_sourcery-0.5.3a1/event_sourcery/_event_store/event → python_event_sourcery-0.5.3a3/docs/code/recipes/integrate}/__init__.py +0 -0
  152. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/__init__.py +0 -0
  153. {python_event_sourcery-0.5.3a1/event_sourcery/_event_store/subscription → python_event_sourcery-0.5.3a3/event_sourcery/_event_store}/__init__.py +0 -0
  154. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/backend.py +0 -0
  155. {python_event_sourcery-0.5.3a1/event_sourcery_django/migrations → python_event_sourcery-0.5.3a3/event_sourcery/_event_store/event}/__init__.py +0 -0
  156. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/event/dto.py +0 -0
  157. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/event/encryption.py +0 -0
  158. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/event/registry.py +0 -0
  159. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/event/serde.py +0 -0
  160. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/event_store.py +0 -0
  161. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/in_memory.py +0 -0
  162. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/outbox.py +0 -0
  163. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/stream_id.py +0 -0
  164. /python_event_sourcery-0.5.3a1/event_sourcery/py.typed → /python_event_sourcery-0.5.3a3/event_sourcery/_event_store/subscription/__init__.py +0 -0
  165. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/subscription/builder.py +0 -0
  166. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/subscription/in_transaction.py +0 -0
  167. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/subscription/interfaces.py +0 -0
  168. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/tenant_id.py +0 -0
  169. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/_event_store/versioning.py +0 -0
  170. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/backend.py +0 -0
  171. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/encryption.py +0 -0
  172. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/event.py +0 -0
  173. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/event_sourcing/__init__.py +0 -0
  174. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/event_sourcing/aggregate.py +0 -0
  175. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/event_sourcing/repository.py +0 -0
  176. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/exceptions.py +0 -0
  177. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/in_transaction.py +0 -0
  178. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/interfaces.py +0 -0
  179. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/outbox.py +0 -0
  180. {python_event_sourcery-0.5.3a1/event_sourcery_django → python_event_sourcery-0.5.3a3/event_sourcery}/py.typed +0 -0
  181. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/read_model/__init__.py +0 -0
  182. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/read_model/cursors_dao.py +0 -0
  183. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/read_model/projector.py +0 -0
  184. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery/subscription.py +0 -0
  185. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_django/__init__.py +0 -0
  186. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_django/dto.py +0 -0
  187. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_django/event_store.py +0 -0
  188. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_django/migrations/0001_initial.py +0 -0
  189. /python_event_sourcery-0.5.3a1/event_sourcery_kurrentdb/py.typed → /python_event_sourcery-0.5.3a3/event_sourcery_django/migrations/__init__.py +0 -0
  190. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_django/models.py +0 -0
  191. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_django/outbox.py +0 -0
  192. {python_event_sourcery-0.5.3a1/event_sourcery_sqlalchemy → python_event_sourcery-0.5.3a3/event_sourcery_django}/py.typed +0 -0
  193. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_django/subscription.py +0 -0
  194. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_kurrentdb/__init__.py +0 -0
  195. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_kurrentdb/dto.py +0 -0
  196. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_kurrentdb/event_store.py +0 -0
  197. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_kurrentdb/outbox.py +0 -0
  198. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_kurrentdb/stream.py +0 -0
  199. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_kurrentdb/subscription.py +0 -0
  200. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/__init__.py +0 -0
  201. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/dto.py +0 -0
  202. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/guid.py +0 -0
  203. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/jsonb.py +0 -0
  204. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/models/__init__.py +0 -0
  205. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/models/base.py +0 -0
  206. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/models/default.py +0 -0
  207. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/outbox.py +0 -0
  208. {python_event_sourcery-0.5.3a1 → python_event_sourcery-0.5.3a3}/event_sourcery_sqlalchemy/subscription.py +0 -0
@@ -0,0 +1 @@
1
+ docs/adr
@@ -0,0 +1,35 @@
1
+ name: Bump version and publish
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+
7
+ env:
8
+ PYTHON_VERSION: "3.10"
9
+
10
+ jobs:
11
+ bump-and-publish:
12
+ if: github.event.head_commit.message != 'Autobump version'
13
+ permissions:
14
+ contents: write
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v2
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v7
20
+ with:
21
+ python-version: ${{ env.PYTHON_VERSION }}
22
+ enable-cache: true
23
+ - name: Bump version
24
+ run: uv version --bump alpha
25
+ - uses: EndBug/add-and-commit@v9
26
+ with:
27
+ add: "pyproject.toml uv.lock"
28
+ author_name: Python Event Sourcery Bot
29
+ message: 'Autobump version'
30
+ - name: Publish prerelease
31
+ env:
32
+ PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
33
+ run: |
34
+ uv build
35
+ uv publish --token $PYPI_TOKEN
@@ -0,0 +1,32 @@
1
+ name: Deploy docs
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ workflow_dispatch:
7
+
8
+ env:
9
+ PYTHON_VERSION: "3.10"
10
+
11
+ permissions:
12
+ contents: write
13
+
14
+ jobs:
15
+ deploy:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v7
21
+ with:
22
+ python-version: ${{ env.PYTHON_VERSION }}
23
+ enable-cache: true
24
+ - name: Install deps
25
+ run: uv sync --all-extras
26
+ - name: Build docs
27
+ run: uv run --all-extras zensical build --clean
28
+ - name: Deploy to GitHub Pages
29
+ uses: peaceiris/actions-gh-pages@v4
30
+ with:
31
+ github_token: ${{ secrets.GITHUB_TOKEN }}
32
+ publish_dir: ./site
@@ -0,0 +1,58 @@
1
+ name: Lint & tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ build:
11
+
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: [ '3.10', '3.11', '3.12', '3.13' ]
16
+
17
+ services:
18
+ postgres:
19
+ image: postgres:14
20
+ env:
21
+ POSTGRES_USER: es
22
+ POSTGRES_PASSWORD: es
23
+ options: >-
24
+ --health-cmd pg_isready
25
+ --health-interval 10s
26
+ --health-timeout 5s
27
+ --health-retries 5
28
+ ports:
29
+ - 5432:5432
30
+
31
+ eventstoredb:
32
+ image: eventstore/eventstore:latest
33
+ env:
34
+ EVENTSTORE_MEM_DB: True
35
+ EVENTSTORE_CLUSTER_SIZE: 1
36
+ EVENTSTORE_RUN_PROJECTIONS: All
37
+ EVENTSTORE_START_STANDARD_PROJECTIONS: true
38
+ EVENTSTORE_INSECURE: true
39
+ EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP: true
40
+ ports:
41
+ - 1113:1113
42
+ - 2113:2113
43
+
44
+ steps:
45
+ - uses: actions/checkout@v2
46
+ - name: Install uv
47
+ uses: astral-sh/setup-uv@v7
48
+ with:
49
+ python-version: ${{ matrix.python-version }}
50
+ enable-cache: true
51
+ - name: Install deps
52
+ run: uv sync --all-extras
53
+ - name: Run linters
54
+ run: make lint
55
+ - name: Build docs
56
+ run: uv run --all-extras zensical build --clean
57
+ - name: Test with pytest
58
+ run: make test
@@ -0,0 +1,24 @@
1
+ name: Publish on Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ env:
8
+ PYTHON_VERSION: "3.10"
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v7
17
+ with:
18
+ python-version: ${{ env.PYTHON_VERSION }}
19
+ - name: Publish to PyPI
20
+ env:
21
+ PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
22
+ run: |
23
+ uv build
24
+ uv publish --token $PYPI_TOKEN
@@ -0,0 +1,129 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
@@ -0,0 +1,45 @@
1
+ # AGENTS.md
2
+
3
+ Event sourcing library for Python with pluggable backends.
4
+
5
+ ## Layout
6
+
7
+ - `event_sourcery/` — core library
8
+ - `event_sourcery_sqlalchemy/`, `event_sourcery_django/`, `event_sourcery_kurrentdb/` — backends (optional extras: `sqlalchemy`, `django`, `kurrentdb`)
9
+ - `tests/` — shared test suite run against every backend
10
+ - `docs/` — documentation (zensical)
11
+
12
+ ## Tooling
13
+
14
+ Package manager: **uv** (PEP 621 `pyproject.toml`, `uv.lock` committed).
15
+
16
+ ```bash
17
+ uv sync --all-extras # install all deps (dev group is included by default)
18
+ ```
19
+
20
+ ## Commands
21
+
22
+ ```bash
23
+ docker compose up -d # required before tests (postgres, kurrentdb, rabbitmq)
24
+ make test # pytest with coverage (fail_under = 100)
25
+ make lint # ruff format + ruff check + mypy (must pass clean)
26
+ make docs-serve # docs live preview
27
+ ```
28
+
29
+ Run single tools via `uv run --all-extras <tool>`, e.g. `uv run --all-extras pytest tests/event_store -k django`.
30
+
31
+ ## Conventions
32
+
33
+ - Python >= 3.10, strict mypy (`disallow_untyped_defs`), ruff line-length 88.
34
+ - New backend functionality goes through the shared test suite in `tests/`; use `not_implemented` / `skip_backend` markers for unsupported features.
35
+ - Version bumps: `uv version --bump alpha` (CI autopublishes prereleases on push to main).
36
+
37
+ ## Docs
38
+
39
+ Changing public API or behavior may require updating `docs/` — pages embed runnable snippets from `docs/code/` (via `--8<--` includes). After touching docs code:
40
+
41
+ ```bash
42
+ uv run --all-extras pytest docs/code # snippets are real tests, must pass
43
+ make lint-fix-docs # lint docs/code
44
+ uv run --all-extras zensical build --clean # verify docs build
45
+ ```
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## 0.5.2
4
+ ### Changed
5
+ - **Breaking:** `Repository.aggregate()` yields `WrappedAggregate` instead of `Aggregate` directly
6
+
7
+ ## 0.5.1
8
+ ### Added
9
+ - In transaction subscription to category
10
+ - Custom context support in `Repository.aggregate()` via optional `context` parameter
11
+ - `WrappedEvent.get_context()` method for typed context retrieval
12
+ ### Fixes
13
+ - event_sourcery_sqlalchemy.configure_models annotation for sqlalchemy.orm.DeclarativeBase
14
+
15
+ ## 0.5.0
16
+ ### Added
17
+ - Event definitions via the `Event` base class (Pydantic) with built-in metadata and tracing IDs.
18
+ - Event Store API for appending/loading streams with optimistic concurrency and optional `NO_VERSIONING`.
19
+ - Stream snapshots to optimize long event streams.
20
+ - Outbox pattern with retries and optional filters, plus synchronous in-process subscriptions.
21
+ - Subscription builder with single-event and batch iterators for asynchronous processing.
22
+ - Multi-tenancy with tenant-scoped stores and explicit visibility rules.
23
+ - Crypto-shredding and field-level encryption via `Encrypted` and `DataSubject` markers.
24
+ - Event sourcing primitives: `Aggregate` and `Repository` base classes.
25
+ - Backend integrations for SQLAlchemy, Django, KurrentDB (EventStoreDB), and in-memory storage.
@@ -0,0 +1,40 @@
1
+ # Basics
2
+
3
+ ## Prerequisites
4
+
5
+ - docker + docker compose / any compatible replacement
6
+ - uv
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ uv sync --all-extras
12
+ ```
13
+
14
+ ## Running tests
15
+
16
+ ```bash
17
+ docker compose up
18
+ make test
19
+ ```
20
+
21
+ ## Running linters
22
+
23
+ ```bash
24
+ make lint
25
+ ```
26
+
27
+ # Documentation
28
+
29
+ First, `cd docs/documentation`
30
+
31
+ ## Serve docs with live preview
32
+
33
+ ```bash
34
+ zensical serve
35
+ ```
36
+
37
+ ## Deploy docs to github pages
38
+
39
+ Docs get auto deployed from main after each change.
40
+
@@ -0,0 +1,20 @@
1
+ SRC_DIRS ?= ${wildcard event_sourcery*}
2
+
3
+ .PHONY: lint
4
+ lint:
5
+ uv run --all-extras ruff format $(SRC_DIRS) tests/
6
+ uv run --all-extras ruff check $(SRC_DIRS) tests/ --fix
7
+ uv run --all-extras mypy $(SRC_DIRS) tests/
8
+
9
+ .PHONY: test
10
+ test:
11
+ uv run --all-extras pytest $(addprefix --cov ,$(SRC_DIRS)) tests/
12
+
13
+ .PHONY: docs-serve
14
+ docs-serve:
15
+ uv run --all-extras zensical serve
16
+
17
+ .PHONY: lint-fix-docs
18
+ lint-fix-docs:
19
+ uv run --all-extras ruff format docs/code tests/
20
+ uv run --all-extras ruff check docs/code --fix
@@ -1,26 +1,20 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.5
2
2
  Name: python-event-sourcery
3
- Version: 0.5.3a1
3
+ Version: 0.5.3a3
4
4
  Summary: A library for event-based systems in Python.
5
- License: MIT
6
- Author: Sebastian Buczyński
7
- Author-email: nnplaya@gmail.com
5
+ Author-email: Sebastian Buczyński <nnplaya@gmail.com>, Łukasz Żukowski <lukasz.zukowski@gmail.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
8
  Requires-Python: >=3.10
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
9
+ Requires-Dist: more-itertools
10
+ Requires-Dist: psycopg2-binary<3,>2
11
+ Requires-Dist: pydantic<3,>=2.0
15
12
  Provides-Extra: django
13
+ Requires-Dist: django<6,>=4; extra == 'django'
16
14
  Provides-Extra: kurrentdb
15
+ Requires-Dist: kurrentdbclient>=1.0.6; extra == 'kurrentdb'
17
16
  Provides-Extra: sqlalchemy
18
- Requires-Dist: SQLAlchemy (>=2.0) ; extra == "sqlalchemy"
19
- Requires-Dist: django (>=4,<6) ; extra == "django"
20
- Requires-Dist: kurrentdbclient (>=1.0.6) ; extra == "kurrentdb"
21
- Requires-Dist: more-itertools
22
- Requires-Dist: psycopg2-binary (>2,<3)
23
- Requires-Dist: pydantic (>=2.0,<3)
17
+ Requires-Dist: sqlalchemy>=2.0; extra == 'sqlalchemy'
24
18
  Description-Content-Type: text/markdown
25
19
 
26
20
 
@@ -149,4 +143,3 @@ Anything missing? Create an issue in this repository. Let others upvote
149
143
  ## Inspirations
150
144
  - [Rails Event Store](https://railseventstore.org/)
151
145
  - [Marten](https://martendb.io/)
152
-
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env python
2
+ """Django's command-line utility for administrative tasks."""
3
+ import os
4
+ import sys
5
+
6
+
7
+ def main() -> None:
8
+ """Run administrative tasks."""
9
+ from tests.backend import django as django_backend
10
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", django_backend.__name__)
11
+ try:
12
+ from django.core.management import execute_from_command_line
13
+ except ImportError as exc:
14
+ raise ImportError(
15
+ "Couldn't import Django. Are you sure it's installed and "
16
+ "available on your PYTHONPATH environment variable? Did you "
17
+ "forget to activate a virtual environment?"
18
+ ) from exc
19
+ execute_from_command_line(sys.argv)
20
+
21
+
22
+ if __name__ == "__main__":
23
+ main()
@@ -0,0 +1,26 @@
1
+ services:
2
+ postgres:
3
+ image: postgres:14
4
+ environment:
5
+ POSTGRES_USER: es
6
+ POSTGRES_PASSWORD: es
7
+ ports:
8
+ - "5432:5432"
9
+
10
+ rabbitmq:
11
+ image: rabbitmq:3.11.2-management
12
+ ports:
13
+ - '5672:5672'
14
+ - '15672:15672'
15
+
16
+ kurrentdb:
17
+ image: kurrentplatform/kurrentdb
18
+ environment:
19
+ - KURRENTDB_CLUSTER_SIZE=1
20
+ - KURRENTDB_RUN_PROJECTIONS=All
21
+ - KURRENTDB_START_STANDARD_PROJECTIONS=true
22
+ - KURRENTDB_INSECURE=true
23
+ - KURRENTDB_ENABLE_ATOM_PUB_OVER_HTTP=true
24
+ - KURRENTDB_NODE_PORT=2113
25
+ ports:
26
+ - "2113:2113"
@@ -0,0 +1,19 @@
1
+ # Record architecture decisions
2
+
3
+ Date: 2022-07-30
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ We need to record the architectural decisions made on this project.
12
+
13
+ ## Decision
14
+
15
+ We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions).
16
+
17
+ ## Consequences
18
+
19
+ See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools).
@@ -0,0 +1,129 @@
1
+ # Explicit __init__ arguments for SQLAlchemy's models
2
+
3
+ Date: 2023-09-03
4
+
5
+ ## Status
6
+
7
+ Draft
8
+
9
+ ## Context
10
+
11
+ We aim for having full support regarding
12
+
13
+ ## Possible solutions
14
+
15
+ ### Use native support for dataclasses in SQLAlchemy
16
+
17
+ Starting from SQLAlchemy 2.0, there's a [native support for dataclasses](https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html#native-support-for-dataclasses-mapped-as-orm-models).
18
+
19
+ However, it's less seamless than one might initially imagine. It comes down to inheriting explicitly from another base class, namely `sqlalchemy.orm.MappedAsDataclass` and using it as a base for models:
20
+ ```python
21
+ from sqlalchemy.orm import DeclarativeBase
22
+ from sqlalchemy.orm import MappedAsDataclass
23
+
24
+ class Base(MappedAsDataclass, DeclarativeBase):
25
+ """subclasses will be converted to dataclasses"""
26
+
27
+ class User(Base):
28
+ __tablename__ = "user_account"
29
+
30
+ id: Mapped[intpk] = mapped_column(init=False)
31
+ ```
32
+
33
+ As a result, `User` becomes a dataclass with attached SQLAlchemy's behaviour.
34
+
35
+ In terms of risk, this may cause compatibility issues. As a reminder, Event Sourcery's models are declared as bare classes (notice lack of inheritance from `Base`):
36
+
37
+ ```python
38
+ class Stream:
39
+ __tablename__ = "event_sourcery_streams"
40
+ __table_args__ = (
41
+ UniqueConstraint("uuid", "category"),
42
+ UniqueConstraint("name", "category"),
43
+ )
44
+
45
+ id = mapped_column(BigInteger().with_variant(Integer(), "sqlite"), primary_key=True)
46
+ ```
47
+
48
+ The assumption is that someone setting up a project with SQLAlchemy will have their own `Base` class and models. The library will let them attach our models to their declarative base later using `event_sourcery_sqlalchemy.models.configure_models`, like:
49
+
50
+ ```python
51
+ @as_declarative()
52
+ class Base:
53
+ pass
54
+
55
+
56
+ # initialize Event Sourcery models, so they can be handled by SQLAlchemy and e.g. alembic
57
+ configure_models(Base)
58
+ ```
59
+
60
+ The exception is raised in case `MappedAsDataclass` appears multiple time in model's MRO, for example:
61
+ - let's say we have a base class for our models that inherits from `MappedAsDataclass`
62
+ - someone has their own `Base` that also inherits from `MappedAsDataclass`
63
+
64
+ ```
65
+ sqlalchemy.exc.InvalidRequestError: Class <class 'event_sourcery_sqlalchemy.models.Stream'> is already a dataclass; ensure that base classes / decorator styles of establishing dataclasses are not being mixed. This can happen if a class that inherits from 'MappedAsDataclass', even indirectly, is been mapped with '@registry.mapped_as_dataclass'
66
+ ```
67
+
68
+ To reproduce, add `MappedAsDataclass` as a base to any model and use this snippet:
69
+
70
+ ```python
71
+ from sqlalchemy import create_engine
72
+ from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass
73
+
74
+ from event_sourcery_sqlalchemy.models import configure_models
75
+
76
+
77
+ engine = create_engine(
78
+ "sqlite+pysqlite:///:memory:", echo=True, future=True
79
+ )
80
+
81
+
82
+ class Base(MappedAsDataclass, DeclarativeBase):
83
+ pass
84
+
85
+
86
+ Base.metadata.create_all(bind=engine)
87
+
88
+
89
+ # initialize Event Sourcery models, so they can be handled by SQLAlchemy and e.g. alembic
90
+ configure_models(Base)
91
+ ```
92
+
93
+
94
+ ### Create base class for models with overridden __init__
95
+
96
+ There is a recipe for providing base class model with overriding `__init__`:
97
+ ```python
98
+ class ModelBase:
99
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
100
+ return super().__init__(*args, **kwargs)
101
+ ```
102
+
103
+ This basically makes mypy unable to verify anything extra because such a signature allows everything to be passed in. Conversely, all operations are considered to be correct from type checker's perspective.
104
+
105
+ This solution is a bit tricky and just gets rid of warnings, but doesn't give us any additional benefits.
106
+
107
+ ### Define our own, explicit `__init__` definition
108
+
109
+ We can simply provide tailored `__init__` for each model to get type safety out of the box.
110
+
111
+ ```python
112
+ class Stream:
113
+ def __init__(self) -> None:
114
+ pass
115
+
116
+
117
+ ```
118
+
119
+ This is safe & compatible with other ORM's features because SQLAlchemy uses other means to build an object when e.g. fetching them from the database.
120
+ In other words, SQLAlchemy internally is not invoking `__init__`.
121
+
122
+ ## Decision
123
+
124
+ Writing custom `__init__` makes the most sense.
125
+
126
+ ## Consequences
127
+
128
+ Whenever someone changes fields of a model (this should be rare after release), `__init__` needs to follow.
129
+ However, this inconvenience can be potentially automated away in the future. At least, we could also have a custom static code check that would guard that.