quadkit-testing 0.0.41__tar.gz → 0.0.43__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 (192) hide show
  1. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/PKG-INFO +4 -4
  2. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/README.md +3 -3
  3. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/pyproject.toml +4 -1
  4. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/redis.py +1 -1
  5. quadkit_testing-0.0.43/src/quadkit/testing/fixtures/db.py +279 -0
  6. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/generators_contract.py +33 -0
  7. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/probes.py +15 -11
  8. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/cqrs.py +1 -1
  9. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/event_bus.py +21 -7
  10. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/outbox.py +1 -1
  11. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/repository.py +3 -3
  12. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/uow.py +1 -1
  13. quadkit_testing-0.0.43/tests/unit/test_db_transaction_fixture.py +211 -0
  14. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_subpackage_exports.py +31 -0
  15. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/.gitignore +0 -0
  16. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/LICENSE +0 -0
  17. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/NOTICE +0 -0
  18. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/py.typed +0 -0
  19. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/README.md +0 -0
  20. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/__init__.py +0 -0
  21. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/_lazy_exports.py +0 -0
  22. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/ai/__init__.py +0 -0
  23. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/ai/bed.py +0 -0
  24. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/ai/client.py +0 -0
  25. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/ai/data.py +0 -0
  26. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/db/__init__.py +0 -0
  27. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/db/bed.py +0 -0
  28. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/db/client.py +0 -0
  29. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/web/__init__.py +0 -0
  30. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/web/bed.py +0 -0
  31. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/web/client.py +0 -0
  32. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/web/py.typed +0 -0
  33. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clock.py +0 -0
  34. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/__init__.py +0 -0
  35. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/audit.py +0 -0
  36. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/blob_store.py +0 -0
  37. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/cache.py +0 -0
  38. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/database.py +0 -0
  39. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/distributed_lock.py +0 -0
  40. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/event_bus.py +0 -0
  41. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/flags.py +0 -0
  42. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/middleware.py +0 -0
  43. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/notification.py +0 -0
  44. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/queue_backend.py +0 -0
  45. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/repository.py +0 -0
  46. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/search.py +0 -0
  47. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/secrets.py +0 -0
  48. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/task_queue.py +0 -0
  49. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/vector_store.py +0 -0
  50. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/webhook.py +0 -0
  51. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/config.py +0 -0
  52. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/constants.py +0 -0
  53. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/decorators.py +0 -0
  54. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/di/__init__.py +0 -0
  55. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/events.py +0 -0
  56. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/exceptions.py +0 -0
  57. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/__init__.py +0 -0
  58. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/audit.py +0 -0
  59. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/buses.py +0 -0
  60. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/cache.py +0 -0
  61. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/clock.py +0 -0
  62. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/config.py +0 -0
  63. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/events.py +0 -0
  64. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/governance.py +0 -0
  65. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/lifecycle.py +0 -0
  66. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/logging.py +0 -0
  67. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/monitoring.py +0 -0
  68. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/tracing.py +0 -0
  69. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/__init__.py +0 -0
  70. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/bed.py +0 -0
  71. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/container.py +0 -0
  72. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/containers.py +0 -0
  73. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/core.py +0 -0
  74. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/py.typed +0 -0
  75. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/web.py +0 -0
  76. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/generators.py +0 -0
  77. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/__init__.py +0 -0
  78. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/container.py +0 -0
  79. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/decorators.py +0 -0
  80. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/overrides.py +0 -0
  81. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/testbed.py +0 -0
  82. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/hooks.py +0 -0
  83. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/__init__.py +0 -0
  84. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/cleanup.py +0 -0
  85. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/config.py +0 -0
  86. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/fixtures.py +0 -0
  87. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/markers.py +0 -0
  88. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/__init__.py +0 -0
  89. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/admin_helpers.py +0 -0
  90. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/assertions.py +0 -0
  91. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/async_helper.py +0 -0
  92. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/factory.py +0 -0
  93. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/smoke.py +0 -0
  94. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/snapshots.py +0 -0
  95. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/stubs.py +0 -0
  96. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/__init__.py +0 -0
  97. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/audit.py +0 -0
  98. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/blob_store.py +0 -0
  99. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/cache.py +0 -0
  100. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/config/__init__.py +0 -0
  101. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/config/models.py +0 -0
  102. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/constants.py +0 -0
  103. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/di/__init__.py +0 -0
  104. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/di/provider.py +0 -0
  105. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/exceptions.py +0 -0
  106. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/lock.py +0 -0
  107. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/notification.py +0 -0
  108. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/queue.py +0 -0
  109. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/search.py +0 -0
  110. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/mocks/__init__.py +0 -0
  111. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/mocks/base.py +0 -0
  112. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/mocks/test_provider.py +0 -0
  113. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/module.py +0 -0
  114. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/plugins/__init__.py +0 -0
  115. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/plugins/pytest/__init__.py +0 -0
  116. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/plugins/pytest/plugin.py +0 -0
  117. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/protocols.py +0 -0
  118. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/py.typed +0 -0
  119. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/__init__.py +0 -0
  120. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/assertions.py +0 -0
  121. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/environment.py +0 -0
  122. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/fakes.py +0 -0
  123. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/fixtures.py +0 -0
  124. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/types.py +0 -0
  125. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/websocket/__init__.py +0 -0
  126. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/websocket/client.py +0 -0
  127. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/workflow/__init__.py +0 -0
  128. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/workflow/harness.py +0 -0
  129. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/__snapshots__/test_snapshot_function.json +0 -0
  130. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/conftest.py +0 -0
  131. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/integration/test_web_client.py +0 -0
  132. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/test_package_structure_p1.py +0 -0
  133. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/__snapshots__/test_snapshot_function.json +0 -0
  134. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/_integration_helpers.py +0 -0
  135. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/conftest.py +0 -0
  136. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_ai_client_budget.py +0 -0
  137. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_ai_clients.py +0 -0
  138. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_app_testbed.py +0 -0
  139. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_app_testbed_from_factory_overrides.py +0 -0
  140. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_assertion_helpers.py +0 -0
  141. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_async_helper.py +0 -0
  142. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_container.py +0 -0
  143. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_container_bind.py +0 -0
  144. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_container_factory_auto_registration.py +0 -0
  145. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_container_try_resolve.py +0 -0
  146. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_db_clients.py +0 -0
  147. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_environment_lifecycle.py +0 -0
  148. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_exceptions.py +0 -0
  149. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_factory.py +0 -0
  150. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fake_audit.py +0 -0
  151. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fake_event_bus_ordering.py +0 -0
  152. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fake_tracer.py +0 -0
  153. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fakes.py +0 -0
  154. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fakes_cluster.py +0 -0
  155. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fakes_lifecycle.py +0 -0
  156. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_generators_util.py +0 -0
  157. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_harness_testkit.py +0 -0
  158. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_integration_cleanup.py +0 -0
  159. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_integration_cluster.py +0 -0
  160. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_integration_fixtures.py +0 -0
  161. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_integration_probes.py +0 -0
  162. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_lib_admin_client.py +0 -0
  163. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_lib_async_helpers.py +0 -0
  164. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_lib_helpers.py +0 -0
  165. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_backends.py +0 -0
  166. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_cqrs.py +0 -0
  167. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_event_bus.py +0 -0
  168. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_lock.py +0 -0
  169. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_outbox.py +0 -0
  170. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_repository.py +0 -0
  171. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_mocks.py +0 -0
  172. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_mocks_cluster.py +0 -0
  173. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_override_context_manager_revert.py +0 -0
  174. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_plugin.py +0 -0
  175. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_public_exports.py +0 -0
  176. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_pytest_plugin_fixtures.py +0 -0
  177. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_service_probe_connectivity.py +0 -0
  178. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_small_modules.py +0 -0
  179. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_smoke.py +0 -0
  180. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_snapshot_asserter_create_compare.py +0 -0
  181. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_snapshots.py +0 -0
  182. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_stubs.py +0 -0
  183. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_test_environment.py +0 -0
  184. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_test_environment_facade.py +0 -0
  185. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_test_environment_overrides.py +0 -0
  186. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_testing_constants.py +0 -0
  187. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_testing_module.py +0 -0
  188. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_testing_utils.py +0 -0
  189. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_testkit_surface.py +0 -0
  190. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_utilities.py +0 -0
  191. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_web_clients.py +0 -0
  192. {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_workflow_websocket_plugins.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: quadkit-testing
3
- Version: 0.0.41
3
+ Version: 0.0.43
4
4
  Summary: Centralized testing infrastructure for Quadkit Framework - Fixtures, factories, and utilities
5
5
  Project-URL: Homepage, https://dbtinoy-.github.io/quadkit/
6
6
  Project-URL: Repository, https://github.com/dbtinoy-/quadkit
@@ -234,10 +234,10 @@ vulnerabilities privately per [SECURITY.md](https://github.com/dbtinoy-/quadkit/
234
234
 
235
235
  ## Stability
236
236
 
237
- Version `0.0.3` in the `0.x` series, released in lockstep with the
237
+ Version `0.0.43` in the `0.x` series, released in lockstep with the
238
238
  other four distributions; APIs may change between minor versions until
239
- 1.0 — pin an exact version (`quadkit-testing==0.0.3`) or a tight range
240
- (`>=0.0.3,<0.1.0`). Full policy:
239
+ 1.0 — pin an exact version (`quadkit-testing==0.0.43`) or a tight range
240
+ (`>=0.0.43,<0.1.0`). Full policy:
241
241
  [stability and compatibility](https://dbtinoy-.github.io/quadkit/reference/stability/).
242
242
 
243
243
  ## Links
@@ -178,10 +178,10 @@ vulnerabilities privately per [SECURITY.md](https://github.com/dbtinoy-/quadkit/
178
178
 
179
179
  ## Stability
180
180
 
181
- Version `0.0.3` in the `0.x` series, released in lockstep with the
181
+ Version `0.0.43` in the `0.x` series, released in lockstep with the
182
182
  other four distributions; APIs may change between minor versions until
183
- 1.0 — pin an exact version (`quadkit-testing==0.0.3`) or a tight range
184
- (`>=0.0.3,<0.1.0`). Full policy:
183
+ 1.0 — pin an exact version (`quadkit-testing==0.0.43`) or a tight range
184
+ (`>=0.0.43,<0.1.0`). Full policy:
185
185
  [stability and compatibility](https://dbtinoy-.github.io/quadkit/reference/stability/).
186
186
 
187
187
  ## Links
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "quadkit-testing"
9
- version = "0.0.41"
9
+ version = "0.0.43"
10
10
  description = "Centralized testing infrastructure for Quadkit Framework - Fixtures, factories, and utilities"
11
11
  readme = "README.md"
12
12
  requires-python = ">=3.11"
@@ -164,6 +164,9 @@ workspace = true
164
164
  [tool.uv.sources.quadkit-contracts]
165
165
  workspace = true
166
166
 
167
+ [tool.uv.sources.quadkit-sql]
168
+ workspace = true
169
+
167
170
  [tool.pytest.ini_options]
168
171
  asyncio_mode = "auto"
169
172
  addopts = ["--cov=quadkit.testing", "--cov-report=html", "--cov-report=term", "--cov-fail-under=66"]
@@ -11,7 +11,7 @@ __all__ = ["FakeRedisClient"]
11
11
  class FakeRedisClient:
12
12
  """In-memory async client compatible with the ``redis.asyncio`` surface used by tests.
13
13
 
14
- Supports the subset of Redis commands exercised by the optional provider tests:
14
+ Supports the subset of Redis commands exercised by quadkit-cache tests:
15
15
  ``ping``, ``set`` (with ``ex``/``px``/``nx``/``xx``), ``get``, ``delete``,
16
16
  ``exists``, ``expire``, ``ttl``, ``flushdb``, and ``close``. All data is
17
17
  kept in process, so tests never touch the network or a pre-started
@@ -0,0 +1,279 @@
1
+ """Database-specific test fixtures"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import AsyncGenerator
6
+ from typing import Any
7
+ from unittest.mock import AsyncMock, Mock
8
+
9
+ import pytest
10
+
11
+ pytest_asyncio: Any | None = None
12
+ try:
13
+ import pytest_asyncio
14
+ except ImportError:
15
+ pytest_asyncio = None
16
+
17
+ from collections.abc import Callable
18
+ from typing import Any as _Any
19
+
20
+ # Explicitly type the chosen fixture decorator so mypy treats decorated functions as typed
21
+ fixture_decorator: Callable[..., _Any] = (
22
+ pytest.fixture if pytest_asyncio is None else pytest_asyncio.fixture
23
+ )
24
+
25
+ try:
26
+ from quadkit.sql.abstractions.connection import ( # type: ignore[attr-defined]
27
+ ConnectionPool,
28
+ DatabaseConnection,
29
+ )
30
+ except ImportError:
31
+ # Fallback if quadkit-sql is not available
32
+ ConnectionPool: Any = Any # type: ignore[no-redef]
33
+ DatabaseConnection: Any = Any # type: ignore[no-redef]
34
+ from quadkit.testing.clients.db import (
35
+ DatabaseTestBed,
36
+ DatabaseTestClient,
37
+ )
38
+
39
+
40
+ @fixture_decorator
41
+ async def db_test_bed() -> AsyncGenerator[DatabaseTestBed, None]:
42
+ """Fixture for DatabaseTestBed with automatic cleanup"""
43
+ test_bed = DatabaseTestBed()
44
+ async with test_bed as tb:
45
+ yield tb
46
+
47
+
48
+ @fixture_decorator
49
+ async def test_database_client() -> AsyncGenerator[DatabaseTestClient, None]:
50
+ """Fixture for DatabaseTestClient"""
51
+ client = DatabaseTestClient()
52
+ async with client as c:
53
+ yield c
54
+
55
+
56
+ @pytest.fixture
57
+ def mock_connection() -> DatabaseConnection:
58
+ """Fixture for mock database connection"""
59
+ mock_conn = Mock(spec=DatabaseConnection)
60
+
61
+ # Mock async methods
62
+ mock_conn.execute = AsyncMock()
63
+ mock_conn.execute_many = AsyncMock()
64
+ mock_conn.fetch_one = AsyncMock()
65
+ mock_conn.fetch_all = AsyncMock()
66
+ mock_conn.close = AsyncMock()
67
+
68
+ # Additional methods expected by tests
69
+ mock_conn.fetchone = AsyncMock()
70
+ mock_conn.fetchall = AsyncMock()
71
+
72
+ # Mock transaction context manager
73
+ mock_transaction = AsyncMock()
74
+ mock_transaction.__aenter__ = AsyncMock(return_value=mock_conn)
75
+ mock_transaction.__aexit__ = AsyncMock(return_value=None)
76
+ mock_conn.transaction = Mock(return_value=mock_transaction)
77
+
78
+ return mock_conn
79
+
80
+
81
+ @pytest.fixture
82
+ def mock_connection_pool() -> ConnectionPool:
83
+ """Fixture for mock connection pool"""
84
+ mock_pool = Mock(spec=ConnectionPool)
85
+
86
+ # Mock async methods
87
+ mock_pool.get_connection = AsyncMock()
88
+ mock_pool.close = AsyncMock()
89
+ mock_pool.health_check = Mock(return_value={"status": "healthy"})
90
+ mock_pool.get_stats = Mock(return_value={"connections": 5})
91
+
92
+ # Additional methods expected by tests
93
+ mock_pool.acquire = AsyncMock()
94
+ mock_pool.release = AsyncMock()
95
+
96
+ return mock_pool
97
+
98
+
99
+ @fixture_decorator
100
+ async def seeded_database(
101
+ db_test_bed: DatabaseTestBed,
102
+ sample_user_data: list[dict[str, Any]],
103
+ sample_order_data: list[dict[str, Any]],
104
+ sample_product_data: list[dict[str, Any]],
105
+ ) -> DatabaseTestBed:
106
+ """Fixture for database with sample data"""
107
+ # Create users table
108
+ await db_test_bed.create_test_table(
109
+ "users",
110
+ "id INTEGER PRIMARY KEY, name TEXT, email TEXT, role TEXT",
111
+ )
112
+
113
+ # Create orders table
114
+ await db_test_bed.create_test_table(
115
+ "orders",
116
+ "id INTEGER PRIMARY KEY, user_id INTEGER, total REAL, status TEXT, items TEXT",
117
+ )
118
+
119
+ # Create products table
120
+ await db_test_bed.create_test_table(
121
+ "products",
122
+ "id INTEGER PRIMARY KEY, name TEXT, price REAL, category TEXT",
123
+ )
124
+
125
+ # Seed sample data
126
+ await db_test_bed.seed_test_data("users", sample_user_data)
127
+ await db_test_bed.seed_test_data("orders", sample_order_data)
128
+ await db_test_bed.seed_test_data("products", sample_product_data)
129
+
130
+ return db_test_bed
131
+
132
+
133
+ @fixture_decorator
134
+ async def clean_database(db_test_bed: DatabaseTestBed) -> DatabaseTestBed:
135
+ """Fixture for clean database with tables but no data"""
136
+ # Create users table
137
+ await db_test_bed.create_test_table(
138
+ "users",
139
+ "id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT",
140
+ )
141
+
142
+ # Create orders table
143
+ await db_test_bed.create_test_table(
144
+ "orders",
145
+ "id INTEGER PRIMARY KEY, user_id INTEGER, total REAL, status TEXT",
146
+ )
147
+
148
+ return db_test_bed
149
+
150
+
151
+ @pytest.fixture
152
+ def sample_user_data() -> list[dict[str, Any]]:
153
+ """Sample user data for testing"""
154
+ return [
155
+ {
156
+ "id": 1,
157
+ "name": "Alice Johnson",
158
+ "email": "alice@example.com",
159
+ "role": "user",
160
+ },
161
+ {"id": 2, "name": "Bob Smith", "email": "bob@example.com", "role": "admin"},
162
+ {
163
+ "id": 3,
164
+ "name": "Charlie Brown",
165
+ "email": "charlie@example.com",
166
+ "role": "user",
167
+ },
168
+ ]
169
+
170
+
171
+ @pytest.fixture
172
+ def sample_order_data() -> list[dict[str, Any]]:
173
+ """Sample order data for testing"""
174
+ return [
175
+ {"id": 1, "user_id": 1, "total": 99.99, "status": "completed", "items": 3},
176
+ {"id": 2, "user_id": 2, "total": 149.50, "status": "pending", "items": 5},
177
+ {"id": 3, "user_id": 1, "total": 75.25, "status": "shipped", "items": 2},
178
+ ]
179
+
180
+
181
+ @pytest.fixture
182
+ def sample_product_data() -> list[dict[str, Any]]:
183
+ """Sample product data for testing"""
184
+ return [
185
+ {"id": 1, "name": "Widget A", "price": 29.99, "category": "electronics"},
186
+ {"id": 2, "name": "Widget B", "price": 49.99, "category": "tools"},
187
+ {"id": 3, "name": "Widget C", "price": 19.99, "category": "accessories"},
188
+ ]
189
+
190
+
191
+ @pytest.fixture
192
+ def database_provider() -> Any:
193
+ """Placeholder fixture for a real DatabaseProviderProtocol instance.
194
+
195
+ Returns ``None`` by default so that ``db_transaction`` skips gracefully
196
+ in test suites that do not configure a live database.
197
+
198
+ Override this in your ``conftest.py`` to connect ``db_transaction`` to
199
+ the real database provider resolved from the application container::
200
+
201
+ from quadkit.contracts.data import DatabaseProviderProtocol
202
+
203
+ @pytest.fixture
204
+ async def database_provider(container: Container):
205
+ return await container.resolve(DatabaseProviderProtocol)
206
+
207
+ Where ``container`` is whatever fixture you use to provide the booted DI
208
+ container for your integration tests.
209
+ """
210
+ return None
211
+
212
+
213
+ @fixture_decorator
214
+ async def db_transaction(
215
+ database_provider: Any,
216
+ ) -> AsyncGenerator[Any, None]:
217
+ """Wrap an integration test in a database transaction that always rolls back.
218
+
219
+ Opens a scoped database context, begins a transaction, and yields the
220
+ active :class:`~quadkit.contracts.data.ConnectionProtocol` so that the
221
+ test can run queries. The transaction is *always* rolled back during
222
+ teardown regardless of test outcome, keeping the database state clean and
223
+ making tests fully order-independent.
224
+
225
+ Requires the ``database_provider`` fixture to be overridden in the test
226
+ suite's ``conftest.py`` (see :func:`database_provider` for instructions).
227
+ When ``database_provider`` returns ``None`` (the default), the test is
228
+ skipped with an informative message.
229
+
230
+ Example::
231
+
232
+ # conftest.py
233
+ from quadkit.contracts.data import DatabaseProviderProtocol
234
+
235
+ @pytest.fixture
236
+ async def database_provider(container):
237
+ return await container.resolve(DatabaseProviderProtocol)
238
+
239
+ # test_users.py
240
+ @pytest.mark.asyncio
241
+ async def test_create_user(db_transaction) -> None:
242
+ await db_transaction.execute(
243
+ "INSERT INTO users(name, email) VALUES($1, $2)",
244
+ "Alice", "alice@example.com",
245
+ )
246
+ row = await db_transaction.fetch_one(
247
+ "SELECT name FROM users WHERE email = $1", "alice@example.com"
248
+ )
249
+ assert row["name"] == "Alice"
250
+ # No teardown needed — the transaction is automatically rolled back.
251
+ """
252
+ if database_provider is None:
253
+ pytest.skip(
254
+ "db_transaction requires a 'database_provider' fixture. "
255
+ "Override it in conftest.py with a real DatabaseProviderProtocol instance."
256
+ )
257
+
258
+ async with database_provider.scoped_context():
259
+ conn = await database_provider.get_scoped_connection()
260
+ await conn.execute("BEGIN")
261
+ try:
262
+ yield conn
263
+ finally:
264
+ await conn.execute("ROLLBACK")
265
+
266
+
267
+ __all__ = [
268
+ "clean_database",
269
+ "database_provider",
270
+ "db_test_bed",
271
+ "db_transaction",
272
+ "mock_connection",
273
+ "mock_connection_pool",
274
+ "sample_order_data",
275
+ "sample_product_data",
276
+ "sample_user_data",
277
+ "seeded_database",
278
+ "test_database_client",
279
+ ]
@@ -8,6 +8,30 @@ from pathlib import Path
8
8
  from typing import Any
9
9
 
10
10
 
11
+ def _assert_marker_convention(py_path: Path, text: str) -> None:
12
+ """Enforce the generated-stub marker convention on one rendered ``.py``.
13
+
14
+ Generated stubs pair ``# @INTENT: <goal>`` directly above ``# @TODO:
15
+ <action>`` and never ship a bare ``# TODO:`` (the ``@`` prefix keeps both
16
+ greppable). See ``docs/09-27-2026/GENERATED_CODE_MARKERS.md``.
17
+ """
18
+ lines = text.splitlines()
19
+ for i, line in enumerate(lines):
20
+ stripped = line.strip()
21
+ if stripped.startswith("# TODO"):
22
+ raise AssertionError(
23
+ f"{py_path}: bare '# TODO' in generated code must be '# @TODO' "
24
+ f"-> {line!r}"
25
+ )
26
+ if stripped.startswith("# @TODO:"):
27
+ prev = lines[i - 1].strip() if i > 0 else ""
28
+ if not prev.startswith("# @INTENT:"):
29
+ raise AssertionError(
30
+ f"{py_path}: '# @TODO' at line {i + 1} is not preceded by "
31
+ f"a '# @INTENT:' line (found {prev!r})"
32
+ )
33
+
34
+
11
35
  def assert_contributor_generators_render(
12
36
  contributor: Any,
13
37
  *,
@@ -77,6 +101,15 @@ def assert_contributor_generators_render(
77
101
  f"(created={len(created)}, overwritten={len(overwritten)}, "
78
102
  f"staged={len(staged)})"
79
103
  )
104
+
105
+ # Every rendered Python stub must follow the @INTENT/@TODO marker
106
+ # convention — a single gate so a new generator (or a template at a
107
+ # deeper package nesting) cannot reintroduce a bare ``# TODO``.
108
+ for py_file in out.rglob("*.py"):
109
+ if "__pycache__" in py_file.parts:
110
+ continue
111
+ _assert_marker_convention(py_file, py_file.read_text(encoding="utf-8"))
112
+
80
113
  exercised += 1
81
114
  return exercised
82
115
 
@@ -51,7 +51,7 @@ class ServiceProbe:
51
51
  await client.close()
52
52
  return True
53
53
  except Exception as e: # noqa: BLE001
54
- logger.debug("probe_failed", service="redis", url=url, error=str(e))
54
+ logger.debug("probe_failed", dependency="redis", url=url, error=str(e))
55
55
  return False
56
56
 
57
57
  @staticmethod
@@ -66,7 +66,7 @@ class ServiceProbe:
66
66
  await conn.close()
67
67
  return True
68
68
  except Exception as e: # noqa: BLE001
69
- logger.debug("probe_failed", service="postgres", dsn=dsn, error=str(e))
69
+ logger.debug("probe_failed", dependency="postgres", dsn=dsn, error=str(e))
70
70
  return False
71
71
 
72
72
  @staticmethod
@@ -79,7 +79,9 @@ class ServiceProbe:
79
79
  response = await client.get(url)
80
80
  return response.status_code == 200
81
81
  except Exception as e: # noqa: BLE001
82
- logger.debug("probe_failed", service="elasticsearch", url=url, error=str(e))
82
+ logger.debug(
83
+ "probe_failed", dependency="elasticsearch", url=url, error=str(e)
84
+ )
83
85
  return False
84
86
 
85
87
  @staticmethod
@@ -94,7 +96,7 @@ class ServiceProbe:
94
96
  await connection.close()
95
97
  return True
96
98
  except Exception as e: # noqa: BLE001
97
- logger.debug("probe_failed", service="rabbitmq", url=url, error=str(e))
99
+ logger.debug("probe_failed", dependency="rabbitmq", url=url, error=str(e))
98
100
  return False
99
101
 
100
102
  @staticmethod
@@ -107,7 +109,9 @@ class ServiceProbe:
107
109
  response = await client.get(f"{url}/health")
108
110
  return response.status_code == 200
109
111
  except Exception as e: # noqa: BLE001
110
- logger.debug("probe_failed", service="meilisearch", url=url, error=str(e))
112
+ logger.debug(
113
+ "probe_failed", dependency="meilisearch", url=url, error=str(e)
114
+ )
111
115
  return False
112
116
 
113
117
  @staticmethod
@@ -125,7 +129,7 @@ class ServiceProbe:
125
129
  return True
126
130
  except Exception as e: # noqa: BLE001
127
131
  logger.debug(
128
- "probe_failed", service="smtp", host=host, port=port, error=str(e)
132
+ "probe_failed", dependency="smtp", host=host, port=port, error=str(e)
129
133
  )
130
134
  return False
131
135
 
@@ -152,7 +156,7 @@ class ServiceProbe:
152
156
  return True
153
157
  except Exception as e: # noqa: BLE001
154
158
  logger.debug(
155
- "probe_failed", service="kafka", bootstrap=bootstrap, error=str(e)
159
+ "probe_failed", dependency="kafka", bootstrap=bootstrap, error=str(e)
156
160
  )
157
161
  return False
158
162
 
@@ -179,7 +183,7 @@ class ServiceProbe:
179
183
  return True
180
184
  except Exception as e: # noqa: BLE001
181
185
  logger.debug(
182
- "probe_failed", service="minio", endpoint=endpoint, error=str(e)
186
+ "probe_failed", dependency="minio", endpoint=endpoint, error=str(e)
183
187
  )
184
188
  return False
185
189
 
@@ -207,7 +211,7 @@ class ServiceProbe:
207
211
  await writer.wait_closed()
208
212
  return True
209
213
  except Exception as e: # noqa: BLE001
210
- logger.debug("probe_failed", service="mongodb", dsn=dsn, error=str(e))
214
+ logger.debug("probe_failed", dependency="mongodb", dsn=dsn, error=str(e))
211
215
  return False
212
216
 
213
217
  @staticmethod
@@ -234,7 +238,7 @@ class ServiceProbe:
234
238
  await writer.wait_closed()
235
239
  return True
236
240
  except Exception as e: # noqa: BLE001
237
- logger.debug("probe_failed", service="qdrant", url=url, error=str(e))
241
+ logger.debug("probe_failed", dependency="qdrant", url=url, error=str(e))
238
242
  return False
239
243
 
240
244
  @staticmethod
@@ -261,5 +265,5 @@ class ServiceProbe:
261
265
  await writer.wait_closed()
262
266
  return True
263
267
  except Exception as e: # noqa: BLE001
264
- logger.debug("probe_failed", service="neo4j", url=url, error=str(e))
268
+ logger.debug("probe_failed", dependency="neo4j", url=url, error=str(e))
265
269
  return False
@@ -2,7 +2,7 @@
2
2
 
3
3
  Provides minimal in-memory CQRS dispatch for unit tests and local development.
4
4
  For production use with middleware pipelines, metrics, and transaction support,
5
- use the ``the optional provider`` extension.
5
+ use the ``quadkit-events`` extension.
6
6
 
7
7
  Example::
8
8
 
@@ -18,7 +18,7 @@ from quadkit.contracts.events import EventBusProtocol as EventBusProtocol
18
18
  from quadkit.contracts.events import EventHandlerProtocol
19
19
 
20
20
  if TYPE_CHECKING:
21
- from collections.abc import Callable
21
+ from collections.abc import Awaitable, Callable
22
22
 
23
23
  from quadkit.contracts.core import MiddlewarePipelineProtocol
24
24
  from quadkit.contracts.domain.events import DomainEvent
@@ -76,11 +76,14 @@ class InMemoryEventBus(EventBusProtocol):
76
76
  the originating request context.
77
77
  """
78
78
  # handlers stored as (priority, handler) tuples, sorted by priority
79
- self._handlers: dict[type | str, list[tuple[int, EventHandlerProtocol]]] = (
80
- defaultdict(list)
81
- )
79
+ self._handlers: dict[
80
+ type | str,
81
+ list[tuple[int, EventHandlerProtocol | Callable[..., Awaitable[Any]]]],
82
+ ] = defaultdict(list)
82
83
  # wildcard subscriptions receive every published event regardless of type
83
- self._wildcard_handlers: list[tuple[int, EventHandlerProtocol]] = []
84
+ self._wildcard_handlers: list[
85
+ tuple[int, EventHandlerProtocol | Callable[..., Awaitable[Any]]]
86
+ ] = []
84
87
  from quadkit.app.pipeline import (
85
88
  MiddlewarePipeline as _MiddlewarePipeline,
86
89
  )
@@ -98,7 +101,7 @@ class InMemoryEventBus(EventBusProtocol):
98
101
  def subscribe(
99
102
  self,
100
103
  event_type: type | str,
101
- handler: EventHandlerProtocol,
104
+ handler: EventHandlerProtocol | Callable[..., Awaitable[Any]],
102
105
  *,
103
106
  priority: int = 0,
104
107
  ) -> None:
@@ -121,7 +124,9 @@ class InMemoryEventBus(EventBusProtocol):
121
124
  self._handlers[event_type].sort(key=lambda entry: entry[0])
122
125
 
123
126
  def unsubscribe(
124
- self, event_type: type | str, handler: EventHandlerProtocol
127
+ self,
128
+ event_type: type | str,
129
+ handler: EventHandlerProtocol | Callable[..., Awaitable[Any]],
125
130
  ) -> None:
126
131
  """Remove a previously registered handler for an event type.
127
132
 
@@ -141,6 +146,15 @@ class InMemoryEventBus(EventBusProtocol):
141
146
  return
142
147
  self._handlers[event_type] = [(p, h) for p, h in handlers if h is not handler]
143
148
 
149
+ async def flush(self) -> None:
150
+ """Wait until all pending events have been dispatched.
151
+
152
+ A no-op here: ``publish`` awaits every handler before it returns, so
153
+ this engine never has an in-flight dispatch to drain. The member
154
+ exists because ``EventBusProtocol`` declares it — the flagship bus
155
+ dispatches in the background and does need it.
156
+ """
157
+
144
158
  def add_middleware(self, middleware: Any) -> None:
145
159
  """Add a middleware function to the event processing chain.
146
160
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Provides an in-memory Outbox for testing and local development.
4
4
  For production with database persistence, use the OutboxEventStore
5
- from the the optional provider extension.
5
+ from the quadkit-events extension.
6
6
 
7
7
  The Outbox pattern ensures events are stored in the same transaction
8
8
  as business data, then relayed asynchronously for publishing.
@@ -3,7 +3,7 @@
3
3
  Provides a generic, async-safe in-memory implementation of the RepositoryProtocol
4
4
  pattern backed by :class:`~quadkit.data.repository.base.AbstractRepository`.
5
5
  Intended as a zero-infrastructure drop-in for unit tests and local development.
6
- For production, replace with ``the optional provider``'s SQLRepository or a
6
+ For production, replace with ``quadkit-sql``'s SQLRepository or a
7
7
  domain-specific storage backend.
8
8
  """
9
9
 
@@ -26,7 +26,7 @@ class InMemoryRepository(AbstractRepository[T, Any], Generic[T]):
26
26
  This class lives in ``quadkit-testing`` intentionally — it is not exported
27
27
  from ``quadkit`` core. Production code should depend on the
28
28
  ``RepositoryProtocol`` protocol from ``quadkit.contracts.data`` and receive a
29
- concrete implementation (e.g. ``SQLRepository`` from ``the optional provider``)
29
+ concrete implementation (e.g. ``SQLRepository`` from ``quadkit-sql``)
30
30
  via dependency injection.
31
31
 
32
32
  Stores entities in a plain dict keyed by their identity attribute.
@@ -36,7 +36,7 @@ class InMemoryRepository(AbstractRepository[T, Any], Generic[T]):
36
36
 
37
37
  Extends :class:`~quadkit.data.repository.base.AbstractRepository` and
38
38
  implements all required primitives. For production persistence, use
39
- ``the optional provider``'s ``SQLRepository`` or any other storage backend.
39
+ ``quadkit-sql``'s ``SQLRepository`` or any other storage backend.
40
40
 
41
41
  Args:
42
42
  id_attr: Name of the entity attribute that holds the primary key.
@@ -6,7 +6,7 @@ Provides a concrete :class:`InMemoryUnitOfWork` that extends
6
6
  database persistence is required.
7
7
 
8
8
  For production, use a backend that overrides :meth:`_flush` to write to a
9
- database (e.g. ``the optional provider``'s ``SQLUnitOfWork``).
9
+ database (e.g. ``quadkit-sql``'s ``SQLUnitOfWork``).
10
10
  """
11
11
 
12
12
  from __future__ import annotations