loom-kernel 0.2.0__tar.gz → 0.3.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 (534) hide show
  1. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/.github/workflows/ci-pr.yml +1 -1
  2. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/.github/workflows/release.yml +34 -0
  3. loom_kernel-0.3.0/CHANGELOG.md +216 -0
  4. loom_kernel-0.3.0/CHANGELOG_RELEASE.md +60 -0
  5. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/PKG-INFO +42 -7
  6. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/README.md +18 -6
  7. loom_kernel-0.3.0/docs/_static/custom.css +13 -0
  8. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/conf.py +18 -2
  9. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/examples-repo/index.md +171 -6
  10. loom_kernel-0.3.0/docs/guides/etl.md +426 -0
  11. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/guides/fake-repo-examples.md +18 -1
  12. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/guides/quickstart.md +24 -6
  13. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/guides/use-case-dsl.md +4 -1
  14. loom_kernel-0.3.0/docs/index.rst +69 -0
  15. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/reference/api/core.rst +8 -0
  16. loom_kernel-0.3.0/docs/reference/api/etl.rst +49 -0
  17. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/reference/index.rst +1 -0
  18. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/pyproject.toml +63 -2
  19. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/celery/bootstrap.py +3 -2
  20. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/config/__init__.py +2 -1
  21. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/config/loader.py +149 -26
  22. loom_kernel-0.3.0/src/loom/core/config/resolver.py +82 -0
  23. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/di/container.py +26 -0
  24. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/discovery/_utils.py +3 -5
  25. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/logger/config.py +23 -1
  26. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/__init__.py +2 -0
  27. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/base.py +7 -15
  28. loom_kernel-0.3.0/src/loom/core/model/struct.py +14 -0
  29. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/timestamped.py +4 -13
  30. loom_kernel-0.3.0/src/loom/core/repository/__init__.py +39 -0
  31. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/abc/__init__.py +15 -1
  32. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/abc/query.py +2 -2
  33. loom_kernel-0.3.0/src/loom/core/repository/abc/repo_for.py +151 -0
  34. loom_kernel-0.3.0/src/loom/core/repository/registration.py +213 -0
  35. loom_kernel-0.3.0/src/loom/core/repository/registry.py +140 -0
  36. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/__init__.py +4 -10
  37. loom_kernel-0.3.0/src/loom/core/repository/sqlalchemy/registry.py +121 -0
  38. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/repository.py +17 -2
  39. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/response/base.py +2 -2
  40. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/factory.py +1 -25
  41. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/use_case.py +47 -17
  42. loom_kernel-0.3.0/src/loom/etl/__init__.py +199 -0
  43. loom_kernel-0.3.0/src/loom/etl/backends/__init__.py +9 -0
  44. loom_kernel-0.3.0/src/loom/etl/backends/_format_registry.py +37 -0
  45. loom_kernel-0.3.0/src/loom/etl/backends/_merge.py +276 -0
  46. loom_kernel-0.3.0/src/loom/etl/backends/_predicate.py +144 -0
  47. loom_kernel-0.3.0/src/loom/etl/backends/_schema_aligner/__init__.py +6 -0
  48. loom_kernel-0.3.0/src/loom/etl/backends/_schema_aligner/_aligner.py +23 -0
  49. loom_kernel-0.3.0/src/loom/etl/backends/_schema_aligner/_policy.py +66 -0
  50. loom_kernel-0.3.0/src/loom/etl/backends/_write_policy.py +376 -0
  51. loom_kernel-0.3.0/src/loom/etl/backends/polars/__init__.py +14 -0
  52. loom_kernel-0.3.0/src/loom/etl/backends/polars/_dtype.py +257 -0
  53. loom_kernel-0.3.0/src/loom/etl/backends/polars/_file_writer.py +92 -0
  54. loom_kernel-0.3.0/src/loom/etl/backends/polars/_predicate.py +102 -0
  55. loom_kernel-0.3.0/src/loom/etl/backends/polars/_reader.py +193 -0
  56. loom_kernel-0.3.0/src/loom/etl/backends/polars/_schema.py +180 -0
  57. loom_kernel-0.3.0/src/loom/etl/backends/polars/_schema_aligner.py +37 -0
  58. loom_kernel-0.3.0/src/loom/etl/backends/polars/_writer.py +354 -0
  59. loom_kernel-0.3.0/src/loom/etl/backends/polars/provider.py +138 -0
  60. loom_kernel-0.3.0/src/loom/etl/backends/spark/__init__.py +16 -0
  61. loom_kernel-0.3.0/src/loom/etl/backends/spark/_dtype.py +126 -0
  62. loom_kernel-0.3.0/src/loom/etl/backends/spark/_reader.py +196 -0
  63. loom_kernel-0.3.0/src/loom/etl/backends/spark/_schema.py +41 -0
  64. loom_kernel-0.3.0/src/loom/etl/backends/spark/_schema_aligner.py +40 -0
  65. loom_kernel-0.3.0/src/loom/etl/backends/spark/_writer.py +408 -0
  66. loom_kernel-0.3.0/src/loom/etl/backends/spark/provider.py +79 -0
  67. loom_kernel-0.3.0/src/loom/etl/checkpoint/__init__.py +15 -0
  68. loom_kernel-0.3.0/src/loom/etl/checkpoint/_backends/_polars.py +106 -0
  69. loom_kernel-0.3.0/src/loom/etl/checkpoint/_backends/_spark.py +135 -0
  70. loom_kernel-0.3.0/src/loom/etl/checkpoint/_cleaners.py +64 -0
  71. loom_kernel-0.3.0/src/loom/etl/checkpoint/_paths.py +52 -0
  72. loom_kernel-0.3.0/src/loom/etl/checkpoint/_scope.py +35 -0
  73. loom_kernel-0.3.0/src/loom/etl/checkpoint/_store.py +234 -0
  74. loom_kernel-0.3.0/src/loom/etl/compiler/__init__.py +48 -0
  75. loom_kernel-0.3.0/src/loom/etl/compiler/_binding.py +111 -0
  76. loom_kernel-0.3.0/src/loom/etl/compiler/_compiler.py +268 -0
  77. loom_kernel-0.3.0/src/loom/etl/compiler/_errors.py +316 -0
  78. loom_kernel-0.3.0/src/loom/etl/compiler/_plan.py +206 -0
  79. loom_kernel-0.3.0/src/loom/etl/compiler/_validators.py +40 -0
  80. loom_kernel-0.3.0/src/loom/etl/compiler/_validators_plan.py +267 -0
  81. loom_kernel-0.3.0/src/loom/etl/compiler/_validators_step.py +294 -0
  82. loom_kernel-0.3.0/src/loom/etl/declarative/__init__.py +53 -0
  83. loom_kernel-0.3.0/src/loom/etl/declarative/_format.py +21 -0
  84. loom_kernel-0.3.0/src/loom/etl/declarative/_read_options.py +91 -0
  85. loom_kernel-0.3.0/src/loom/etl/declarative/_utils.py +18 -0
  86. loom_kernel-0.3.0/src/loom/etl/declarative/_write_options.py +111 -0
  87. loom_kernel-0.3.0/src/loom/etl/declarative/expr/__init__.py +50 -0
  88. loom_kernel-0.3.0/src/loom/etl/declarative/expr/_params.py +61 -0
  89. loom_kernel-0.3.0/src/loom/etl/declarative/expr/_predicate.py +174 -0
  90. loom_kernel-0.3.0/src/loom/etl/declarative/expr/_predicate_dialect.py +160 -0
  91. loom_kernel-0.3.0/src/loom/etl/declarative/expr/_refs.py +122 -0
  92. loom_kernel-0.3.0/src/loom/etl/declarative/source/__init__.py +43 -0
  93. loom_kernel-0.3.0/src/loom/etl/declarative/source/_from.py +569 -0
  94. loom_kernel-0.3.0/src/loom/etl/declarative/source/_specs.py +149 -0
  95. loom_kernel-0.3.0/src/loom/etl/declarative/target/__init__.py +70 -0
  96. loom_kernel-0.3.0/src/loom/etl/declarative/target/_file.py +34 -0
  97. loom_kernel-0.3.0/src/loom/etl/declarative/target/_into.py +453 -0
  98. loom_kernel-0.3.0/src/loom/etl/declarative/target/_schema_mode.py +23 -0
  99. loom_kernel-0.3.0/src/loom/etl/declarative/target/_table.py +103 -0
  100. loom_kernel-0.3.0/src/loom/etl/declarative/target/_temp.py +43 -0
  101. loom_kernel-0.3.0/src/loom/etl/executor/__init__.py +61 -0
  102. loom_kernel-0.3.0/src/loom/etl/executor/_dispatcher.py +94 -0
  103. loom_kernel-0.3.0/src/loom/etl/executor/_executor.py +357 -0
  104. loom_kernel-0.3.0/src/loom/etl/observability/__init__.py +59 -0
  105. loom_kernel-0.3.0/src/loom/etl/observability/config.py +106 -0
  106. loom_kernel-0.3.0/src/loom/etl/observability/factory.py +52 -0
  107. loom_kernel-0.3.0/src/loom/etl/observability/observers/__init__.py +13 -0
  108. loom_kernel-0.3.0/src/loom/etl/observability/observers/_labels.py +57 -0
  109. loom_kernel-0.3.0/src/loom/etl/observability/observers/composite.py +62 -0
  110. loom_kernel-0.3.0/src/loom/etl/observability/observers/noop.py +36 -0
  111. loom_kernel-0.3.0/src/loom/etl/observability/observers/otel.py +263 -0
  112. loom_kernel-0.3.0/src/loom/etl/observability/observers/protocol.py +37 -0
  113. loom_kernel-0.3.0/src/loom/etl/observability/observers/structlog.py +100 -0
  114. loom_kernel-0.3.0/src/loom/etl/observability/recording/__init__.py +5 -0
  115. loom_kernel-0.3.0/src/loom/etl/observability/recording/_recorder.py +225 -0
  116. loom_kernel-0.3.0/src/loom/etl/observability/records.py +241 -0
  117. loom_kernel-0.3.0/src/loom/etl/observability/sinks/__init__.py +17 -0
  118. loom_kernel-0.3.0/src/loom/etl/observability/sinks/_protocol.py +44 -0
  119. loom_kernel-0.3.0/src/loom/etl/observability/sinks/_table.py +42 -0
  120. loom_kernel-0.3.0/src/loom/etl/observability/sinks/_writer.py +26 -0
  121. loom_kernel-0.3.0/src/loom/etl/pipeline/__init__.py +12 -0
  122. loom_kernel-0.3.0/src/loom/etl/pipeline/_generics.py +31 -0
  123. loom_kernel-0.3.0/src/loom/etl/pipeline/_params.py +27 -0
  124. loom_kernel-0.3.0/src/loom/etl/pipeline/_pipeline.py +62 -0
  125. loom_kernel-0.3.0/src/loom/etl/pipeline/_process.py +64 -0
  126. loom_kernel-0.3.0/src/loom/etl/pipeline/_sql.py +55 -0
  127. loom_kernel-0.3.0/src/loom/etl/pipeline/_step.py +154 -0
  128. loom_kernel-0.3.0/src/loom/etl/pipeline/_step_sql.py +91 -0
  129. loom_kernel-0.3.0/src/loom/etl/runner/__init__.py +6 -0
  130. loom_kernel-0.3.0/src/loom/etl/runner/_providers.py +64 -0
  131. loom_kernel-0.3.0/src/loom/etl/runner/_wiring.py +112 -0
  132. loom_kernel-0.3.0/src/loom/etl/runner/config_loader.py +45 -0
  133. loom_kernel-0.3.0/src/loom/etl/runner/core.py +166 -0
  134. loom_kernel-0.3.0/src/loom/etl/runner/errors.py +17 -0
  135. loom_kernel-0.3.0/src/loom/etl/runner/filtering.py +107 -0
  136. loom_kernel-0.3.0/src/loom/etl/runtime/__init__.py +5 -0
  137. loom_kernel-0.3.0/src/loom/etl/runtime/contracts.py +128 -0
  138. loom_kernel-0.3.0/src/loom/etl/schema/__init__.py +46 -0
  139. loom_kernel-0.3.0/src/loom/etl/schema/_contract.py +220 -0
  140. loom_kernel-0.3.0/src/loom/etl/schema/_schema.py +334 -0
  141. loom_kernel-0.3.0/src/loom/etl/storage/__init__.py +60 -0
  142. loom_kernel-0.3.0/src/loom/etl/storage/_config.py +373 -0
  143. loom_kernel-0.3.0/src/loom/etl/storage/_file_locator.py +146 -0
  144. loom_kernel-0.3.0/src/loom/etl/storage/_locator.py +253 -0
  145. loom_kernel-0.3.0/src/loom/etl/storage/routing.py +230 -0
  146. loom_kernel-0.3.0/src/loom/etl/testing/__init__.py +58 -0
  147. loom_kernel-0.3.0/src/loom/etl/testing/_result.py +88 -0
  148. loom_kernel-0.3.0/src/loom/etl/testing/_runners.py +142 -0
  149. loom_kernel-0.3.0/src/loom/etl/testing/_scenario.py +79 -0
  150. loom_kernel-0.3.0/src/loom/etl/testing/_stubs.py +212 -0
  151. loom_kernel-0.3.0/src/loom/etl/testing/spark.py +324 -0
  152. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/prometheus/__init__.py +1 -1
  153. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/prometheus/middleware.py +3 -8
  154. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/autocrud.py +43 -3
  155. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/fastapi/auto.py +21 -5
  156. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/model.py +1 -1
  157. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/testing/repository_harness.py +11 -5
  158. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/conftest.py +34 -0
  159. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/rest/test_auto_interface_integration.py +77 -6
  160. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/rest/test_fastapi_app_integration.py +11 -8
  161. loom_kernel-0.3.0/tests/integration/core/use_case/test_custom_repository_integration.py +238 -0
  162. loom_kernel-0.3.0/tests/integration/etl/__init__.py +1 -0
  163. loom_kernel-0.3.0/tests/integration/etl/test_runner_integration.py +241 -0
  164. loom_kernel-0.3.0/tests/integration/etl/test_runtime_contracts.py +455 -0
  165. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/repository.py +4 -3
  166. loom_kernel-0.3.0/tests/integration/support/__init__.py +1 -0
  167. loom_kernel-0.3.0/tests/integration/support/logical_repo_fixtures.py +34 -0
  168. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/bootstrap/test_bootstrap_metrics.py +2 -2
  169. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/config/test_config.py +98 -0
  170. loom_kernel-0.3.0/tests/unit/core/model/test_struct.py +12 -0
  171. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/use_case/test_factory.py +49 -16
  172. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/conftest.py +175 -0
  173. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_apply_schema.py +90 -0
  174. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_backend.py +390 -0
  175. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_file_writer.py +71 -0
  176. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_predicate_pushdown.py +160 -0
  177. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_reader_columns.py +162 -0
  178. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_reader_json_columns.py +199 -0
  179. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_step_execution.py +223 -0
  180. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_upsert_writer.py +209 -0
  181. loom_kernel-0.3.0/tests/unit/etl/backends/test_polars/test_writer_to_frame.py +75 -0
  182. loom_kernel-0.3.0/tests/unit/etl/backends/test_spark/conftest.py +89 -0
  183. loom_kernel-0.3.0/tests/unit/etl/backends/test_spark/test_dtype.py +104 -0
  184. loom_kernel-0.3.0/tests/unit/etl/backends/test_spark/test_spark_apply_schema.py +215 -0
  185. loom_kernel-0.3.0/tests/unit/etl/backends/test_spark/test_step_execution.py +404 -0
  186. loom_kernel-0.3.0/tests/unit/etl/backends/test_spark/test_writer_to_frame.py +102 -0
  187. loom_kernel-0.3.0/tests/unit/etl/checkpoint/__init__.py +0 -0
  188. loom_kernel-0.3.0/tests/unit/etl/checkpoint/backends/test_checkpoint_polars.py +33 -0
  189. loom_kernel-0.3.0/tests/unit/etl/checkpoint/test_checkpoint_paths.py +61 -0
  190. loom_kernel-0.3.0/tests/unit/etl/checkpoint/test_cleaners.py +81 -0
  191. loom_kernel-0.3.0/tests/unit/etl/checkpoint/test_store.py +248 -0
  192. loom_kernel-0.3.0/tests/unit/etl/compiler/__init__.py +0 -0
  193. loom_kernel-0.3.0/tests/unit/etl/compiler/test_catalog_validator.py +92 -0
  194. loom_kernel-0.3.0/tests/unit/etl/compiler/test_compiler.py +502 -0
  195. loom_kernel-0.3.0/tests/unit/etl/compiler/test_compiler_catalog.py +132 -0
  196. loom_kernel-0.3.0/tests/unit/etl/compiler/test_compiler_upsert.py +133 -0
  197. loom_kernel-0.3.0/tests/unit/etl/compiler/test_errors.py +223 -0
  198. loom_kernel-0.3.0/tests/unit/etl/compiler/test_errors_additional_factories.py +76 -0
  199. loom_kernel-0.3.0/tests/unit/etl/compiler/test_errors_runtime_factories.py +159 -0
  200. loom_kernel-0.3.0/tests/unit/etl/compiler/test_param_exprs_validator.py +150 -0
  201. loom_kernel-0.3.0/tests/unit/etl/compiler/test_plan_traversal.py +207 -0
  202. loom_kernel-0.3.0/tests/unit/etl/compiler/test_step_validator.py +81 -0
  203. loom_kernel-0.3.0/tests/unit/etl/compiler/test_structural.py +135 -0
  204. loom_kernel-0.3.0/tests/unit/etl/compiler/test_temp_validator.py +205 -0
  205. loom_kernel-0.3.0/tests/unit/etl/compiler/test_upsert_validator.py +125 -0
  206. loom_kernel-0.3.0/tests/unit/etl/conftest.py +40 -0
  207. loom_kernel-0.3.0/tests/unit/etl/io/__init__.py +0 -0
  208. loom_kernel-0.3.0/tests/unit/etl/io/test_source.py +263 -0
  209. loom_kernel-0.3.0/tests/unit/etl/io/test_source_json.py +236 -0
  210. loom_kernel-0.3.0/tests/unit/etl/io/test_source_options.py +178 -0
  211. loom_kernel-0.3.0/tests/unit/etl/io/test_target.py +225 -0
  212. loom_kernel-0.3.0/tests/unit/etl/io/test_utils.py +32 -0
  213. loom_kernel-0.3.0/tests/unit/etl/io/test_variants.py +125 -0
  214. loom_kernel-0.3.0/tests/unit/etl/pipeline/__init__.py +1 -0
  215. loom_kernel-0.3.0/tests/unit/etl/pipeline/test_pipeline_process.py +67 -0
  216. loom_kernel-0.3.0/tests/unit/etl/pipeline/test_proxy.py +90 -0
  217. loom_kernel-0.3.0/tests/unit/etl/pipeline/test_step.py +132 -0
  218. loom_kernel-0.3.0/tests/unit/etl/schema/__init__.py +0 -0
  219. loom_kernel-0.3.0/tests/unit/etl/schema/test_contract.py +249 -0
  220. loom_kernel-0.3.0/tests/unit/etl/schema/test_schema.py +181 -0
  221. loom_kernel-0.3.0/tests/unit/etl/schema/test_table.py +63 -0
  222. loom_kernel-0.3.0/tests/unit/etl/sql/__init__.py +0 -0
  223. loom_kernel-0.3.0/tests/unit/etl/sql/test_merge.py +214 -0
  224. loom_kernel-0.3.0/tests/unit/etl/sql/test_predicate.py +99 -0
  225. loom_kernel-0.3.0/tests/unit/etl/sql/test_predicate_dialect.py +98 -0
  226. loom_kernel-0.3.0/tests/unit/etl/sql/test_sql_runtime.py +172 -0
  227. loom_kernel-0.3.0/tests/unit/etl/storage/__init__.py +0 -0
  228. loom_kernel-0.3.0/tests/unit/etl/storage/test_backend_factory.py +426 -0
  229. loom_kernel-0.3.0/tests/unit/etl/storage/test_io_protocols.py +101 -0
  230. loom_kernel-0.3.0/tests/unit/etl/storage/test_locator.py +87 -0
  231. loom_kernel-0.3.0/tests/unit/etl/storage/test_observability_and_protocols.py +149 -0
  232. loom_kernel-0.3.0/tests/unit/etl/storage/test_route_build.py +31 -0
  233. loom_kernel-0.3.0/tests/unit/etl/storage/test_schema_readers.py +91 -0
  234. loom_kernel-0.3.0/tests/unit/etl/storage/test_storage_config.py +341 -0
  235. loom_kernel-0.3.0/tests/unit/etl/test_config_loader.py +85 -0
  236. loom_kernel-0.3.0/tests/unit/etl/test_executor.py +317 -0
  237. loom_kernel-0.3.0/tests/unit/etl/test_format_registry.py +30 -0
  238. loom_kernel-0.3.0/tests/unit/etl/test_module_contracts.py +452 -0
  239. loom_kernel-0.3.0/tests/unit/etl/test_observer.py +351 -0
  240. loom_kernel-0.3.0/tests/unit/etl/test_observer_internals.py +448 -0
  241. loom_kernel-0.3.0/tests/unit/etl/test_public_api_discovery.py +57 -0
  242. loom_kernel-0.3.0/tests/unit/etl/test_record_schema_coverage.py +65 -0
  243. loom_kernel-0.3.0/tests/unit/etl/test_runner.py +300 -0
  244. loom_kernel-0.3.0/tests/unit/etl/test_runner_errors.py +19 -0
  245. loom_kernel-0.3.0/tests/unit/etl/test_spark_testing.py +78 -0
  246. loom_kernel-0.3.0/tests/unit/etl/testing/test_runners.py +146 -0
  247. loom_kernel-0.3.0/tests/unit/etl/testing/test_scenario_and_stubs.py +106 -0
  248. loom_kernel-0.3.0/tests/unit/etl/testing/test_spark_helpers.py +167 -0
  249. loom_kernel-0.3.0/tests/unit/prometheus/__init__.py +0 -0
  250. loom_kernel-0.3.0/tests/unit/rest/__init__.py +0 -0
  251. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_autocrud.py +9 -9
  252. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_fastapi_auto_logger.py +29 -0
  253. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_rest_adapter.py +34 -0
  254. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_rest_model.py +2 -2
  255. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_router_runtime.py +3 -3
  256. loom_kernel-0.3.0/tests/unit/testing/__init__.py +0 -0
  257. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/testing/test_golden.py +12 -4
  258. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/testing/test_http_harness.py +3 -4
  259. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/testing/test_runner.py +11 -3
  260. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/uv.lock +638 -5
  261. loom_kernel-0.2.0/CHANGELOG.md +0 -120
  262. loom_kernel-0.2.0/CHANGELOG_RELEASE.md +0 -125
  263. loom_kernel-0.2.0/docs/_static/custom.css +0 -11
  264. loom_kernel-0.2.0/docs/index.rst +0 -41
  265. loom_kernel-0.2.0/src/loom/core/repository/__init__.py +0 -21
  266. loom_kernel-0.2.0/src/loom/core/repository/abc/repo_for.py +0 -74
  267. loom_kernel-0.2.0/src/loom/core/repository/sqlalchemy/registry.py +0 -125
  268. loom_kernel-0.2.0/tests/integration/core/use_case/test_custom_repository_integration.py +0 -103
  269. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/.github/workflows/ci-main.yml +0 -0
  270. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/.github/workflows/docs.yml +0 -0
  271. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/.gitignore +0 -0
  272. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/.pre-commit-config.yaml +0 -0
  273. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/.readthedocs.yaml +0 -0
  274. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/LICENSE +0 -0
  275. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/Makefile +0 -0
  276. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/codecov.yml +0 -0
  277. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/_static/.gitkeep +0 -0
  278. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/_static/logo-transparent.png +0 -0
  279. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/_static/logo.svg +0 -0
  280. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/architecture/adr/README.md +0 -0
  281. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/architecture/clean-architecture.md +0 -0
  282. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/architecture/overview.md +0 -0
  283. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/guides/autocrud.md +0 -0
  284. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/guides/celery.md +0 -0
  285. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/reference/api/repository.rst +0 -0
  286. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/reference/api/rest.rst +0 -0
  287. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/reference/api/testing.rst +0 -0
  288. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/docs/requirements.txt +0 -0
  289. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/sonar-project.properties +0 -0
  290. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/__init__.py +0 -0
  291. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/celery/__init__.py +0 -0
  292. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/celery/auto.py +0 -0
  293. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/celery/config.py +0 -0
  294. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/celery/constants.py +0 -0
  295. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/celery/event_loop.py +0 -0
  296. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/celery/runner.py +0 -0
  297. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/celery/service.py +0 -0
  298. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/backend/__init__.py +0 -0
  299. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/backend/core_model.py +0 -0
  300. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/backend/protocol.py +0 -0
  301. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/backend/sqlalchemy.py +0 -0
  302. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/bootstrap/__init__.py +0 -0
  303. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
  304. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/bootstrap/kernel.py +0 -0
  305. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/__init__.py +0 -0
  306. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/abc/__init__.py +0 -0
  307. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/abc/backend.py +0 -0
  308. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/abc/config.py +0 -0
  309. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/abc/dependency.py +0 -0
  310. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/codec.py +0 -0
  311. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/decorators.py +0 -0
  312. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/dependency.py +0 -0
  313. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/gateway.py +0 -0
  314. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/keys.py +0 -0
  315. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/repository.py +0 -0
  316. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/cache/serializer.py +0 -0
  317. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/command/__init__.py +0 -0
  318. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/command/adapter.py +0 -0
  319. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/command/base.py +0 -0
  320. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/command/field.py +0 -0
  321. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/command/introspection.py +0 -0
  322. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/config/errors.py +0 -0
  323. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/config/keys.py +0 -0
  324. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/config/model.py +0 -0
  325. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/contracts/__init__.py +0 -0
  326. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/contracts/manifest.py +0 -0
  327. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/di/__init__.py +0 -0
  328. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/di/scope.py +0 -0
  329. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/discovery/__init__.py +0 -0
  330. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/discovery/base.py +0 -0
  331. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/discovery/interfaces.py +0 -0
  332. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/discovery/manifest.py +0 -0
  333. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/discovery/modules.py +0 -0
  334. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/engine/__init__.py +0 -0
  335. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/engine/compilable.py +0 -0
  336. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/engine/compiler.py +0 -0
  337. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/engine/events.py +0 -0
  338. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/engine/executor.py +0 -0
  339. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/engine/metrics.py +0 -0
  340. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/engine/plan.py +0 -0
  341. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/errors/__init__.py +0 -0
  342. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/errors/codes.py +0 -0
  343. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/errors/errors.py +0 -0
  344. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/job/__init__.py +0 -0
  345. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/job/callback.py +0 -0
  346. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/job/context.py +0 -0
  347. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/job/handle.py +0 -0
  348. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/job/job.py +0 -0
  349. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/job/service.py +0 -0
  350. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/logger/__init__.py +0 -0
  351. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/logger/abc.py +0 -0
  352. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/logger/registry.py +0 -0
  353. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/logger/structlogger.py +0 -0
  354. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/enums.py +0 -0
  355. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/field.py +0 -0
  356. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/introspection.py +0 -0
  357. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/projection.py +0 -0
  358. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/relation.py +0 -0
  359. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/types.py +0 -0
  360. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/model/types_postgres.py +0 -0
  361. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/projection/__init__.py +0 -0
  362. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/projection/loaders.py +0 -0
  363. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/projection/runtime.py +0 -0
  364. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/abc/repository.py +0 -0
  365. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/mutation.py +0 -0
  366. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
  367. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
  368. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/mixins.py +0 -0
  369. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
  370. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
  371. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
  372. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
  373. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +0 -0
  374. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
  375. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
  376. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
  377. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
  378. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
  379. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
  380. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/session_manager.py +0 -0
  381. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
  382. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
  383. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/response/__init__.py +0 -0
  384. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/tracing/__init__.py +0 -0
  385. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/tracing/context.py +0 -0
  386. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/transport/__init__.py +0 -0
  387. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/transport/adapter.py +0 -0
  388. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/uow/__init__.py +0 -0
  389. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/uow/abc.py +0 -0
  390. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/uow/context.py +0 -0
  391. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/__init__.py +0 -0
  392. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/_predicates.py +0 -0
  393. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/compute.py +0 -0
  394. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/constants.py +0 -0
  395. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/field_ref.py +0 -0
  396. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/invoker.py +0 -0
  397. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/keys.py +0 -0
  398. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/markers.py +0 -0
  399. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/registry.py +0 -0
  400. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/core/use_case/rule.py +0 -0
  401. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/prometheus/adapter.py +0 -0
  402. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/__init__.py +0 -0
  403. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/adapter.py +0 -0
  404. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/compiler.py +0 -0
  405. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/constants.py +0 -0
  406. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/errors.py +0 -0
  407. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/fastapi/__init__.py +0 -0
  408. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/fastapi/app.py +0 -0
  409. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/fastapi/openapi.py +0 -0
  410. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/fastapi/response.py +0 -0
  411. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/fastapi/router_runtime.py +0 -0
  412. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/middleware.py +0 -0
  413. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/rest/rest_adapter.py +0 -0
  414. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/testing/__init__.py +0 -0
  415. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/testing/golden.py +0 -0
  416. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/testing/http_harness.py +0 -0
  417. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/testing/in_memory.py +0 -0
  418. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/src/loom/testing/runner.py +0 -0
  419. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/__init__.py +0 -0
  420. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/golden/__init__.py +0 -0
  421. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/golden/baselines/.gitkeep +0 -0
  422. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/golden/outputs/.gitkeep +0 -0
  423. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/golden/plans/.gitkeep +0 -0
  424. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/helpers/__init__.py +0 -0
  425. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/__init__.py +0 -0
  426. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/celery_bootstrap/__init__.py +0 -0
  427. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/celery_bootstrap/config/conf.celery.integration.yaml +0 -0
  428. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/celery_bootstrap/test_auto_create_app_integration.py +0 -0
  429. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/celery_bootstrap/test_bootstrap_worker.py +0 -0
  430. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/conftest.py +0 -0
  431. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/__init__.py +0 -0
  432. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/repository/__init__.py +0 -0
  433. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/repository/sqlalchemy/__init__.py +0 -0
  434. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/repository/sqlalchemy/conftest.py +0 -0
  435. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/repository/sqlalchemy/test_cache_integration.py +0 -0
  436. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/repository/sqlalchemy/test_repository_integration.py +0 -0
  437. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/rest/__init__.py +0 -0
  438. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/core/use_case/test_use_case_crud_integration.py +0 -0
  439. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/__init__.py +0 -0
  440. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/config/__init__.py +0 -0
  441. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/config/conf.interfaces.yaml +0 -0
  442. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/config/conf.manifest.yaml +0 -0
  443. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/config/conf.modules.yaml +0 -0
  444. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/config/conf.yaml +0 -0
  445. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/main.py +0 -0
  446. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/manifest.py +0 -0
  447. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/__init__.py +0 -0
  448. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/category/__init__.py +0 -0
  449. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/category/model.py +0 -0
  450. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/category/schemas.py +0 -0
  451. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/interface.py +0 -0
  452. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/jobs.py +0 -0
  453. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/model.py +0 -0
  454. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/relations.py +0 -0
  455. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/repository_contract.py +0 -0
  456. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/review/__init__.py +0 -0
  457. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/review/model.py +0 -0
  458. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/review/schemas.py +0 -0
  459. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/schemas.py +0 -0
  460. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/integration/fake_repo/product/use_cases.py +0 -0
  461. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/celery_bootstrap/__init__.py +0 -0
  462. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/celery_bootstrap/test_bootstrap.py +0 -0
  463. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/celery_bootstrap/test_event_loop.py +0 -0
  464. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/celery_jobs/__init__.py +0 -0
  465. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/celery_jobs/test_auto.py +0 -0
  466. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/celery_jobs/test_celery_service.py +0 -0
  467. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/celery_jobs/test_config.py +0 -0
  468. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/celery_jobs/test_runner.py +0 -0
  469. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/backend/__init__.py +0 -0
  470. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/backend/test_backend_compiler.py +0 -0
  471. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/bootstrap/__init__.py +0 -0
  472. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/bootstrap/test_bootstrap.py +0 -0
  473. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/bootstrap/test_kernel.py +0 -0
  474. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/cache/test_cached_repository.py +0 -0
  475. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/command/__init__.py +0 -0
  476. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/command/test_command_base.py +0 -0
  477. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/command/test_command_field.py +0 -0
  478. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/command/test_command_patch.py +0 -0
  479. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/command/test_introspection.py +0 -0
  480. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/config/__init__.py +0 -0
  481. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/di/__init__.py +0 -0
  482. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/di/test_container.py +0 -0
  483. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/discovery/test_manifest.py +0 -0
  484. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/engine/__init__.py +0 -0
  485. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/engine/test_compiler.py +0 -0
  486. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/engine/test_executor.py +0 -0
  487. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/engine/test_executor_trace.py +0 -0
  488. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/engine/test_executor_uow.py +0 -0
  489. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/engine/test_metrics.py +0 -0
  490. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/engine/test_plan.py +0 -0
  491. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/errors/__init__.py +0 -0
  492. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/errors/test_errors.py +0 -0
  493. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/job/__init__.py +0 -0
  494. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/job/conftest.py +0 -0
  495. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/job/test_callback.py +0 -0
  496. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/job/test_context.py +0 -0
  497. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/job/test_handle.py +0 -0
  498. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/job/test_inline_service.py +0 -0
  499. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/job/test_job.py +0 -0
  500. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/logger/test_registry.py +0 -0
  501. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/model/__init__.py +0 -0
  502. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/model/test_model.py +0 -0
  503. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/model/test_timestamped.py +0 -0
  504. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/projection/test_runtime.py +0 -0
  505. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/repository/abc/conftest.py +0 -0
  506. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/repository/abc/test_query.py +0 -0
  507. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/repository/abc/test_repository_contract.py +0 -0
  508. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/repository/sqlalchemy/conftest.py +0 -0
  509. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/repository/sqlalchemy/test_loaders.py +0 -0
  510. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/repository/sqlalchemy/test_repository.py +0 -0
  511. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/repository/sqlalchemy/test_transactional.py +0 -0
  512. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/tracing/__init__.py +0 -0
  513. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/tracing/test_context.py +0 -0
  514. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/uow/__init__.py +0 -0
  515. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/uow/test_executor_uow.py +0 -0
  516. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/uow/test_sqlalchemy_uow.py +0 -0
  517. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/uow/test_uow_protocols.py +0 -0
  518. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/use_case/__init__.py +0 -0
  519. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/use_case/test_compute.py +0 -0
  520. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/use_case/test_field_ref.py +0 -0
  521. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/use_case/test_invoker.py +0 -0
  522. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/use_case/test_markers.py +0 -0
  523. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/use_case/test_rule.py +0 -0
  524. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/core/use_case/test_use_case.py +0 -0
  525. {loom_kernel-0.2.0/tests/unit/prometheus → loom_kernel-0.3.0/tests/unit/etl}/__init__.py +0 -0
  526. {loom_kernel-0.2.0/tests/unit/rest → loom_kernel-0.3.0/tests/unit/etl/backends/test_polars}/__init__.py +0 -0
  527. {loom_kernel-0.2.0/tests/unit/testing → loom_kernel-0.3.0/tests/unit/etl/backends/test_spark}/__init__.py +0 -0
  528. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/prometheus/test_adapter.py +0 -0
  529. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/prometheus/test_middleware.py +0 -0
  530. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_middleware.py +0 -0
  531. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_pydantic_adapter.py +0 -0
  532. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_response.py +0 -0
  533. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/rest/test_rest_compiler.py +0 -0
  534. {loom_kernel-0.2.0 → loom_kernel-0.3.0}/tests/unit/testing/test_in_memory.py +0 -0
@@ -188,7 +188,7 @@ jobs:
188
188
  --skip-existing dist/*
189
189
 
190
190
  - name: Enforce changelog generation
191
- if: ${{ always() }}
191
+ if: ${{ always() && !startsWith(github.head_ref, 'docs/release-') }}
192
192
  shell: bash
193
193
  run: |
194
194
  set -euo pipefail
@@ -14,6 +14,7 @@ on:
14
14
  permissions:
15
15
  contents: write
16
16
  id-token: write
17
+ pull-requests: write
17
18
 
18
19
  concurrency:
19
20
  group: release-${{ github.ref }}
@@ -30,6 +31,7 @@ jobs:
30
31
  - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
31
32
  with:
32
33
  fetch-depth: 0
34
+ token: ${{ secrets.GITHUB_TOKEN }}
33
35
 
34
36
  - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
35
37
  with:
@@ -85,6 +87,38 @@ jobs:
85
87
  sed -i "0,/^version = \".*\"/s//version = \"${VERSION}\"/" pyproject.toml
86
88
  sed -i "/^\[tool.commitizen\]/,/^\[/ s/^version = \".*\"/version = \"${VERSION}\"/" pyproject.toml
87
89
 
90
+ - name: Open version bump PR
91
+ if: ${{ steps.version.outputs.deploy == 'true' }}
92
+ env:
93
+ VERSION: ${{ steps.version.outputs.version }}
94
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
95
+ shell: bash
96
+ run: |
97
+ set -euo pipefail
98
+ git config user.name "github-actions[bot]"
99
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
100
+
101
+ BRANCH="docs/release-v${VERSION}"
102
+ git checkout -b "${BRANCH}"
103
+
104
+ if [ -f CHANGELOG_RELEASE.md ]; then
105
+ cat CHANGELOG_RELEASE.md CHANGELOG.md > CHANGELOG_MERGED.md
106
+ mv CHANGELOG_MERGED.md CHANGELOG.md
107
+ fi
108
+
109
+ git add pyproject.toml CHANGELOG.md
110
+ git diff --staged --quiet && exit 0
111
+ git commit -m "chore(release): bump version to ${VERSION}"
112
+ git push origin "${BRANCH}"
113
+
114
+ gh pr create \
115
+ --title "chore(release): bump version to ${VERSION}" \
116
+ --body "Automated version bump and changelog update after release v${VERSION}." \
117
+ --base master \
118
+ --head "${BRANCH}"
119
+
120
+ gh pr merge "${BRANCH}" --squash --auto --delete-branch
121
+
88
122
  - name: Build package
89
123
  if: ${{ steps.version.outputs.deploy == 'true' }}
90
124
  shell: bash
@@ -0,0 +1,216 @@
1
+ # 🚀 Release 0.3.0 ([#14](https://github.com/the-reacher-data/loom-py/pull/14)) ([`ef414c5`](https://github.com/the-reacher-data/loom-py/commit/ef414c5bfd303296af450840318dfbe9d301e5d1))
2
+
3
+
4
+ ## ✨ Features
5
+ ### config
6
+ - **config:** add cloud URI support and pluggable resolver extension point<br>
7
+ > Add fsspec as a hard dependency of loom[config]
8
+ > load_config() now accepts s3://, gs://, abfss://, r2:// URIs via fsspec
9
+ > Add ConfigResolver protocol for pluggable ${prefix:key} resolution at
10
+ > parse time (enables SSM, Key Vault, etc. without baking secrets into images)
11
+ > Resolver registration is idempotent; resolvers are evaluated at job startup
12
+ > so secret rotation takes effect on the next run
13
+ > Migrate loom.etl.runner.config_loader to use core load_config, removing
14
+ > the parallel OmegaConf implementation
15
+ > ETL _load_yaml inherits cloud URI and resolver support transparently
16
+
17
+
18
+ ### etl
19
+ - **etl:** add FileLocator with explicit alias API for file routes<br>
20
+ > Introduces `FileLocator` protocol and `MappingFileLocator` so that
21
+ > `FromFile.alias("name")` / `IntoFile.alias("name")` specs resolve at
22
+ > runtime through `storage.files` config rather than hard-coded URIs.
23
+ > `FileLocation` / `FileLocator` / `MappingFileLocator` in `storage/_file_locator.py`
24
+ > `StorageConfig.to_file_locator()` returns `MappingFileLocator | None`
25
+ > (None when `files` is empty — no conditional needed at call sites)
26
+ > `FromFile.alias()` / `IntoFile.alias()` classmethods set `is_alias=True`
27
+ > on the emitted spec
28
+ > `is_alias: bool` added to `FileSourceSpec` and `FileSpec`
29
+ > Polars and Spark backends resolve aliases via injected `file_locator`
30
+ > Both providers wired: `file_locator = config.to_file_locator()`
31
+ > Full test coverage across io, storage, and backend layers
32
+
33
+
34
+
35
+ ## 🐛 Fixes
36
+ ### observability
37
+ - **observability:** honor missing table policy for record store writers
38
+
39
+
40
+ ## 📖 Documentation
41
+ ### etl
42
+ - **etl:** keep only user guide and drop refactor docs
43
+ - **etl:** expand ETL documentation and update directory table<br>
44
+ > Add dummy-loom-etl companion repo link in README and etl guide
45
+ > Expand README subpaths table with loom.etl and loom.core.config entries
46
+ > Add FileLocator/alias API, cloud config URI, and ConfigResolver sections to etl guide
47
+ > Add loom.etl.backends (polars + spark) to etl.rst API reference
48
+ > Add loom.core.config to core.rst API reference
49
+
50
+
51
+
52
+
53
+ ## ♻️ Refactor
54
+ ### stepsql
55
+ - **stepsql:** delegate SQL execution to backend readers
56
+
57
+
58
+
59
+
60
+
61
+ # 🚀 Release 0.3.0 ([#14](https://github.com/the-reacher-data/loom-py/pull/14)) ([`ef414c5`](https://github.com/the-reacher-data/loom-py/commit/ef414c5bfd303296af450840318dfbe9d301e5d1))
62
+
63
+
64
+ ## ✨ Features
65
+ ### config
66
+ - **config:** add cloud URI support and pluggable resolver extension point<br>
67
+ > Add fsspec as a hard dependency of loom[config]
68
+ > load_config() now accepts s3://, gs://, abfss://, r2:// URIs via fsspec
69
+ > Add ConfigResolver protocol for pluggable ${prefix:key} resolution at
70
+ > parse time (enables SSM, Key Vault, etc. without baking secrets into images)
71
+ > Resolver registration is idempotent; resolvers are evaluated at job startup
72
+ > so secret rotation takes effect on the next run
73
+ > Migrate loom.etl.runner.config_loader to use core load_config, removing
74
+ > the parallel OmegaConf implementation
75
+ > ETL _load_yaml inherits cloud URI and resolver support transparently
76
+
77
+
78
+ ### etl
79
+ - **etl:** add FileLocator with explicit alias API for file routes<br>
80
+ > Introduces `FileLocator` protocol and `MappingFileLocator` so that
81
+ > `FromFile.alias("name")` / `IntoFile.alias("name")` specs resolve at
82
+ > runtime through `storage.files` config rather than hard-coded URIs.
83
+ > `FileLocation` / `FileLocator` / `MappingFileLocator` in `storage/_file_locator.py`
84
+ > `StorageConfig.to_file_locator()` returns `MappingFileLocator | None`
85
+ > (None when `files` is empty — no conditional needed at call sites)
86
+ > `FromFile.alias()` / `IntoFile.alias()` classmethods set `is_alias=True`
87
+ > on the emitted spec
88
+ > `is_alias: bool` added to `FileSourceSpec` and `FileSpec`
89
+ > Polars and Spark backends resolve aliases via injected `file_locator`
90
+ > Both providers wired: `file_locator = config.to_file_locator()`
91
+ > Full test coverage across io, storage, and backend layers
92
+
93
+
94
+
95
+ ## 🐛 Fixes
96
+ ### observability
97
+ - **observability:** honor missing table policy for record store writers
98
+
99
+
100
+ ## 📖 Documentation
101
+ ### etl
102
+ - **etl:** keep only user guide and drop refactor docs
103
+ - **etl:** expand ETL documentation and update directory table<br>
104
+ > Add dummy-loom-etl companion repo link in README and etl guide
105
+ > Expand README subpaths table with loom.etl and loom.core.config entries
106
+ > Add FileLocator/alias API, cloud config URI, and ConfigResolver sections to etl guide
107
+ > Add loom.etl.backends (polars + spark) to etl.rst API reference
108
+ > Add loom.core.config to core.rst API reference
109
+
110
+
111
+
112
+
113
+ ## ♻️ Refactor
114
+ ### stepsql
115
+ - **stepsql:** delegate SQL execution to backend readers
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+ # 🚀 Release 0.2.1 ([#12](https://github.com/the-reacher-data/loom-py/pull/12)) ([`87f7d1f`](https://github.com/the-reacher-data/loom-py/commit/87f7d1f1eb1ccde71d0aca1c5584b83317e30707))
124
+
125
+ ## ✨ Features
126
+
127
+ ### logger
128
+ - **logger:** support per-logger levels from config<br>
129
+ > `LoomConfig` now accepts a `loggers` mapping to override the log level per named logger. Resolves `structlog` / stdlib incompatibility when mixing loom-managed and third-party loggers.
130
+
131
+ ### repository
132
+ - **repository:** generalize main repo registration for loom structs<br>
133
+ > `repository_for` is now importable from `loom.core.repository` (top-level). The SQLAlchemy-specific import path still works but is no longer the canonical one.
134
+
135
+ ## 🐛 Bug Fixes
136
+
137
+ ### rest
138
+ - **rest:** serialize pagination envelopes in camel case<br>
139
+ > `PageResult` and list-envelope responses were serialized in snake_case. All envelope fields now follow the camelCase contract of the HTTP layer.
140
+ - **rest:** support loom structs in autocrud tests<br>
141
+ > Auto-CRUD route generation was not exercising the `msgspec.Struct` code path in integration tests.
142
+
143
+ ### prometheus
144
+ - **prometheus:** expose metrics at exact path<br>
145
+ > Metrics endpoint was registered with a trailing-slash variant that did not match the documented `/metrics` path.
146
+
147
+ ### docs
148
+ - **docs:** fix RTD build failure, logo and docs examples (#10, #11)<br>
149
+ > Mock `starlette`, `celery`, `kombu`, `redis` in `autodoc_mock_imports`. Logo resized to natural proportions with dark-mode safe background. Status badges added to index. Rule/Compute examples updated to named predicates.
150
+
151
+ ---
152
+
153
+ # 🚀 Release 0.2.0 ([#9](https://github.com/the-reacher-data/loom-py/pull/9)) ([`2f669ab`](https://github.com/the-reacher-data/loom-py/commit/2f669ab205c7255eb6494e4cdb8ab8092817af62))
154
+
155
+ ## ✨ Features
156
+
157
+ ### cache
158
+ - **cache:** aiocache gateway with auto-inferred invalidation specs<br>
159
+ > CachedRepository wraps any repository with read-through/write-through caching. ONE_TO_MANY depends_on specs are auto-generated from field annotations — no explicit declaration needed. Explicit depends_on always wins.
160
+
161
+ ### celery
162
+ - **celery:** production-ready Celery integration layer<br>
163
+ > CeleryJobService, persistent worker event loop, trace propagation, eager fallback, and task_default_queue routing so callbacks land on the correct consumed queue. bootstrap_worker compiles use cases, repositories, and registers Celery tasks in a single call.
164
+
165
+ - **celery:** worker job discovery from modules or manifest<br>
166
+ > bootstrap_worker discovers and registers Job classes automatically from module include paths (mode: modules) or from a typed WorkerManifest (mode: manifest). WorkerManifest replaces scattered JOBS/USE_CASES/INTERFACES module attributes with a single typed contract.
167
+
168
+ - **celery:** interfaces= and use_cases= on bootstrap_worker<br>
169
+ > Callbacks that call ApplicationInvoker need matching use-case keys compiled in the worker. interfaces= extracts use-case types from RestInterface route declarations (including AutoCRUD-generated ones). use_cases= handles non-AutoCRUD scenarios. Both can be combined with discovery mode.
170
+
171
+ ### core
172
+ - **core:** typed repository abstractions and SQLAlchemy backend<br>
173
+ > Async repository protocol (RepositoryRead, RepositoryWrite, RepoFor) backed by SQLAlchemy 2.0 async session. Struct-based model system using msgspec.Struct as the single source of truth — models compile to SA mapped classes at startup via compile_all(). count() and UPDATE RETURNING included as first-class operations.
174
+
175
+ - **core:** use-case DSL with field refs, compute, rules and typed markers<br>
176
+ > Declarative use-case definition via Input, Load, LoadById, Exists, Compute and Rule markers. Signature inspection runs once at compile time; RuntimeExecutor drives execution from an immutable ExecutionPlan. No per-request reflection.
177
+
178
+ - **core:** ApplicationInvoker and named use-case registry<br>
179
+ > Use cases and job callbacks invoke other use cases by type through ApplicationInvoker without direct coupling. A named registry maps use-case keys to compiled instances at bootstrap, providing a stable cross-invocation contract.
180
+
181
+ - **core:** compiled model artifact and cache entity keys<br>
182
+ > compile_all() produces a typed CompiledCore artifact exposing stable entity keys used by the cache layer for deterministic repository-level invalidation across reads and writes.
183
+
184
+ - **core:** executor skips UoW for read-only use cases and GET routes<br>
185
+ > UseCase.read_only=True and all GET routes bypass UoW.begin/commit, removing at minimum one BEGIN+COMMIT round-trip from every read request on PostgreSQL.
186
+
187
+ ### job
188
+ - **job:** async job domain model and orchestration primitives<br>
189
+ > Job[ResultT] base class with Celery routing ClassVars. JobHandle / JobGroup with dual-mode waiting (Celery + inline). JobCallback lifecycle with on_success/on_failure. Dispatch is transactionally safe — jobs flush on UoW commit and are cleared on rollback.
190
+
191
+ ### observability
192
+ - **observability:** trace_id propagation and Prometheus adapter<br>
193
+ > trace_id injected into every request context and propagated to job callbacks. MetricsAdapter protocol emits execution events; PrometheusAdapter records latency histograms and error counters with low cardinality labels.
194
+
195
+ ### projection
196
+ - **projection:** compiler-driven memory/SQL routing<br>
197
+ > Projections are source-agnostic at declaration time. The backend compiler decides at compile_all() whether each projection runs in-memory (relation already loaded in the active profile) or via SQL. Users declare only CountLoader, ExistsLoader, or JoinFieldsLoader — no source= parameter. Internal _Memory* and _Sql* loaders are synthesized at compile time.
198
+
199
+ ### rest
200
+ - **rest:** AutoCRUD and FastAPI adapter<br>
201
+ > RestInterface.auto=True generates full CRUD routes at class definition time via build_auto_routes(). OpenAPI contracts expose query params, pagination defaults, and decoupled CreateInput/UpdateInput write DTOs. Discovery engine mounts all declared interfaces at bootstrap.
202
+
203
+ ## 📖 Documentation
204
+
205
+ - Sphinx documentation platform with full public guides<br>
206
+ > Quickstart, use-case DSL reference, AutoCRUD guide, Celery integration guide (job definition, dispatch, callbacks, YAML reference, bootstrap options, ApplicationInvoker, Docker-compose stack), and dummy-loom examples-repo walkthrough. Deployed to Read the Docs.
207
+
208
+ ## ⚡ Performance
209
+
210
+ ### engine
211
+ - **engine:** UPDATE RETURNING replaces SELECT + flush + refresh<br>
212
+ > SQLAlchemyUpdateMixin.update() issues a single UPDATE ... RETURNING round-trip. Server-side onupdate expressions are pre-computed at init time and injected into the SET clause automatically.
213
+
214
+ ### repository
215
+ - **repository:** single-query total count for offset pagination<br>
216
+ > list_with_query with PaginationMode.OFFSET issues a single SELECT COUNT(*) instead of a separate full-table scan, eliminating one round-trip per paginated list operation.
@@ -0,0 +1,60 @@
1
+ # 🚀 Release 0.3.0 ([#14](https://github.com/the-reacher-data/loom-py/pull/14)) ([`ef414c5`](https://github.com/the-reacher-data/loom-py/commit/ef414c5bfd303296af450840318dfbe9d301e5d1))
2
+
3
+
4
+ ## ✨ Features
5
+ ### config
6
+ - **config:** add cloud URI support and pluggable resolver extension point<br>
7
+ > Add fsspec as a hard dependency of loom[config]
8
+ > load_config() now accepts s3://, gs://, abfss://, r2:// URIs via fsspec
9
+ > Add ConfigResolver protocol for pluggable ${prefix:key} resolution at
10
+ > parse time (enables SSM, Key Vault, etc. without baking secrets into images)
11
+ > Resolver registration is idempotent; resolvers are evaluated at job startup
12
+ > so secret rotation takes effect on the next run
13
+ > Migrate loom.etl.runner.config_loader to use core load_config, removing
14
+ > the parallel OmegaConf implementation
15
+ > ETL _load_yaml inherits cloud URI and resolver support transparently
16
+
17
+
18
+ ### etl
19
+ - **etl:** add FileLocator with explicit alias API for file routes<br>
20
+ > Introduces `FileLocator` protocol and `MappingFileLocator` so that
21
+ > `FromFile.alias("name")` / `IntoFile.alias("name")` specs resolve at
22
+ > runtime through `storage.files` config rather than hard-coded URIs.
23
+ > `FileLocation` / `FileLocator` / `MappingFileLocator` in `storage/_file_locator.py`
24
+ > `StorageConfig.to_file_locator()` returns `MappingFileLocator | None`
25
+ > (None when `files` is empty — no conditional needed at call sites)
26
+ > `FromFile.alias()` / `IntoFile.alias()` classmethods set `is_alias=True`
27
+ > on the emitted spec
28
+ > `is_alias: bool` added to `FileSourceSpec` and `FileSpec`
29
+ > Polars and Spark backends resolve aliases via injected `file_locator`
30
+ > Both providers wired: `file_locator = config.to_file_locator()`
31
+ > Full test coverage across io, storage, and backend layers
32
+
33
+
34
+
35
+ ## 🐛 Fixes
36
+ ### observability
37
+ - **observability:** honor missing table policy for record store writers
38
+
39
+
40
+ ## 📖 Documentation
41
+ ### etl
42
+ - **etl:** keep only user guide and drop refactor docs
43
+ - **etl:** expand ETL documentation and update directory table<br>
44
+ > Add dummy-loom-etl companion repo link in README and etl guide
45
+ > Expand README subpaths table with loom.etl and loom.core.config entries
46
+ > Add FileLocator/alias API, cloud config URI, and ConfigResolver sections to etl guide
47
+ > Add loom.etl.backends (polars + spark) to etl.rst API reference
48
+ > Add loom.core.config to core.rst API reference
49
+
50
+
51
+
52
+
53
+ ## ♻️ Refactor
54
+ ### stepsql
55
+ - **stepsql:** delegate SQL execution to backend readers
56
+
57
+
58
+
59
+
60
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: loom-kernel
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Loom Python project
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.11
@@ -17,7 +17,30 @@ Requires-Dist: celery<6.0,>=5.3; extra == 'celery'
17
17
  Requires-Dist: kombu<6.0,>=5.3; extra == 'celery'
18
18
  Requires-Dist: redis<6.0,>=5.0; extra == 'celery'
19
19
  Provides-Extra: config
20
+ Requires-Dist: fsspec>=2024.2.0; extra == 'config'
20
21
  Requires-Dist: omegaconf<3.0,>=2.3; extra == 'config'
22
+ Provides-Extra: etl-otel
23
+ Requires-Dist: opentelemetry-api<2.0,>=1.20; extra == 'etl-otel'
24
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc<2.0,>=1.20; extra == 'etl-otel'
25
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http<2.0,>=1.20; extra == 'etl-otel'
26
+ Requires-Dist: opentelemetry-sdk<2.0,>=1.20; extra == 'etl-otel'
27
+ Provides-Extra: etl-polars
28
+ Requires-Dist: deltalake<2.0,>=1.5; extra == 'etl-polars'
29
+ Requires-Dist: fsspec>=2024.2.0; extra == 'etl-polars'
30
+ Requires-Dist: opentelemetry-api<2.0,>=1.20; extra == 'etl-polars'
31
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc<2.0,>=1.20; extra == 'etl-polars'
32
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http<2.0,>=1.20; extra == 'etl-polars'
33
+ Requires-Dist: opentelemetry-sdk<2.0,>=1.20; extra == 'etl-polars'
34
+ Requires-Dist: polars<2.0,>=1.0; extra == 'etl-polars'
35
+ Provides-Extra: etl-spark
36
+ Requires-Dist: delta-spark<4.0,>=3.2; extra == 'etl-spark'
37
+ Requires-Dist: findspark<3.0,>=2.0; extra == 'etl-spark'
38
+ Requires-Dist: fsspec>=2024.2.0; extra == 'etl-spark'
39
+ Requires-Dist: opentelemetry-api<2.0,>=1.20; extra == 'etl-spark'
40
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc<2.0,>=1.20; extra == 'etl-spark'
41
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http<2.0,>=1.20; extra == 'etl-spark'
42
+ Requires-Dist: opentelemetry-sdk<2.0,>=1.20; extra == 'etl-spark'
43
+ Requires-Dist: pyspark<4.0,>=3.5; extra == 'etl-spark'
21
44
  Provides-Extra: prometheus
22
45
  Requires-Dist: prometheus-client>=0.20; extra == 'prometheus'
23
46
  Provides-Extra: pyspark
@@ -33,11 +56,9 @@ Provides-Extra: sqlalchemy
33
56
  Requires-Dist: sqlalchemy<3.0,>=2.0; extra == 'sqlalchemy'
34
57
  Description-Content-Type: text/markdown
35
58
 
36
- <div style="width:100%;background:#fff;padding:4px 0;box-sizing:border-box;">
37
- <p align="center" style="margin:0;">
38
- <img src="docs/_static/logo-transparent.png" alt="loom-kernel" style="display:block;width:100%;max-width:none;max-height:220px;height:auto;object-fit:contain;margin:0 auto;" />
39
- </p>
40
- </div>
59
+ <p align="center">
60
+ <img src="docs/_static/logo-transparent.png" alt="loom-kernel" width="160" style="background:#ffffff;border-radius:6px;padding:8px 20px;" />
61
+ </p>
41
62
 
42
63
  # loom-kernel
43
64
 
@@ -72,7 +93,8 @@ infrastructure (DB, cache, transport) without breaking business logic.
72
93
 
73
94
  - Usage guides and architecture docs are available in the `docs/` site.
74
95
  - API reference is autogenerated from public docstrings.
75
- - End-to-end demo application: [`dummy-loom`](https://github.com/the-reacher-data/dummy-loom).
96
+ - End-to-end REST demo: [`dummy-loom`](https://github.com/the-reacher-data/dummy-loom).
97
+ - End-to-end ETL demo: [`dummy-loom-etl`](https://github.com/the-reacher-data/dummy-loom-etl) — full Polars and Spark pipeline examples.
76
98
 
77
99
  ## Main subpaths
78
100
 
@@ -84,10 +106,23 @@ infrastructure (DB, cache, transport) without breaking business logic.
84
106
  | `src/loom/core/repository/sqlalchemy` | Concrete async SQLAlchemy repository implementation. |
85
107
  | `src/loom/core/model` | Base model, fields, relations, and entity introspection. |
86
108
  | `src/loom/core/cache` | Decorators and cached repository with dependency invalidation. |
109
+ | `src/loom/core/config` | YAML config loader with cloud URI support and pluggable resolvers. |
87
110
  | `src/loom/rest` | Framework-agnostic REST model and route compiler. |
88
111
  | `src/loom/rest/fastapi` | Direct FastAPI integration (auto wiring and runtime router). |
89
112
  | `src/loom/prometheus` | Middleware and adapter for runtime metrics. |
90
113
  | `src/loom/testing` | Harnesses for unit/integration tests and golden tests. |
114
+ | `src/loom/etl` | Declarative ETL subsystem — pipelines, Polars/Spark backends, observability. |
115
+ | `src/loom/etl/pipeline` | `ETLStep`, `ETLProcess`, `ETLPipeline`, `StepSQL`, and `ETLParams`. |
116
+ | `src/loom/etl/declarative` | `FromTable`, `FromFile`, `IntoTable`, `IntoFile`, predicate DSL, and `params` proxy. |
117
+ | `src/loom/etl/schema` | Backend-agnostic schema model (`LoomDtype`, `ColumnSchema`, `TableRef`). |
118
+ | `src/loom/etl/storage` | Storage config, table/file locators, and route resolution. |
119
+ | `src/loom/etl/compiler` | Compile-time validation and execution plan builder. |
120
+ | `src/loom/etl/runner` | `ETLRunner` entry point and YAML config loader. |
121
+ | `src/loom/etl/checkpoint` | Step-level checkpoint store for incremental re-runs. |
122
+ | `src/loom/etl/observability` | Run/step observers, OTEL sink, structlog sink, and execution records. |
123
+ | `src/loom/etl/backends/polars` | Polars + Delta Lake reader, writer, and schema aligner. |
124
+ | `src/loom/etl/backends/spark` | Spark + Delta reader, writer, and schema aligner. |
125
+ | `src/loom/etl/testing` | `PolarsStepRunner`, `SparkStepRunner`, `ETLScenario`, and test stubs. |
91
126
 
92
127
  ## Quick start
93
128
 
@@ -1,8 +1,6 @@
1
- <div style="width:100%;background:#fff;padding:4px 0;box-sizing:border-box;">
2
- <p align="center" style="margin:0;">
3
- <img src="docs/_static/logo-transparent.png" alt="loom-kernel" style="display:block;width:100%;max-width:none;max-height:220px;height:auto;object-fit:contain;margin:0 auto;" />
4
- </p>
5
- </div>
1
+ <p align="center">
2
+ <img src="docs/_static/logo-transparent.png" alt="loom-kernel" width="160" style="background:#ffffff;border-radius:6px;padding:8px 20px;" />
3
+ </p>
6
4
 
7
5
  # loom-kernel
8
6
 
@@ -37,7 +35,8 @@ infrastructure (DB, cache, transport) without breaking business logic.
37
35
 
38
36
  - Usage guides and architecture docs are available in the `docs/` site.
39
37
  - API reference is autogenerated from public docstrings.
40
- - End-to-end demo application: [`dummy-loom`](https://github.com/the-reacher-data/dummy-loom).
38
+ - End-to-end REST demo: [`dummy-loom`](https://github.com/the-reacher-data/dummy-loom).
39
+ - End-to-end ETL demo: [`dummy-loom-etl`](https://github.com/the-reacher-data/dummy-loom-etl) — full Polars and Spark pipeline examples.
41
40
 
42
41
  ## Main subpaths
43
42
 
@@ -49,10 +48,23 @@ infrastructure (DB, cache, transport) without breaking business logic.
49
48
  | `src/loom/core/repository/sqlalchemy` | Concrete async SQLAlchemy repository implementation. |
50
49
  | `src/loom/core/model` | Base model, fields, relations, and entity introspection. |
51
50
  | `src/loom/core/cache` | Decorators and cached repository with dependency invalidation. |
51
+ | `src/loom/core/config` | YAML config loader with cloud URI support and pluggable resolvers. |
52
52
  | `src/loom/rest` | Framework-agnostic REST model and route compiler. |
53
53
  | `src/loom/rest/fastapi` | Direct FastAPI integration (auto wiring and runtime router). |
54
54
  | `src/loom/prometheus` | Middleware and adapter for runtime metrics. |
55
55
  | `src/loom/testing` | Harnesses for unit/integration tests and golden tests. |
56
+ | `src/loom/etl` | Declarative ETL subsystem — pipelines, Polars/Spark backends, observability. |
57
+ | `src/loom/etl/pipeline` | `ETLStep`, `ETLProcess`, `ETLPipeline`, `StepSQL`, and `ETLParams`. |
58
+ | `src/loom/etl/declarative` | `FromTable`, `FromFile`, `IntoTable`, `IntoFile`, predicate DSL, and `params` proxy. |
59
+ | `src/loom/etl/schema` | Backend-agnostic schema model (`LoomDtype`, `ColumnSchema`, `TableRef`). |
60
+ | `src/loom/etl/storage` | Storage config, table/file locators, and route resolution. |
61
+ | `src/loom/etl/compiler` | Compile-time validation and execution plan builder. |
62
+ | `src/loom/etl/runner` | `ETLRunner` entry point and YAML config loader. |
63
+ | `src/loom/etl/checkpoint` | Step-level checkpoint store for incremental re-runs. |
64
+ | `src/loom/etl/observability` | Run/step observers, OTEL sink, structlog sink, and execution records. |
65
+ | `src/loom/etl/backends/polars` | Polars + Delta Lake reader, writer, and schema aligner. |
66
+ | `src/loom/etl/backends/spark` | Spark + Delta reader, writer, and schema aligner. |
67
+ | `src/loom/etl/testing` | `PolarsStepRunner`, `SparkStepRunner`, `ETLScenario`, and test stubs. |
56
68
 
57
69
  ## Quick start
58
70
 
@@ -0,0 +1,13 @@
1
+ .loom-hero {
2
+ padding: 1rem 0 1.5rem;
3
+ text-align: center;
4
+ }
5
+
6
+ .loom-hero img {
7
+ display: inline-block;
8
+ width: 160px;
9
+ height: auto;
10
+ background: #ffffff;
11
+ border-radius: 6px;
12
+ padding: 8px 20px;
13
+ }
@@ -6,6 +6,7 @@ import os
6
6
  import sys
7
7
  from datetime import datetime
8
8
  from pathlib import Path
9
+ from typing import Any
9
10
 
10
11
  ROOT = Path(__file__).resolve().parents[1]
11
12
  SRC = ROOT / "src"
@@ -52,7 +53,14 @@ napoleon_google_docstring = True
52
53
  napoleon_numpy_docstring = False
53
54
 
54
55
 
55
- def _skip_duplicate_reexports(app, what, name, obj, skip, options):
56
+ def _skip_duplicate_reexports(
57
+ app: Any,
58
+ what: str,
59
+ name: str,
60
+ obj: Any,
61
+ skip: bool,
62
+ options: Any,
63
+ ) -> bool:
56
64
  """Skip known re-exported symbols that duplicate canonical API objects."""
57
65
  del what, obj, options
58
66
  current_module = app.env.temp_data.get("autodoc:module")
@@ -80,16 +88,24 @@ intersphinx_mapping = {
80
88
  # Optional dependencies are mocked to keep docs builds lightweight and stable.
81
89
  autodoc_mock_imports = [
82
90
  "aiocache",
91
+ "celery",
92
+ "deltalake",
83
93
  "fastapi",
94
+ "fsspec",
95
+ "kombu",
84
96
  "omegaconf",
97
+ "polars",
98
+ "pyarrow",
85
99
  "prometheus_client",
86
100
  "pydantic",
87
101
  "pyspark",
102
+ "redis",
88
103
  "sqlalchemy",
104
+ "starlette",
89
105
  "uvicorn",
90
106
  ]
91
107
 
92
108
 
93
- def setup(app):
109
+ def setup(app: Any) -> None:
94
110
  """Register Sphinx hooks."""
95
111
  app.connect("autodoc-skip-member", _skip_duplicate_reexports)