hexcore 7.0.0__tar.gz → 9.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 (370) hide show
  1. hexcore-9.0.0/PKG-INFO +340 -0
  2. hexcore-9.0.0/README.md +265 -0
  3. hexcore-9.0.0/hexcore/__init__.py +86 -0
  4. hexcore-9.0.0/hexcore/_deprecation.py +206 -0
  5. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/cqrs/in_memory_buses.py +24 -5
  6. hexcore-9.0.0/hexcore/application/eventsourcing/__init__.py +14 -0
  7. hexcore-9.0.0/hexcore/application/eventsourcing/config.py +115 -0
  8. hexcore-9.0.0/hexcore/application/eventsourcing/factory.py +208 -0
  9. hexcore-9.0.0/hexcore/application/eventsourcing/projector.py +301 -0
  10. hexcore-9.0.0/hexcore/application/eventsourcing/relay.py +202 -0
  11. hexcore-9.0.0/hexcore/application/eventsourcing/repository.py +211 -0
  12. hexcore-9.0.0/hexcore/capabilities.py +145 -0
  13. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/config.py +78 -27
  14. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/cqrs.py +48 -1
  15. hexcore-9.0.0/hexcore/cqrs.pyi +146 -0
  16. hexcore-9.0.0/hexcore/darwin/__init__.py +499 -0
  17. hexcore-9.0.0/hexcore/darwin/__init__.pyi +402 -0
  18. hexcore-9.0.0/hexcore/darwin/application/__init__.py +6 -0
  19. hexcore-9.0.0/hexcore/darwin/application/commands.py +360 -0
  20. hexcore-9.0.0/hexcore/darwin/application/config.py +355 -0
  21. hexcore-9.0.0/hexcore/darwin/application/container.py +573 -0
  22. hexcore-9.0.0/hexcore/darwin/application/hooks.py +130 -0
  23. hexcore-9.0.0/hexcore/darwin/application/plugins.py +397 -0
  24. hexcore-9.0.0/hexcore/darwin/application/services.py +840 -0
  25. hexcore-9.0.0/hexcore/darwin/domain/__init__.py +8 -0
  26. hexcore-9.0.0/hexcore/darwin/domain/context.py +390 -0
  27. hexcore-9.0.0/hexcore/darwin/domain/entities.py +201 -0
  28. hexcore-9.0.0/hexcore/darwin/domain/events.py +181 -0
  29. hexcore-9.0.0/hexcore/darwin/domain/exceptions.py +208 -0
  30. hexcore-9.0.0/hexcore/darwin/domain/permissions.py +321 -0
  31. hexcore-9.0.0/hexcore/darwin/domain/plugins.py +311 -0
  32. hexcore-9.0.0/hexcore/darwin/domain/ports.py +343 -0
  33. hexcore-9.0.0/hexcore/darwin/domain/value_objects.py +232 -0
  34. hexcore-9.0.0/hexcore/darwin/infrastructure/__init__.py +8 -0
  35. hexcore-9.0.0/hexcore/darwin/infrastructure/api/__init__.py +7 -0
  36. hexcore-9.0.0/hexcore/darwin/infrastructure/api/dependencies.py +176 -0
  37. hexcore-9.0.0/hexcore/darwin/infrastructure/api/middlewares.py +289 -0
  38. hexcore-9.0.0/hexcore/darwin/infrastructure/api/routers.py +457 -0
  39. hexcore-9.0.0/hexcore/darwin/infrastructure/cli.py +175 -0
  40. hexcore-9.0.0/hexcore/darwin/infrastructure/clock.py +79 -0
  41. hexcore-9.0.0/hexcore/darwin/infrastructure/envelope.py +429 -0
  42. hexcore-9.0.0/hexcore/darwin/infrastructure/hashing.py +213 -0
  43. hexcore-9.0.0/hexcore/darwin/infrastructure/keys.py +308 -0
  44. hexcore-9.0.0/hexcore/darwin/infrastructure/lifespan.py +205 -0
  45. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/__init__.py +13 -0
  46. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/beanie/__init__.py +6 -0
  47. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/beanie/documents.py +313 -0
  48. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/beanie/repositories.py +572 -0
  49. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/beanie/schema.py +174 -0
  50. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/selection.py +136 -0
  51. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/sqlalchemy/__init__.py +10 -0
  52. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/sqlalchemy/models.py +97 -0
  53. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/sqlalchemy/models_mixins.py +400 -0
  54. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/sqlalchemy/repositories.py +682 -0
  55. hexcore-9.0.0/hexcore/darwin/infrastructure/orms/sqlalchemy/schema.py +287 -0
  56. hexcore-9.0.0/hexcore/darwin/infrastructure/revocation.py +299 -0
  57. hexcore-9.0.0/hexcore/darwin/infrastructure/secretbox.py +117 -0
  58. hexcore-9.0.0/hexcore/darwin/infrastructure/tokens.py +398 -0
  59. hexcore-9.0.0/hexcore/darwin/infrastructure/transports.py +277 -0
  60. hexcore-9.0.0/hexcore/darwin/plugins/__init__.py +6 -0
  61. hexcore-9.0.0/hexcore/darwin/plugins/impersonate/__init__.py +244 -0
  62. hexcore-9.0.0/hexcore/darwin/plugins/impersonate/commands.py +76 -0
  63. hexcore-9.0.0/hexcore/darwin/plugins/impersonate/domain.py +208 -0
  64. hexcore-9.0.0/hexcore/darwin/plugins/impersonate/router.py +194 -0
  65. hexcore-9.0.0/hexcore/darwin/plugins/impersonate/service.py +310 -0
  66. hexcore-9.0.0/hexcore/darwin/plugins/magic_link/__init__.py +124 -0
  67. hexcore-9.0.0/hexcore/darwin/plugins/magic_link/commands.py +233 -0
  68. hexcore-9.0.0/hexcore/darwin/plugins/magic_link/router.py +152 -0
  69. hexcore-9.0.0/hexcore/darwin/plugins/oauth/__init__.py +320 -0
  70. hexcore-9.0.0/hexcore/darwin/plugins/oauth/domain.py +252 -0
  71. hexcore-9.0.0/hexcore/darwin/plugins/oauth/http.py +219 -0
  72. hexcore-9.0.0/hexcore/darwin/plugins/oauth/orms/__init__.py +13 -0
  73. hexcore-9.0.0/hexcore/darwin/plugins/oauth/orms/beanie/__init__.py +6 -0
  74. hexcore-9.0.0/hexcore/darwin/plugins/oauth/orms/beanie/repository.py +148 -0
  75. hexcore-9.0.0/hexcore/darwin/plugins/oauth/orms/sqlalchemy/__init__.py +10 -0
  76. hexcore-9.0.0/hexcore/darwin/plugins/oauth/orms/sqlalchemy/models.py +80 -0
  77. hexcore-9.0.0/hexcore/darwin/plugins/oauth/orms/sqlalchemy/models_mixins.py +115 -0
  78. hexcore-9.0.0/hexcore/darwin/plugins/oauth/orms/sqlalchemy/repository.py +136 -0
  79. hexcore-9.0.0/hexcore/darwin/plugins/oauth/providers.py +278 -0
  80. hexcore-9.0.0/hexcore/darwin/plugins/oauth/router.py +249 -0
  81. hexcore-9.0.0/hexcore/darwin/plugins/oauth/service.py +575 -0
  82. hexcore-9.0.0/hexcore/darwin/plugins/organization/__init__.py +247 -0
  83. hexcore-9.0.0/hexcore/darwin/plugins/organization/domain.py +345 -0
  84. hexcore-9.0.0/hexcore/darwin/plugins/organization/orms/__init__.py +13 -0
  85. hexcore-9.0.0/hexcore/darwin/plugins/organization/orms/beanie/__init__.py +6 -0
  86. hexcore-9.0.0/hexcore/darwin/plugins/organization/orms/beanie/repository.py +557 -0
  87. hexcore-9.0.0/hexcore/darwin/plugins/organization/orms/sqlalchemy/__init__.py +10 -0
  88. hexcore-9.0.0/hexcore/darwin/plugins/organization/orms/sqlalchemy/models.py +114 -0
  89. hexcore-9.0.0/hexcore/darwin/plugins/organization/orms/sqlalchemy/models_mixins.py +193 -0
  90. hexcore-9.0.0/hexcore/darwin/plugins/organization/orms/sqlalchemy/repository.py +428 -0
  91. hexcore-9.0.0/hexcore/darwin/plugins/organization/router.py +351 -0
  92. hexcore-9.0.0/hexcore/darwin/plugins/organization/service.py +579 -0
  93. hexcore-9.0.0/hexcore/darwin/plugins/passkey/__init__.py +319 -0
  94. hexcore-9.0.0/hexcore/darwin/plugins/passkey/domain.py +322 -0
  95. hexcore-9.0.0/hexcore/darwin/plugins/passkey/orms/__init__.py +13 -0
  96. hexcore-9.0.0/hexcore/darwin/plugins/passkey/orms/beanie/__init__.py +6 -0
  97. hexcore-9.0.0/hexcore/darwin/plugins/passkey/orms/beanie/repository.py +274 -0
  98. hexcore-9.0.0/hexcore/darwin/plugins/passkey/orms/sqlalchemy/__init__.py +10 -0
  99. hexcore-9.0.0/hexcore/darwin/plugins/passkey/orms/sqlalchemy/models.py +114 -0
  100. hexcore-9.0.0/hexcore/darwin/plugins/passkey/orms/sqlalchemy/models_mixins.py +173 -0
  101. hexcore-9.0.0/hexcore/darwin/plugins/passkey/orms/sqlalchemy/repository.py +257 -0
  102. hexcore-9.0.0/hexcore/darwin/plugins/passkey/router.py +286 -0
  103. hexcore-9.0.0/hexcore/darwin/plugins/passkey/service.py +419 -0
  104. hexcore-9.0.0/hexcore/darwin/plugins/passkey/webauthn_adapter.py +257 -0
  105. hexcore-9.0.0/hexcore/darwin/plugins/storage.py +166 -0
  106. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/__init__.py +260 -0
  107. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/commands.py +121 -0
  108. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/crypto.py +43 -0
  109. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/domain.py +192 -0
  110. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/orms/__init__.py +13 -0
  111. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/orms/beanie/__init__.py +6 -0
  112. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/orms/beanie/repository.py +210 -0
  113. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/orms/sqlalchemy/__init__.py +10 -0
  114. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/orms/sqlalchemy/models.py +82 -0
  115. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/orms/sqlalchemy/models_mixins.py +113 -0
  116. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/orms/sqlalchemy/repository.py +224 -0
  117. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/router.py +239 -0
  118. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/service.py +397 -0
  119. hexcore-9.0.0/hexcore/darwin/plugins/two_factor/totp.py +198 -0
  120. hexcore-9.0.0/hexcore/darwin/testing/__init__.py +86 -0
  121. hexcore-9.0.0/hexcore/darwin/testing/fakes.py +567 -0
  122. hexcore-9.0.0/hexcore/darwin/testing/fixtures.py +107 -0
  123. hexcore-9.0.0/hexcore/darwin/testing/helpers.py +401 -0
  124. hexcore-9.0.0/hexcore/domain/auth/__init__.py +66 -0
  125. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/auth/permissions.py +7 -7
  126. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/base.py +65 -18
  127. hexcore-9.0.0/hexcore/domain/cqrs/__init__.py +60 -0
  128. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/buses.py +0 -20
  129. hexcore-9.0.0/hexcore/domain/cqrs/dispatch.py +89 -0
  130. hexcore-9.0.0/hexcore/domain/cqrs/envelope.py +245 -0
  131. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/handlers.py +0 -15
  132. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/middleware.py +0 -11
  133. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/resolution.py +5 -1
  134. hexcore-9.0.0/hexcore/domain/cqrs/serializer.py +103 -0
  135. hexcore-9.0.0/hexcore/domain/events.py +106 -0
  136. hexcore-9.0.0/hexcore/domain/eventsourcing/__init__.py +44 -0
  137. hexcore-9.0.0/hexcore/domain/eventsourcing/aggregate.py +330 -0
  138. hexcore-9.0.0/hexcore/domain/eventsourcing/exceptions.py +78 -0
  139. hexcore-9.0.0/hexcore/domain/eventsourcing/projections.py +98 -0
  140. hexcore-9.0.0/hexcore/domain/eventsourcing/snapshots.py +78 -0
  141. hexcore-9.0.0/hexcore/domain/eventsourcing/store.py +175 -0
  142. hexcore-9.0.0/hexcore/domain/eventsourcing/stored.py +95 -0
  143. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/services.py +2 -2
  144. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/uow.py +7 -0
  145. hexcore-9.0.0/hexcore/eventsourcing.py +255 -0
  146. hexcore-9.0.0/hexcore/eventsourcing.pyi +124 -0
  147. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/fastapi.py +6 -1
  148. hexcore-9.0.0/hexcore/fastapi.pyi +114 -0
  149. hexcore-9.0.0/hexcore/infrastructure/api/__init__.py +131 -0
  150. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/app.py +99 -2
  151. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/cqrs.py +3 -9
  152. hexcore-9.0.0/hexcore/infrastructure/api/eventsourcing.py +211 -0
  153. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/health.py +39 -15
  154. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/utils.py +0 -1
  155. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cache/cache_backends/redis.py +6 -2
  156. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cli.py +38 -1
  157. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/postgres_bus.py +70 -21
  158. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/postgres_lock.py +10 -7
  159. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/procrastinate.py +22 -12
  160. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/rabbitmq.py +28 -11
  161. hexcore-9.0.0/hexcore/infrastructure/cqrs/redis_bus.py +217 -0
  162. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/redis_lock.py +1 -2
  163. hexcore-9.0.0/hexcore/infrastructure/events/events_backends/memory.py +40 -0
  164. hexcore-9.0.0/hexcore/infrastructure/eventsourcing/__init__.py +11 -0
  165. hexcore-9.0.0/hexcore/infrastructure/eventsourcing/beanie_documents.py +190 -0
  166. hexcore-9.0.0/hexcore/infrastructure/eventsourcing/beanie_store.py +311 -0
  167. hexcore-9.0.0/hexcore/infrastructure/eventsourcing/memory.py +215 -0
  168. hexcore-9.0.0/hexcore/infrastructure/eventsourcing/redis_store.py +393 -0
  169. hexcore-9.0.0/hexcore/infrastructure/eventsourcing/sqlalchemy_models.py +137 -0
  170. hexcore-9.0.0/hexcore/infrastructure/eventsourcing/sqlalchemy_models_mixins.py +187 -0
  171. hexcore-9.0.0/hexcore/infrastructure/eventsourcing/sqlalchemy_store.py +503 -0
  172. hexcore-9.0.0/hexcore/infrastructure/repositories/_beanie_impl.py +87 -0
  173. hexcore-9.0.0/hexcore/infrastructure/repositories/_sqlalchemy_impl.py +133 -0
  174. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/base.py +9 -3
  175. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/decorators.py +6 -6
  176. hexcore-9.0.0/hexcore/infrastructure/repositories/implementations.py +119 -0
  177. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/orms/beanie/__init__.py +3 -1
  178. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/orms/beanie/utils.py +3 -2
  179. hexcore-9.0.0/hexcore/infrastructure/repositories/orms/sqlalchemy/__init__.py +71 -0
  180. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/orms/sqlalchemy/session.py +0 -17
  181. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/orms/sqlalchemy/utils.py +92 -5
  182. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/utils.py +31 -12
  183. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/task_queues/celery_adapter.py +60 -14
  184. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/task_queues/procrastinate_adapter.py +18 -8
  185. hexcore-9.0.0/hexcore/infrastructure/uow/__init__.py +442 -0
  186. hexcore-9.0.0/hexcore/infrastructure/uow/decorators.py +36 -0
  187. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/workers/consumer.py +22 -10
  188. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/workers/rabbitmq_worker.py +10 -1
  189. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/sql.py +19 -1
  190. hexcore-9.0.0/hexcore/sql.pyi +72 -0
  191. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/testing/__init__.py +3 -0
  192. hexcore-9.0.0/hexcore/testing/repositories.py +283 -0
  193. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/types.py +17 -5
  194. hexcore-9.0.0/hexcore.egg-info/PKG-INFO +340 -0
  195. hexcore-9.0.0/hexcore.egg-info/SOURCES.txt +347 -0
  196. hexcore-9.0.0/hexcore.egg-info/requires.txt +81 -0
  197. hexcore-9.0.0/pyproject.toml +237 -0
  198. hexcore-9.0.0/tests/test_alembic_metadata_completeness.py +194 -0
  199. hexcore-9.0.0/tests/test_cqrs_envelope.py +349 -0
  200. hexcore-9.0.0/tests/test_darwin_backend_neutrality.py +456 -0
  201. hexcore-9.0.0/tests/test_darwin_beanie.py +594 -0
  202. hexcore-9.0.0/tests/test_darwin_cli.py +263 -0
  203. hexcore-9.0.0/tests/test_darwin_container.py +338 -0
  204. hexcore-9.0.0/tests/test_darwin_context.py +284 -0
  205. hexcore-9.0.0/tests/test_darwin_custom_plugin.py +387 -0
  206. hexcore-9.0.0/tests/test_darwin_envelope.py +784 -0
  207. hexcore-9.0.0/tests/test_darwin_facade_and_events.py +447 -0
  208. hexcore-9.0.0/tests/test_darwin_flows.py +555 -0
  209. hexcore-9.0.0/tests/test_darwin_hashing.py +210 -0
  210. hexcore-9.0.0/tests/test_darwin_http.py +658 -0
  211. hexcore-9.0.0/tests/test_darwin_impersonate.py +1114 -0
  212. hexcore-9.0.0/tests/test_darwin_magic_link.py +597 -0
  213. hexcore-9.0.0/tests/test_darwin_models.py +369 -0
  214. hexcore-9.0.0/tests/test_darwin_oauth.py +1296 -0
  215. hexcore-9.0.0/tests/test_darwin_organization.py +1313 -0
  216. hexcore-9.0.0/tests/test_darwin_passkey.py +1174 -0
  217. hexcore-9.0.0/tests/test_darwin_permissions.py +240 -0
  218. hexcore-9.0.0/tests/test_darwin_plugin_decoupling.py +343 -0
  219. hexcore-9.0.0/tests/test_darwin_plugins.py +860 -0
  220. hexcore-9.0.0/tests/test_darwin_repositories.py +489 -0
  221. hexcore-9.0.0/tests/test_darwin_revocation.py +297 -0
  222. hexcore-9.0.0/tests/test_darwin_schema_registration.py +431 -0
  223. hexcore-9.0.0/tests/test_darwin_storage_selection.py +573 -0
  224. hexcore-9.0.0/tests/test_darwin_tokens.py +502 -0
  225. hexcore-9.0.0/tests/test_darwin_two_factor.py +1161 -0
  226. hexcore-9.0.0/tests/test_darwin_value_objects.py +216 -0
  227. hexcore-9.0.0/tests/test_deprecations.py +581 -0
  228. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_documentation_examples.py +92 -35
  229. hexcore-9.0.0/tests/test_domain_base_contract.py +159 -0
  230. hexcore-9.0.0/tests/test_event_dispatch_mro.py +282 -0
  231. hexcore-9.0.0/tests/test_eventsourcing_aggregate.py +527 -0
  232. hexcore-9.0.0/tests/test_eventsourcing_beanie.py +303 -0
  233. hexcore-9.0.0/tests/test_eventsourcing_config.py +389 -0
  234. hexcore-9.0.0/tests/test_eventsourcing_ports.py +259 -0
  235. hexcore-9.0.0/tests/test_eventsourcing_projections.py +512 -0
  236. hexcore-9.0.0/tests/test_eventsourcing_redis.py +396 -0
  237. hexcore-9.0.0/tests/test_eventsourcing_relay.py +429 -0
  238. hexcore-9.0.0/tests/test_eventsourcing_repository.py +422 -0
  239. hexcore-9.0.0/tests/test_eventsourcing_snapshot_checkpoint.py +257 -0
  240. hexcore-9.0.0/tests/test_eventsourcing_sql_schema.py +284 -0
  241. hexcore-9.0.0/tests/test_eventsourcing_store_contract.py +473 -0
  242. hexcore-9.0.0/tests/test_eventsourcing_uow_integration.py +283 -0
  243. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_facades.py +9 -6
  244. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_infrastructure_query_path.py +4 -4
  245. hexcore-9.0.0/tests/test_optional_dependencies.py +346 -0
  246. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_packaging.py +91 -1
  247. hexcore-9.0.0/tests/test_sql_naming_convention.py +153 -0
  248. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_sql_session_layer.py +8 -8
  249. hexcore-9.0.0/tests/test_testing_kit.py +937 -0
  250. hexcore-9.0.0/tests/test_typing_gate.py +179 -0
  251. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_uow_session_regression.py +134 -4
  252. hexcore-7.0.0/PKG-INFO +0 -1156
  253. hexcore-7.0.0/README.md +0 -1112
  254. hexcore-7.0.0/hexcore/__init__.py +0 -38
  255. hexcore-7.0.0/hexcore/_deprecation.py +0 -134
  256. hexcore-7.0.0/hexcore/domain/auth/__init__.py +0 -13
  257. hexcore-7.0.0/hexcore/domain/cqrs/__init__.py +0 -104
  258. hexcore-7.0.0/hexcore/domain/cqrs/serializer.py +0 -46
  259. hexcore-7.0.0/hexcore/domain/events.py +0 -103
  260. hexcore-7.0.0/hexcore/infrastructure/api/__init__.py +0 -78
  261. hexcore-7.0.0/hexcore/infrastructure/cqrs/redis_bus.py +0 -151
  262. hexcore-7.0.0/hexcore/infrastructure/events/events_backends/memory.py +0 -36
  263. hexcore-7.0.0/hexcore/infrastructure/repositories/implementations.py +0 -227
  264. hexcore-7.0.0/hexcore/infrastructure/repositories/orms/sqlalchemy/__init__.py +0 -44
  265. hexcore-7.0.0/hexcore/infrastructure/uow/__init__.py +0 -218
  266. hexcore-7.0.0/hexcore/infrastructure/uow/decorators.py +0 -16
  267. hexcore-7.0.0/hexcore.egg-info/PKG-INFO +0 -1156
  268. hexcore-7.0.0/hexcore.egg-info/SOURCES.txt +0 -160
  269. hexcore-7.0.0/hexcore.egg-info/requires.txt +0 -41
  270. hexcore-7.0.0/pyproject.toml +0 -122
  271. hexcore-7.0.0/tests/test_deprecations.py +0 -306
  272. hexcore-7.0.0/tests/test_optional_dependencies.py +0 -57
  273. {hexcore-7.0.0 → hexcore-9.0.0}/LICENSE +0 -0
  274. {hexcore-7.0.0 → hexcore-9.0.0}/MANIFEST.in +0 -0
  275. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/__main__.py +0 -0
  276. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/__init__.py +0 -0
  277. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/cqrs/__init__.py +0 -0
  278. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/cqrs/adapters.py +0 -0
  279. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/cqrs/config.py +0 -0
  280. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/cqrs/factory.py +0 -0
  281. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/cqrs/pipeline.py +0 -0
  282. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/cqrs/registry.py +0 -0
  283. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/cqrs/scheduler.py +0 -0
  284. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/dtos/__init__.py +0 -0
  285. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/dtos/base.py +0 -0
  286. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/dtos/cursor.py +0 -0
  287. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/dtos/errors.py +0 -0
  288. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/dtos/query.py +0 -0
  289. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/use_cases/__init__.py +0 -0
  290. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/use_cases/base.py +0 -0
  291. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/application/use_cases/query.py +0 -0
  292. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/__init__.py +0 -0
  293. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/auth/value_objects.py +0 -0
  294. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/commands.py +0 -0
  295. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/context.py +0 -0
  296. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/cron.py +0 -0
  297. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/decorators.py +0 -0
  298. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/exceptions.py +0 -0
  299. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/queries.py +0 -0
  300. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/cqrs/task_queues.py +0 -0
  301. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/exceptions.py +0 -0
  302. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/domain/repositories.py +0 -0
  303. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/__init__.py +0 -0
  304. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/exception_handlers.py +0 -0
  305. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/lifespan.py +0 -0
  306. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/middlewares.py +0 -0
  307. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/rate_limit.py +0 -0
  308. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/routing.py +0 -0
  309. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/api/streaming.py +0 -0
  310. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cache/__init__.py +0 -0
  311. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cache/cache_backends/__init__.py +0 -0
  312. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cache/cache_backends/memory.py +0 -0
  313. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/__init__.py +0 -0
  314. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/cron_sql.py +0 -0
  315. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/middlewares.py +0 -0
  316. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/cqrs/pydantic_serializer.py +0 -0
  317. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/events/__init__.py +0 -0
  318. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/events/events_backends/__init__.py +0 -0
  319. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/__init__.py +0 -0
  320. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/repositories/orms/__init__.py +0 -0
  321. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/task_queues/__init__.py +0 -0
  322. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/uow/helpers.py +0 -0
  323. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/uow/scopes.py +0 -0
  324. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/workers/__init__.py +0 -0
  325. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/infrastructure/workers/runner.py +0 -0
  326. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/py.typed +0 -0
  327. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/testing/fakes.py +0 -0
  328. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/testing/fixtures.py +0 -0
  329. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore/testing/helpers.py +0 -0
  330. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore.egg-info/dependency_links.txt +0 -0
  331. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore.egg-info/entry_points.txt +0 -0
  332. {hexcore-7.0.0 → hexcore-9.0.0}/hexcore.egg-info/top_level.txt +0 -0
  333. {hexcore-7.0.0 → hexcore-9.0.0}/setup.cfg +0 -0
  334. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_api_app_and_lifespan.py +0 -0
  335. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_api_cqrs_providers.py +0 -0
  336. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_api_exception_handlers.py +0 -0
  337. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_api_health.py +0 -0
  338. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_api_middlewares_and_routing.py +0 -0
  339. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_api_rate_limit.py +0 -0
  340. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_api_streaming.py +0 -0
  341. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_basic.py +0 -0
  342. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_beanie_query_utils.py +0 -0
  343. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_celery_event_loop.py +0 -0
  344. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_config_cors_security.py +0 -0
  345. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_config_loading.py +0 -0
  346. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_consumer_optional_event_bus.py +0 -0
  347. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_cqrs.py +0 -0
  348. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_cqrs_factory.py +0 -0
  349. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_cqrs_middlewares.py +0 -0
  350. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_cron_sql.py +0 -0
  351. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_domain_service_query.py +0 -0
  352. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_dotted_resolution.py +0 -0
  353. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_handler_registry.py +0 -0
  354. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_lock_error_policy.py +0 -0
  355. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_postgres_bus.py +0 -0
  356. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_postgres_lock.py +0 -0
  357. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_query_cursor_and_endpoint.py +0 -0
  358. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_query_field_validation.py +0 -0
  359. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_rabbitmq_bus.py +0 -0
  360. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_redis_bus.py +0 -0
  361. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_redis_lock.py +0 -0
  362. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_repositories_utils.py +0 -0
  363. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_scheduler.py +0 -0
  364. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_scheduler_catchup.py +0 -0
  365. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_smart_routing.py +0 -0
  366. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_task_queues_adapters.py +0 -0
  367. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_testing_utilities.py +0 -0
  368. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_use_cases_query.py +0 -0
  369. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_worker_bus_integration.py +0 -0
  370. {hexcore-7.0.0 → hexcore-9.0.0}/tests/test_worker_runner.py +0 -0
hexcore-9.0.0/PKG-INFO ADDED
@@ -0,0 +1,340 @@
1
+ Metadata-Version: 2.4
2
+ Name: hexcore
3
+ Version: 9.0.0
4
+ Summary: Reusable core for Python projects with hexagonal architecture, DDD, CQRS and background tasks. Ships the abstractions and the infrastructure: SQL session layer, FastAPI factories, worker runner, dynamic cron and identity.
5
+ Author-email: "David Latosefki (Indroic)" <indroic@outlook.com>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: croniter>=2.0.0
11
+ Requires-Dist: pydantic>=2.11.7
12
+ Requires-Dist: typer>=0.17.3
13
+ Provides-Extra: api
14
+ Requires-Dist: fastapi>=0.116.1; extra == "api"
15
+ Provides-Extra: redis
16
+ Requires-Dist: redis>=6.4.0; extra == "redis"
17
+ Provides-Extra: mongo
18
+ Requires-Dist: beanie>=2.0.0; extra == "mongo"
19
+ Provides-Extra: sql
20
+ Requires-Dist: sqlalchemy>=2.0.43; extra == "sql"
21
+ Requires-Dist: alembic>=1.16.5; extra == "sql"
22
+ Requires-Dist: asyncpg>=0.30.0; extra == "sql"
23
+ Requires-Dist: aiosqlite>=0.21.0; extra == "sql"
24
+ Provides-Extra: rabbitmq
25
+ Requires-Dist: aio-pika>=9.4.0; extra == "rabbitmq"
26
+ Requires-Dist: pika>=1.3.2; extra == "rabbitmq"
27
+ Provides-Extra: procrastinate
28
+ Requires-Dist: procrastinate>=3.0.0; extra == "procrastinate"
29
+ Provides-Extra: celery
30
+ Requires-Dist: celery>=5.4.0; extra == "celery"
31
+ Provides-Extra: darwin
32
+ Requires-Dist: fastapi>=0.116.1; extra == "darwin"
33
+ Requires-Dist: joserfc>=1.0.0; extra == "darwin"
34
+ Requires-Dist: argon2-cffi>=23.1.0; extra == "darwin"
35
+ Provides-Extra: darwin-sqlalchemy
36
+ Requires-Dist: hexcore[darwin]; extra == "darwin-sqlalchemy"
37
+ Requires-Dist: sqlalchemy>=2.0.43; extra == "darwin-sqlalchemy"
38
+ Requires-Dist: alembic>=1.16.5; extra == "darwin-sqlalchemy"
39
+ Requires-Dist: asyncpg>=0.30.0; extra == "darwin-sqlalchemy"
40
+ Requires-Dist: aiosqlite>=0.21.0; extra == "darwin-sqlalchemy"
41
+ Provides-Extra: darwin-beanie
42
+ Requires-Dist: hexcore[darwin]; extra == "darwin-beanie"
43
+ Requires-Dist: beanie>=2.0.0; extra == "darwin-beanie"
44
+ Provides-Extra: darwin-magic-link
45
+ Requires-Dist: hexcore[darwin]; extra == "darwin-magic-link"
46
+ Provides-Extra: darwin-two-factor
47
+ Requires-Dist: hexcore[darwin]; extra == "darwin-two-factor"
48
+ Provides-Extra: darwin-oauth
49
+ Requires-Dist: hexcore[darwin]; extra == "darwin-oauth"
50
+ Requires-Dist: httpx>=0.27.0; extra == "darwin-oauth"
51
+ Provides-Extra: darwin-impersonate
52
+ Requires-Dist: hexcore[darwin]; extra == "darwin-impersonate"
53
+ Provides-Extra: darwin-passkey
54
+ Requires-Dist: hexcore[darwin]; extra == "darwin-passkey"
55
+ Requires-Dist: webauthn>=2.0.0; extra == "darwin-passkey"
56
+ Provides-Extra: darwin-organization
57
+ Requires-Dist: hexcore[darwin]; extra == "darwin-organization"
58
+ Provides-Extra: all
59
+ Requires-Dist: fastapi>=0.116.1; extra == "all"
60
+ Requires-Dist: redis>=6.4.0; extra == "all"
61
+ Requires-Dist: beanie>=2.0.0; extra == "all"
62
+ Requires-Dist: sqlalchemy>=2.0.43; extra == "all"
63
+ Requires-Dist: alembic>=1.16.5; extra == "all"
64
+ Requires-Dist: asyncpg>=0.30.0; extra == "all"
65
+ Requires-Dist: aiosqlite>=0.21.0; extra == "all"
66
+ Requires-Dist: aio-pika>=9.4.0; extra == "all"
67
+ Requires-Dist: pika>=1.3.2; extra == "all"
68
+ Requires-Dist: procrastinate>=3.0.0; extra == "all"
69
+ Requires-Dist: celery>=5.4.0; extra == "all"
70
+ Requires-Dist: joserfc>=1.0.0; extra == "all"
71
+ Requires-Dist: argon2-cffi>=23.1.0; extra == "all"
72
+ Requires-Dist: httpx>=0.27.0; extra == "all"
73
+ Requires-Dist: webauthn>=2.0.0; extra == "all"
74
+ Dynamic: license-file
75
+
76
+ # HexCore [![PyPI Downloads](https://static.pepy.tech/personalized-badge/hexcore?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/hexcore)
77
+
78
+ A reusable core for Python applications built on **hexagonal architecture**, **DDD**, **CQRS**
79
+ and **background tasks**. HexCore ships the abstractions (entities, repositories, unit of work,
80
+ buses) *and* the infrastructure every project otherwise rewrites: the SQL session layer, the
81
+ FastAPI factories, the worker runner, the dynamic cron, identity, and the testing utilities.
82
+
83
+ The design goal is that the happy path takes **zero configuration**: `create_app()` with no
84
+ arguments gives you a usable app, `init_engine()` with no arguments gives you a
85
+ production-correct engine.
86
+
87
+ > 🇪🇸 **¿Preferís español?** La documentación está completa en los dos idiomas:
88
+ > **[docs/es/](./docs/es/)**.
89
+
90
+ ```python
91
+ # main.py — a complete HexCore app
92
+ from hexcore.fastapi import build_lifespan, create_app, SqlEngineStep
93
+
94
+ app = create_app(
95
+ lifespan=build_lifespan(SqlEngineStep()),
96
+ routers=[users_router, tickets_router],
97
+ )
98
+ ```
99
+
100
+ ```python
101
+ # worker.py — the complete worker, with cron, mutual death and SIGTERM
102
+ import hexcore.cqrs as cqrs
103
+
104
+ await cqrs.run_procrastinate_worker(
105
+ procrastinate_app,
106
+ queues=["default", "reactive"],
107
+ scheduler=cqrs.DynamicScheduler(repo, enqueuer, lock_provider=lock),
108
+ on_startup=[lambda: cqrs.seed_cron_jobs(CRON_JOBS)],
109
+ )
110
+ ```
111
+
112
+ ---
113
+
114
+ ## 📚 Documentation
115
+
116
+ **→ [`docs/`](./docs/) — 🇬🇧 [English](./docs/en/) · 🇪🇸 [español](./docs/es/)**
117
+
118
+ | | English | Español |
119
+ | :-- | :-- | :-- |
120
+ | Installation and extras | [installation](./docs/en/installation.md) | [instalacion](./docs/es/instalacion.md) |
121
+ | Quickstart | [quickstart](./docs/en/quickstart.md) | [inicio-rapido](./docs/es/inicio-rapido.md) |
122
+ | Configuration | [configuration](./docs/en/configuration.md) | [configuracion](./docs/es/configuracion.md) |
123
+ | SQL layer | [sql](./docs/en/sql.md) | [sql](./docs/es/sql.md) |
124
+ | Repositories and entities | [repositories](./docs/en/repositories.md) | [repositorios](./docs/es/repositorios.md) |
125
+ | FastAPI utilities | [fastapi](./docs/en/fastapi.md) | [fastapi](./docs/es/fastapi.md) |
126
+ | CQRS architecture | [cqrs](./docs/en/cqrs.md) | [cqrs](./docs/es/cqrs.md) |
127
+ | Queues and workers | [queues-and-workers](./docs/en/queues-and-workers.md) | [colas-y-workers](./docs/es/colas-y-workers.md) |
128
+ | Scheduled tasks | [cron](./docs/en/cron.md) | [cron](./docs/es/cron.md) |
129
+ | **Event Sourcing** | [event-sourcing](./docs/en/event-sourcing.md) | [event-sourcing](./docs/es/event-sourcing.md) |
130
+ | Testing | [testing](./docs/en/testing.md) | [testing](./docs/es/testing.md) |
131
+ | CLI | [cli](./docs/en/cli.md) | [cli](./docs/es/cli.md) |
132
+ | **Darwin** (identity) | [darwin/](./docs/en/darwin/) | [darwin/](./docs/es/darwin/) |
133
+ | API reference | [reference](./docs/en/reference.md) | [referencia](./docs/es/referencia.md) |
134
+ | Versions and migration | [versions-and-migration](./docs/en/versions-and-migration.md) | [versiones-y-migracion](./docs/es/versiones-y-migracion.md) |
135
+ | Typing | [typing](./docs/en/typing.md) | [tipado](./docs/es/tipado.md) |
136
+
137
+ ---
138
+
139
+ ## Installation
140
+
141
+ ```sh
142
+ pip install hexcore
143
+ ```
144
+
145
+ Requires Python ≥ 3.12. HexCore pulls in no heavy dependencies: everything that is not the core
146
+ lives in **extras**, and the modules that need them only import them when you use them.
147
+
148
+ ```sh
149
+ pip install "hexcore[api,sql,procrastinate]"
150
+ pip install "hexcore[darwin-sqlalchemy]"
151
+ pip install "hexcore[all]"
152
+ ```
153
+
154
+ | Group | Extras |
155
+ | :-- | :-- |
156
+ | Core | `api`, `sql`, `mongo`, `redis`, `rabbitmq`, `procrastinate`, `celery` |
157
+ | Identity | `darwin`, `darwin-sqlalchemy`, `darwin-beanie`, `darwin-magic-link`, `darwin-two-factor`, `darwin-oauth`, `darwin-impersonate`, `darwin-passkey`, `darwin-organization` |
158
+ | Everything | `all` |
159
+
160
+ The full table, with what each one enables, is in
161
+ [installation](./docs/en/installation.md) · [instalación](./docs/es/instalacion.md).
162
+
163
+ > `import hexcore.cqrs` works with no extras at all: name resolution is lazy, so
164
+ > `hexcore.cqrs.SqlAlchemyCronJobRepository` only requires `[sql]` at the moment you ask for it.
165
+
166
+ ---
167
+
168
+ ## The four imports
169
+
170
+ There is one facade module per task. They re-export the public surface **without moving
171
+ anything**: the long paths keep resolving to the same object.
172
+
173
+ ```python
174
+ import hexcore.fastapi as hx # create_app, build_lifespan, providers, middlewares, health
175
+ import hexcore.cqrs as cqrs # Command, Query, handlers, decorators, buses, worker, cron
176
+ import hexcore.sql as sql # init_engine, session_scope, uow_scope, Base, query DTOs
177
+ import hexcore.darwin as darwin # IdentityConfig, configure_identity, build_identity_router
178
+ ```
179
+
180
+ The facades expose **only the canonical names**. The historical `I*` aliases were removed in
181
+ 7.0 — see [Removed API](#removed-api-and-its-replacement).
182
+
183
+ ---
184
+
185
+ ## What you get, at a glance
186
+
187
+ | You need | API | Extra |
188
+ | :-- | :-- | :-- |
189
+ | A wired-up FastAPI app | `hx.create_app()`, `hx.AppFeatures` | `api` |
190
+ | Orchestrated startup and shutdown | `hx.build_lifespan()` + steps | `api` |
191
+ | SQL engine and sessions | `sql.init_engine()`, `sql.PoolSettings` | `sql` |
192
+ | A session or UoW outside a request | `sql.session_scope()`, `sql.uow_scope()` | `sql` |
193
+ | Health checks that actually probe | `hx.register_health_routes()` | `api` |
194
+ | Rate limiting | `hx.rate_limit()` | `api` |
195
+ | SSE / WebSocket / connection caps | `hx.sse_stream()`, `hx.connection_slot()` | `api` |
196
+ | Commands, queries and events | `cqrs.Command`, `cqrs.Query`, `cqrs.HandlerRegistry` | — |
197
+ | Running work in the background | `cqrs.background_command`, `cqrs.background_task` | — |
198
+ | The worker entrypoint | `cqrs.run_cqrs_worker()`, `cqrs.run_procrastinate_worker()` | — |
199
+ | Cron you can edit without a restart | `cqrs.DynamicScheduler`, `cqrs.SqlAlchemyCronJobRepository` | `sql` |
200
+ | Distributed locks | `cqrs.RedisLockProvider`, `cqrs.PostgresLockProvider` | `redis` / `sql` |
201
+ | Identity and authentication | `darwin.configure_identity()`, `darwin.build_identity_router()` | `darwin` + storage |
202
+ | Testing all of the above | `hexcore.testing` | — |
203
+
204
+ ---
205
+
206
+ ## Darwin: the identity module
207
+
208
+ Registration, email verification, sign-in, sessions with rotating refresh, revocation, audited
209
+ impersonation, and a plugin system that adds second factor, OAuth, magic links, passkeys and
210
+ organizations without the core knowing about them.
211
+
212
+ ```python
213
+ from hexcore.darwin import (
214
+ IdentityConfig,
215
+ build_identity_router,
216
+ configure_identity,
217
+ identity_startup_steps,
218
+ )
219
+ from hexcore.fastapi import AppFeatures, SqlEngineStep, build_lifespan, create_app
220
+
221
+ configure_identity(IdentityConfig())
222
+
223
+ app = create_app(
224
+ features=AppFeatures(auth_context=True, csrf=True),
225
+ lifespan=build_lifespan(SqlEngineStep(), *identity_startup_steps()),
226
+ routers=[build_identity_router()],
227
+ )
228
+ ```
229
+
230
+ ⚠️ If you use SQL, the most important thing to read before deploying is the Alembic section:
231
+ [storage](./docs/en/darwin/storage.md) · [almacenamiento](./docs/es/darwin/almacenamiento.md).
232
+ A plugin missing from your `env.py` makes `alembic revision --autogenerate` emit
233
+ `op.drop_table` for its tables.
234
+
235
+ ---
236
+
237
+ ## Project templates (CLI)
238
+
239
+ ```sh
240
+ hexcore init my_project --template hexagonal
241
+ hexcore init my_project --template vertical-slice
242
+ ```
243
+
244
+ - `hexagonal` → `src/domain`, `src/application`, `src/infrastructure`.
245
+ - `vertical-slice` → `src/features`, `src/shared/{domain,application,infrastructure}`.
246
+
247
+ Both generate a root `config.py` and leave Alembic configured. See
248
+ [CLI](./docs/en/cli.md) · [CLI](./docs/es/cli.md).
249
+
250
+ ---
251
+
252
+ ## Versions and support
253
+
254
+ | Series | Status | What it means |
255
+ | :-- | :-- | :-- |
256
+ | **9.x** | ✅ **Active** | The only supported one. Receives features and fixes. Adds the event store and Event Sourcing, and leaves a single event bus port. |
257
+ | **8.x** | ⛔ **Deprecated** | Ships Darwin. Migrating to 9.x is mechanical: the two deprecated names still resolve and warn. |
258
+ | **7.x** | ⛔ **Deprecated** | Removes the pre-5.0 surface and fixes the CORS and rate-limiting defects. No Darwin: it shipped before the module landed on `master`. |
259
+ | **6.x** | ⛔ **Deprecated** | No longer receives fixes. Contains the CORS and rate-limiting security defects fixed in 7.0, and the pre-5.0 aliases still present. |
260
+ | **5.x** | ⛔ **Deprecated** | Same API surface as 6.x. |
261
+ | **4.x** | ⛔ **Deprecated** | **Partial** application: missing the Celery event-loop fix, the facades, and the aligned documentation. |
262
+ | **3.x** | ⛔ **Deprecated** | **Partial** application: has the P0/P1 fixes but none of the FastAPI factories. |
263
+ | **2.x** | ⛔ **Deprecated** | Contains silent bugs fixed in 5.x: the worker re-enqueued instead of executing, the cron skipped or duplicated runs, and a Redis outage switched off the entire cron. |
264
+ | **1.x** | ⛔ **Deprecated** | No support of any kind. |
265
+
266
+ **Everything before 9.0 is deprecated. Migrate to 9.x.** The detail of each series, the silent
267
+ 2.x bugs and the step-by-step guides are in
268
+ [versions and migration](./docs/en/versions-and-migration.md) ·
269
+ [versiones y migración](./docs/es/versiones-y-migracion.md).
270
+
271
+ ### Removed API and its replacement
272
+
273
+ The v1/v2 aliases were deprecated since 5.0 — two full majors of notice — and were removed in
274
+ 7.0. The replacement is mechanical: they are renames, not behavior changes.
275
+
276
+ | Removed in 7.0 (was v1/v2) | Use instead |
277
+ | :-- | :-- |
278
+ | `ICommandBus`, `IQueryBus`, `IEventBus` | `AbstractCommandBus`, `AbstractQueryBus`, `AbstractEventBus` |
279
+ | `ICommandHandler`, `IQueryHandler` | `AbstractCommandHandler`, `AbstractQueryHandler` |
280
+ | `IMiddleware` | `AbstractMiddleware` |
281
+ | `ISerializer` | `AbstractSerializer` |
282
+ | `IEventDispatcher` | `EventBus` |
283
+ | `EventBus.register()` / `.dispatch()` | `EventBus.subscribe()` / `.publish()` |
284
+ | `ServerConfig.event_dispatcher` | `ServerConfig.event_bus` |
285
+ | `SQLAlchemyCommonImplementationsRepo` | `SqlAlchemyRepository` |
286
+ | `BeanieODMCommonImplementationsRepo` | `BeanieRepository` |
287
+ | `NoSqlUnitOfWork` | `BeanieUnitOfWork` |
288
+ | `reset_sqlalchemy_engine()` | `dispose_engine()` |
289
+ | `MiddlewareConfig` | **Removed in 3.0.** It was dead code: never read. |
290
+
291
+ Passing `event_dispatcher=` to `ServerConfig` **fails with an error that says what to use**,
292
+ rather than being silently ignored: pydantic discards keyword arguments it does not know, and
293
+ keeping the default bus without noticing would surface much later as "my events never arrive".
294
+
295
+ If you are still on 6.x, run your tests with warnings visible to see what you have left to
296
+ migrate:
297
+
298
+ ```sh
299
+ python -m pytest -W "default::DeprecationWarning"
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Contributing
305
+
306
+ 1. **Code of conduct** — read the [Code of Conduct](CODE_OF_CONDUCT.md) before interacting.
307
+ 2. **Branches** — fork and create a branch (`feat/name`, `fix/name`, `docs/name`).
308
+ 3. **Tests** — every fix lands with at least one test that fails before and passes after:
309
+
310
+ ```sh
311
+ uv sync --extra all --group dev
312
+ uv run python -m pytest -q
313
+ ```
314
+
315
+ CI fails if any test is **skipped**: a skip means an extra is missing, and we would be
316
+ reporting green without having run half the suite.
317
+ 4. **Typecheck** — `uv run pyright hexcore`. The verdict comes from the ratchet, not the exit
318
+ code: see [typing](./docs/en/typing.md) · [tipado](./docs/es/tipado.md).
319
+ 5. **Style** — [PEP8](https://pep8.org/). Comment the *why*, not the *what*.
320
+ 6. **Commits** — [Commitizen](https://commitizen-tools.github.io/commitizen/): `feat:`, `fix:`,
321
+ `docs:`, `refactor:`, and `!` for breaking changes. The version bump and the CHANGELOG are
322
+ automatic on merge to `master`.
323
+ 7. **PRs** — describe the problem, the reproduction, the solution and **why that option**.
324
+
325
+ Full detail in [CONTRIBUTING.md](CONTRIBUTING.md).
326
+
327
+ ### Project skills
328
+
329
+ There is a set of skills for extending HexCore in VS Code and compatible environments:
330
+ [HexCore Skills repository](https://github.com/Indroic/hexcore-skill).
331
+
332
+ ---
333
+
334
+ ## References
335
+
336
+ - [docs/](./docs/) — the complete documentation, in English and Spanish.
337
+ - [docs/ARCHITECTURE_TYPING.md](./docs/ARCHITECTURE_TYPING.md) — type system and stubs.
338
+ - [CHANGELOG.md](./CHANGELOG.md) — change history.
339
+ - [CONTRIBUTING.md](./CONTRIBUTING.md) — collaboration guidelines.
340
+ - [SECURITY.md](./SECURITY.md) — security policy.
@@ -0,0 +1,265 @@
1
+ # HexCore [![PyPI Downloads](https://static.pepy.tech/personalized-badge/hexcore?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/hexcore)
2
+
3
+ A reusable core for Python applications built on **hexagonal architecture**, **DDD**, **CQRS**
4
+ and **background tasks**. HexCore ships the abstractions (entities, repositories, unit of work,
5
+ buses) *and* the infrastructure every project otherwise rewrites: the SQL session layer, the
6
+ FastAPI factories, the worker runner, the dynamic cron, identity, and the testing utilities.
7
+
8
+ The design goal is that the happy path takes **zero configuration**: `create_app()` with no
9
+ arguments gives you a usable app, `init_engine()` with no arguments gives you a
10
+ production-correct engine.
11
+
12
+ > 🇪🇸 **¿Preferís español?** La documentación está completa en los dos idiomas:
13
+ > **[docs/es/](./docs/es/)**.
14
+
15
+ ```python
16
+ # main.py — a complete HexCore app
17
+ from hexcore.fastapi import build_lifespan, create_app, SqlEngineStep
18
+
19
+ app = create_app(
20
+ lifespan=build_lifespan(SqlEngineStep()),
21
+ routers=[users_router, tickets_router],
22
+ )
23
+ ```
24
+
25
+ ```python
26
+ # worker.py — the complete worker, with cron, mutual death and SIGTERM
27
+ import hexcore.cqrs as cqrs
28
+
29
+ await cqrs.run_procrastinate_worker(
30
+ procrastinate_app,
31
+ queues=["default", "reactive"],
32
+ scheduler=cqrs.DynamicScheduler(repo, enqueuer, lock_provider=lock),
33
+ on_startup=[lambda: cqrs.seed_cron_jobs(CRON_JOBS)],
34
+ )
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 📚 Documentation
40
+
41
+ **→ [`docs/`](./docs/) — 🇬🇧 [English](./docs/en/) · 🇪🇸 [español](./docs/es/)**
42
+
43
+ | | English | Español |
44
+ | :-- | :-- | :-- |
45
+ | Installation and extras | [installation](./docs/en/installation.md) | [instalacion](./docs/es/instalacion.md) |
46
+ | Quickstart | [quickstart](./docs/en/quickstart.md) | [inicio-rapido](./docs/es/inicio-rapido.md) |
47
+ | Configuration | [configuration](./docs/en/configuration.md) | [configuracion](./docs/es/configuracion.md) |
48
+ | SQL layer | [sql](./docs/en/sql.md) | [sql](./docs/es/sql.md) |
49
+ | Repositories and entities | [repositories](./docs/en/repositories.md) | [repositorios](./docs/es/repositorios.md) |
50
+ | FastAPI utilities | [fastapi](./docs/en/fastapi.md) | [fastapi](./docs/es/fastapi.md) |
51
+ | CQRS architecture | [cqrs](./docs/en/cqrs.md) | [cqrs](./docs/es/cqrs.md) |
52
+ | Queues and workers | [queues-and-workers](./docs/en/queues-and-workers.md) | [colas-y-workers](./docs/es/colas-y-workers.md) |
53
+ | Scheduled tasks | [cron](./docs/en/cron.md) | [cron](./docs/es/cron.md) |
54
+ | **Event Sourcing** | [event-sourcing](./docs/en/event-sourcing.md) | [event-sourcing](./docs/es/event-sourcing.md) |
55
+ | Testing | [testing](./docs/en/testing.md) | [testing](./docs/es/testing.md) |
56
+ | CLI | [cli](./docs/en/cli.md) | [cli](./docs/es/cli.md) |
57
+ | **Darwin** (identity) | [darwin/](./docs/en/darwin/) | [darwin/](./docs/es/darwin/) |
58
+ | API reference | [reference](./docs/en/reference.md) | [referencia](./docs/es/referencia.md) |
59
+ | Versions and migration | [versions-and-migration](./docs/en/versions-and-migration.md) | [versiones-y-migracion](./docs/es/versiones-y-migracion.md) |
60
+ | Typing | [typing](./docs/en/typing.md) | [tipado](./docs/es/tipado.md) |
61
+
62
+ ---
63
+
64
+ ## Installation
65
+
66
+ ```sh
67
+ pip install hexcore
68
+ ```
69
+
70
+ Requires Python ≥ 3.12. HexCore pulls in no heavy dependencies: everything that is not the core
71
+ lives in **extras**, and the modules that need them only import them when you use them.
72
+
73
+ ```sh
74
+ pip install "hexcore[api,sql,procrastinate]"
75
+ pip install "hexcore[darwin-sqlalchemy]"
76
+ pip install "hexcore[all]"
77
+ ```
78
+
79
+ | Group | Extras |
80
+ | :-- | :-- |
81
+ | Core | `api`, `sql`, `mongo`, `redis`, `rabbitmq`, `procrastinate`, `celery` |
82
+ | Identity | `darwin`, `darwin-sqlalchemy`, `darwin-beanie`, `darwin-magic-link`, `darwin-two-factor`, `darwin-oauth`, `darwin-impersonate`, `darwin-passkey`, `darwin-organization` |
83
+ | Everything | `all` |
84
+
85
+ The full table, with what each one enables, is in
86
+ [installation](./docs/en/installation.md) · [instalación](./docs/es/instalacion.md).
87
+
88
+ > `import hexcore.cqrs` works with no extras at all: name resolution is lazy, so
89
+ > `hexcore.cqrs.SqlAlchemyCronJobRepository` only requires `[sql]` at the moment you ask for it.
90
+
91
+ ---
92
+
93
+ ## The four imports
94
+
95
+ There is one facade module per task. They re-export the public surface **without moving
96
+ anything**: the long paths keep resolving to the same object.
97
+
98
+ ```python
99
+ import hexcore.fastapi as hx # create_app, build_lifespan, providers, middlewares, health
100
+ import hexcore.cqrs as cqrs # Command, Query, handlers, decorators, buses, worker, cron
101
+ import hexcore.sql as sql # init_engine, session_scope, uow_scope, Base, query DTOs
102
+ import hexcore.darwin as darwin # IdentityConfig, configure_identity, build_identity_router
103
+ ```
104
+
105
+ The facades expose **only the canonical names**. The historical `I*` aliases were removed in
106
+ 7.0 — see [Removed API](#removed-api-and-its-replacement).
107
+
108
+ ---
109
+
110
+ ## What you get, at a glance
111
+
112
+ | You need | API | Extra |
113
+ | :-- | :-- | :-- |
114
+ | A wired-up FastAPI app | `hx.create_app()`, `hx.AppFeatures` | `api` |
115
+ | Orchestrated startup and shutdown | `hx.build_lifespan()` + steps | `api` |
116
+ | SQL engine and sessions | `sql.init_engine()`, `sql.PoolSettings` | `sql` |
117
+ | A session or UoW outside a request | `sql.session_scope()`, `sql.uow_scope()` | `sql` |
118
+ | Health checks that actually probe | `hx.register_health_routes()` | `api` |
119
+ | Rate limiting | `hx.rate_limit()` | `api` |
120
+ | SSE / WebSocket / connection caps | `hx.sse_stream()`, `hx.connection_slot()` | `api` |
121
+ | Commands, queries and events | `cqrs.Command`, `cqrs.Query`, `cqrs.HandlerRegistry` | — |
122
+ | Running work in the background | `cqrs.background_command`, `cqrs.background_task` | — |
123
+ | The worker entrypoint | `cqrs.run_cqrs_worker()`, `cqrs.run_procrastinate_worker()` | — |
124
+ | Cron you can edit without a restart | `cqrs.DynamicScheduler`, `cqrs.SqlAlchemyCronJobRepository` | `sql` |
125
+ | Distributed locks | `cqrs.RedisLockProvider`, `cqrs.PostgresLockProvider` | `redis` / `sql` |
126
+ | Identity and authentication | `darwin.configure_identity()`, `darwin.build_identity_router()` | `darwin` + storage |
127
+ | Testing all of the above | `hexcore.testing` | — |
128
+
129
+ ---
130
+
131
+ ## Darwin: the identity module
132
+
133
+ Registration, email verification, sign-in, sessions with rotating refresh, revocation, audited
134
+ impersonation, and a plugin system that adds second factor, OAuth, magic links, passkeys and
135
+ organizations without the core knowing about them.
136
+
137
+ ```python
138
+ from hexcore.darwin import (
139
+ IdentityConfig,
140
+ build_identity_router,
141
+ configure_identity,
142
+ identity_startup_steps,
143
+ )
144
+ from hexcore.fastapi import AppFeatures, SqlEngineStep, build_lifespan, create_app
145
+
146
+ configure_identity(IdentityConfig())
147
+
148
+ app = create_app(
149
+ features=AppFeatures(auth_context=True, csrf=True),
150
+ lifespan=build_lifespan(SqlEngineStep(), *identity_startup_steps()),
151
+ routers=[build_identity_router()],
152
+ )
153
+ ```
154
+
155
+ ⚠️ If you use SQL, the most important thing to read before deploying is the Alembic section:
156
+ [storage](./docs/en/darwin/storage.md) · [almacenamiento](./docs/es/darwin/almacenamiento.md).
157
+ A plugin missing from your `env.py` makes `alembic revision --autogenerate` emit
158
+ `op.drop_table` for its tables.
159
+
160
+ ---
161
+
162
+ ## Project templates (CLI)
163
+
164
+ ```sh
165
+ hexcore init my_project --template hexagonal
166
+ hexcore init my_project --template vertical-slice
167
+ ```
168
+
169
+ - `hexagonal` → `src/domain`, `src/application`, `src/infrastructure`.
170
+ - `vertical-slice` → `src/features`, `src/shared/{domain,application,infrastructure}`.
171
+
172
+ Both generate a root `config.py` and leave Alembic configured. See
173
+ [CLI](./docs/en/cli.md) · [CLI](./docs/es/cli.md).
174
+
175
+ ---
176
+
177
+ ## Versions and support
178
+
179
+ | Series | Status | What it means |
180
+ | :-- | :-- | :-- |
181
+ | **9.x** | ✅ **Active** | The only supported one. Receives features and fixes. Adds the event store and Event Sourcing, and leaves a single event bus port. |
182
+ | **8.x** | ⛔ **Deprecated** | Ships Darwin. Migrating to 9.x is mechanical: the two deprecated names still resolve and warn. |
183
+ | **7.x** | ⛔ **Deprecated** | Removes the pre-5.0 surface and fixes the CORS and rate-limiting defects. No Darwin: it shipped before the module landed on `master`. |
184
+ | **6.x** | ⛔ **Deprecated** | No longer receives fixes. Contains the CORS and rate-limiting security defects fixed in 7.0, and the pre-5.0 aliases still present. |
185
+ | **5.x** | ⛔ **Deprecated** | Same API surface as 6.x. |
186
+ | **4.x** | ⛔ **Deprecated** | **Partial** application: missing the Celery event-loop fix, the facades, and the aligned documentation. |
187
+ | **3.x** | ⛔ **Deprecated** | **Partial** application: has the P0/P1 fixes but none of the FastAPI factories. |
188
+ | **2.x** | ⛔ **Deprecated** | Contains silent bugs fixed in 5.x: the worker re-enqueued instead of executing, the cron skipped or duplicated runs, and a Redis outage switched off the entire cron. |
189
+ | **1.x** | ⛔ **Deprecated** | No support of any kind. |
190
+
191
+ **Everything before 9.0 is deprecated. Migrate to 9.x.** The detail of each series, the silent
192
+ 2.x bugs and the step-by-step guides are in
193
+ [versions and migration](./docs/en/versions-and-migration.md) ·
194
+ [versiones y migración](./docs/es/versiones-y-migracion.md).
195
+
196
+ ### Removed API and its replacement
197
+
198
+ The v1/v2 aliases were deprecated since 5.0 — two full majors of notice — and were removed in
199
+ 7.0. The replacement is mechanical: they are renames, not behavior changes.
200
+
201
+ | Removed in 7.0 (was v1/v2) | Use instead |
202
+ | :-- | :-- |
203
+ | `ICommandBus`, `IQueryBus`, `IEventBus` | `AbstractCommandBus`, `AbstractQueryBus`, `AbstractEventBus` |
204
+ | `ICommandHandler`, `IQueryHandler` | `AbstractCommandHandler`, `AbstractQueryHandler` |
205
+ | `IMiddleware` | `AbstractMiddleware` |
206
+ | `ISerializer` | `AbstractSerializer` |
207
+ | `IEventDispatcher` | `EventBus` |
208
+ | `EventBus.register()` / `.dispatch()` | `EventBus.subscribe()` / `.publish()` |
209
+ | `ServerConfig.event_dispatcher` | `ServerConfig.event_bus` |
210
+ | `SQLAlchemyCommonImplementationsRepo` | `SqlAlchemyRepository` |
211
+ | `BeanieODMCommonImplementationsRepo` | `BeanieRepository` |
212
+ | `NoSqlUnitOfWork` | `BeanieUnitOfWork` |
213
+ | `reset_sqlalchemy_engine()` | `dispose_engine()` |
214
+ | `MiddlewareConfig` | **Removed in 3.0.** It was dead code: never read. |
215
+
216
+ Passing `event_dispatcher=` to `ServerConfig` **fails with an error that says what to use**,
217
+ rather than being silently ignored: pydantic discards keyword arguments it does not know, and
218
+ keeping the default bus without noticing would surface much later as "my events never arrive".
219
+
220
+ If you are still on 6.x, run your tests with warnings visible to see what you have left to
221
+ migrate:
222
+
223
+ ```sh
224
+ python -m pytest -W "default::DeprecationWarning"
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Contributing
230
+
231
+ 1. **Code of conduct** — read the [Code of Conduct](CODE_OF_CONDUCT.md) before interacting.
232
+ 2. **Branches** — fork and create a branch (`feat/name`, `fix/name`, `docs/name`).
233
+ 3. **Tests** — every fix lands with at least one test that fails before and passes after:
234
+
235
+ ```sh
236
+ uv sync --extra all --group dev
237
+ uv run python -m pytest -q
238
+ ```
239
+
240
+ CI fails if any test is **skipped**: a skip means an extra is missing, and we would be
241
+ reporting green without having run half the suite.
242
+ 4. **Typecheck** — `uv run pyright hexcore`. The verdict comes from the ratchet, not the exit
243
+ code: see [typing](./docs/en/typing.md) · [tipado](./docs/es/tipado.md).
244
+ 5. **Style** — [PEP8](https://pep8.org/). Comment the *why*, not the *what*.
245
+ 6. **Commits** — [Commitizen](https://commitizen-tools.github.io/commitizen/): `feat:`, `fix:`,
246
+ `docs:`, `refactor:`, and `!` for breaking changes. The version bump and the CHANGELOG are
247
+ automatic on merge to `master`.
248
+ 7. **PRs** — describe the problem, the reproduction, the solution and **why that option**.
249
+
250
+ Full detail in [CONTRIBUTING.md](CONTRIBUTING.md).
251
+
252
+ ### Project skills
253
+
254
+ There is a set of skills for extending HexCore in VS Code and compatible environments:
255
+ [HexCore Skills repository](https://github.com/Indroic/hexcore-skill).
256
+
257
+ ---
258
+
259
+ ## References
260
+
261
+ - [docs/](./docs/) — the complete documentation, in English and Spanish.
262
+ - [docs/ARCHITECTURE_TYPING.md](./docs/ARCHITECTURE_TYPING.md) — type system and stubs.
263
+ - [CHANGELOG.md](./CHANGELOG.md) — change history.
264
+ - [CONTRIBUTING.md](./CONTRIBUTING.md) — collaboration guidelines.
265
+ - [SECURITY.md](./SECURITY.md) — security policy.