loom-kernel 0.0.0__tar.gz → 0.2.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.
- loom_kernel-0.2.0/.github/workflows/ci-main.yml +113 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/.github/workflows/ci-pr.yml +78 -19
- loom_kernel-0.2.0/.github/workflows/docs.yml +82 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/.github/workflows/release.yml +8 -8
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/.gitignore +7 -2
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/.pre-commit-config.yaml +8 -1
- loom_kernel-0.2.0/.readthedocs.yaml +15 -0
- loom_kernel-0.2.0/CHANGELOG.md +120 -0
- loom_kernel-0.2.0/CHANGELOG_RELEASE.md +125 -0
- loom_kernel-0.2.0/PKG-INFO +459 -0
- loom_kernel-0.2.0/README.md +424 -0
- loom_kernel-0.2.0/codecov.yml +28 -0
- loom_kernel-0.2.0/docs/_static/custom.css +11 -0
- loom_kernel-0.2.0/docs/_static/logo-transparent.png +0 -0
- loom_kernel-0.2.0/docs/_static/logo.svg +4 -0
- loom_kernel-0.2.0/docs/architecture/adr/README.md +8 -0
- loom_kernel-0.2.0/docs/architecture/clean-architecture.md +10 -0
- loom_kernel-0.2.0/docs/architecture/overview.md +9 -0
- loom_kernel-0.2.0/docs/conf.py +95 -0
- loom_kernel-0.2.0/docs/examples-repo/index.md +477 -0
- loom_kernel-0.2.0/docs/guides/autocrud.md +166 -0
- loom_kernel-0.2.0/docs/guides/celery.md +538 -0
- loom_kernel-0.2.0/docs/guides/fake-repo-examples.md +28 -0
- loom_kernel-0.2.0/docs/guides/quickstart.md +405 -0
- loom_kernel-0.2.0/docs/guides/use-case-dsl.md +474 -0
- loom_kernel-0.2.0/docs/index.rst +41 -0
- loom_kernel-0.2.0/docs/reference/api/core.rst +32 -0
- loom_kernel-0.2.0/docs/reference/api/repository.rst +31 -0
- loom_kernel-0.2.0/docs/reference/api/rest.rst +24 -0
- loom_kernel-0.2.0/docs/reference/api/testing.rst +10 -0
- loom_kernel-0.2.0/docs/reference/index.rst +13 -0
- loom_kernel-0.2.0/docs/requirements.txt +5 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/pyproject.toml +35 -6
- loom_kernel-0.2.0/sonar-project.properties +131 -0
- loom_kernel-0.2.0/src/loom/__init__.py +1 -0
- loom_kernel-0.2.0/src/loom/celery/__init__.py +20 -0
- loom_kernel-0.2.0/src/loom/celery/auto.py +45 -0
- loom_kernel-0.2.0/src/loom/celery/bootstrap.py +776 -0
- loom_kernel-0.2.0/src/loom/celery/config.py +199 -0
- loom_kernel-0.2.0/src/loom/celery/constants.py +22 -0
- loom_kernel-0.2.0/src/loom/celery/event_loop.py +158 -0
- loom_kernel-0.2.0/src/loom/celery/runner.py +398 -0
- loom_kernel-0.2.0/src/loom/celery/service.py +406 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/backend/__init__.py +6 -0
- loom_kernel-0.2.0/src/loom/core/backend/core_model.py +426 -0
- loom_kernel-0.2.0/src/loom/core/backend/sqlalchemy.py +909 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/bootstrap/__init__.py +8 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/bootstrap/bootstrap.py +15 -5
- loom_kernel-0.2.0/src/loom/core/bootstrap/kernel.py +100 -0
- loom_kernel-0.2.0/src/loom/core/cache/abc/config.py +135 -0
- loom_kernel-0.2.0/src/loom/core/cache/gateway.py +280 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/repository.py +154 -21
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/serializer.py +1 -0
- loom_kernel-0.2.0/src/loom/core/command/base.py +151 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/command/field.py +1 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/command/introspection.py +3 -15
- loom_kernel-0.2.0/src/loom/core/config/keys.py +24 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/config/loader.py +92 -29
- loom_kernel-0.2.0/src/loom/core/contracts/__init__.py +1 -0
- loom_kernel-0.2.0/src/loom/core/contracts/manifest.py +38 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/di/container.py +43 -28
- loom_kernel-0.2.0/src/loom/core/discovery/_utils.py +176 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/discovery/interfaces.py +17 -11
- loom_kernel-0.2.0/src/loom/core/discovery/manifest.py +87 -0
- loom_kernel-0.2.0/src/loom/core/discovery/modules.py +45 -0
- loom_kernel-0.2.0/src/loom/core/engine/compilable.py +42 -0
- loom_kernel-0.2.0/src/loom/core/engine/compiler.py +436 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/engine/events.py +5 -0
- loom_kernel-0.2.0/src/loom/core/engine/executor.py +673 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/engine/plan.py +52 -6
- loom_kernel-0.2.0/src/loom/core/errors/codes.py +32 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/errors/errors.py +8 -6
- loom_kernel-0.2.0/src/loom/core/job/__init__.py +18 -0
- loom_kernel-0.2.0/src/loom/core/job/callback.py +70 -0
- loom_kernel-0.2.0/src/loom/core/job/context.py +69 -0
- loom_kernel-0.2.0/src/loom/core/job/handle.py +186 -0
- loom_kernel-0.2.0/src/loom/core/job/job.py +82 -0
- loom_kernel-0.2.0/src/loom/core/job/service.py +327 -0
- loom_kernel-0.2.0/src/loom/core/logger/__init__.py +39 -0
- loom_kernel-0.2.0/src/loom/core/logger/config.py +300 -0
- loom_kernel-0.2.0/src/loom/core/logger/registry.py +40 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/logger/structlogger.py +20 -20
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/__init__.py +4 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/base.py +45 -23
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/field.py +3 -3
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/introspection.py +27 -32
- loom_kernel-0.2.0/src/loom/core/model/projection.py +56 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/timestamped.py +2 -1
- loom_kernel-0.2.0/src/loom/core/projection/__init__.py +23 -0
- loom_kernel-0.2.0/src/loom/core/projection/loaders.py +265 -0
- loom_kernel-0.2.0/src/loom/core/projection/runtime.py +291 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/abc/repo_for.py +32 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/abc/repository.py +31 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/__init__.py +12 -4
- loom_kernel-0.2.0/src/loom/core/repository/sqlalchemy/integrity.py +185 -0
- loom_kernel-0.2.0/src/loom/core/repository/sqlalchemy/loaders.py +134 -0
- loom_kernel-0.2.0/src/loom/core/repository/sqlalchemy/mixins.py +505 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +44 -40
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +1 -3
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +17 -23
- loom_kernel-0.2.0/src/loom/core/repository/sqlalchemy/registry.py +125 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/session_manager.py +2 -2
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/uow.py +4 -3
- loom_kernel-0.2.0/src/loom/core/response/__init__.py +5 -0
- loom_kernel-0.2.0/src/loom/core/response/base.py +17 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/transport/adapter.py +1 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/uow/abc.py +6 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/uow/context.py +1 -3
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/use_case/__init__.py +6 -3
- loom_kernel-0.2.0/src/loom/core/use_case/_predicates.py +61 -0
- loom_kernel-0.2.0/src/loom/core/use_case/compute.py +120 -0
- loom_kernel-0.2.0/src/loom/core/use_case/constants.py +27 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/use_case/factory.py +11 -6
- loom_kernel-0.2.0/src/loom/core/use_case/field_ref.py +83 -0
- loom_kernel-0.2.0/src/loom/core/use_case/invoker.py +120 -0
- loom_kernel-0.2.0/src/loom/core/use_case/keys.py +55 -0
- loom_kernel-0.2.0/src/loom/core/use_case/markers.py +235 -0
- loom_kernel-0.2.0/src/loom/core/use_case/registry.py +88 -0
- loom_kernel-0.2.0/src/loom/core/use_case/rule.py +194 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/use_case/use_case.py +14 -6
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/prometheus/adapter.py +64 -41
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/prometheus/middleware.py +19 -27
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/adapter.py +4 -8
- loom_kernel-0.2.0/src/loom/rest/autocrud.py +457 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/compiler.py +43 -3
- loom_kernel-0.2.0/src/loom/rest/constants.py +29 -0
- loom_kernel-0.2.0/src/loom/rest/errors.py +98 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/fastapi/app.py +53 -3
- loom_kernel-0.2.0/src/loom/rest/fastapi/auto.py +455 -0
- loom_kernel-0.2.0/src/loom/rest/fastapi/openapi.py +376 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/fastapi/router_runtime.py +188 -42
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/middleware.py +4 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/model.py +55 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/rest_adapter.py +1 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/testing/golden.py +17 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/testing/http_harness.py +5 -6
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/testing/in_memory.py +97 -6
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/testing/repository_harness.py +6 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/testing/runner.py +5 -5
- loom_kernel-0.2.0/tests/integration/celery_bootstrap/config/conf.celery.integration.yaml +51 -0
- loom_kernel-0.2.0/tests/integration/celery_bootstrap/test_auto_create_app_integration.py +402 -0
- loom_kernel-0.2.0/tests/integration/celery_bootstrap/test_bootstrap_worker.py +186 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/core/repository/sqlalchemy/test_cache_integration.py +28 -8
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/core/repository/sqlalchemy/test_repository_integration.py +90 -2
- loom_kernel-0.2.0/tests/integration/core/rest/test_auto_interface_integration.py +227 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/core/rest/test_fastapi_app_integration.py +23 -10
- loom_kernel-0.2.0/tests/integration/core/use_case/test_custom_repository_integration.py +103 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/core/use_case/test_use_case_crud_integration.py +6 -10
- loom_kernel-0.2.0/tests/integration/fake_repo/config/conf.interfaces.yaml +14 -0
- loom_kernel-0.2.0/tests/integration/fake_repo/config/conf.manifest.yaml +8 -0
- loom_kernel-0.2.0/tests/integration/fake_repo/config/conf.modules.yaml +15 -0
- loom_kernel-0.0.0/tests/integration/fake_repo/src/config/conf.manifest.yaml → loom_kernel-0.2.0/tests/integration/fake_repo/config/conf.yaml +1 -5
- loom_kernel-0.2.0/tests/integration/fake_repo/main.py +25 -0
- loom_kernel-0.2.0/tests/integration/fake_repo/manifest.py +28 -0
- {loom_kernel-0.0.0/tests/integration/fake_repo/src/app → loom_kernel-0.2.0/tests/integration/fake_repo}/product/interface.py +9 -4
- loom_kernel-0.2.0/tests/integration/fake_repo/product/jobs.py +17 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/product/model.py +4 -11
- loom_kernel-0.2.0/tests/integration/fake_repo/product/repository.py +37 -0
- loom_kernel-0.2.0/tests/integration/fake_repo/product/repository_contract.py +14 -0
- loom_kernel-0.2.0/tests/integration/fake_repo/product/use_cases.py +162 -0
- loom_kernel-0.2.0/tests/unit/celery_bootstrap/test_bootstrap.py +436 -0
- loom_kernel-0.2.0/tests/unit/celery_bootstrap/test_event_loop.py +182 -0
- loom_kernel-0.2.0/tests/unit/celery_jobs/test_auto.py +73 -0
- loom_kernel-0.2.0/tests/unit/celery_jobs/test_celery_service.py +418 -0
- loom_kernel-0.2.0/tests/unit/celery_jobs/test_config.py +242 -0
- loom_kernel-0.2.0/tests/unit/celery_jobs/test_runner.py +599 -0
- loom_kernel-0.2.0/tests/unit/core/backend/test_backend_compiler.py +246 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/bootstrap/test_bootstrap.py +8 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/bootstrap/test_bootstrap_metrics.py +20 -14
- loom_kernel-0.2.0/tests/unit/core/bootstrap/test_kernel.py +58 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/cache/test_cached_repository.py +142 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/command/test_command_base.py +13 -10
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/command/test_command_patch.py +1 -3
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/config/test_config.py +96 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/di/test_container.py +15 -0
- loom_kernel-0.2.0/tests/unit/core/discovery/test_manifest.py +50 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/engine/test_compiler.py +79 -12
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/engine/test_executor.py +277 -5
- loom_kernel-0.2.0/tests/unit/core/engine/test_executor_uow.py +282 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/engine/test_metrics.py +2 -2
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/engine/test_plan.py +50 -6
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/errors/test_errors.py +10 -9
- loom_kernel-0.2.0/tests/unit/core/job/conftest.py +23 -0
- loom_kernel-0.2.0/tests/unit/core/job/test_callback.py +79 -0
- loom_kernel-0.2.0/tests/unit/core/job/test_context.py +86 -0
- loom_kernel-0.2.0/tests/unit/core/job/test_handle.py +154 -0
- loom_kernel-0.2.0/tests/unit/core/job/test_inline_service.py +171 -0
- loom_kernel-0.2.0/tests/unit/core/job/test_job.py +124 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/logger/test_registry.py +7 -7
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/model/test_timestamped.py +7 -2
- loom_kernel-0.2.0/tests/unit/core/projection/test_runtime.py +191 -0
- loom_kernel-0.2.0/tests/unit/core/repository/sqlalchemy/test_loaders.py +113 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/repository/sqlalchemy/test_repository.py +89 -1
- loom_kernel-0.2.0/tests/unit/core/tracing/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/tracing/test_context.py +2 -1
- loom_kernel-0.2.0/tests/unit/core/uow/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/uow/test_executor_uow.py +13 -17
- loom_kernel-0.2.0/tests/unit/core/use_case/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/use_case/test_compute.py +48 -10
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/use_case/test_field_ref.py +9 -1
- loom_kernel-0.2.0/tests/unit/core/use_case/test_invoker.py +152 -0
- loom_kernel-0.2.0/tests/unit/core/use_case/test_markers.py +54 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/use_case/test_rule.py +77 -7
- loom_kernel-0.2.0/tests/unit/prometheus/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/prometheus/test_adapter.py +8 -7
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/prometheus/test_middleware.py +30 -8
- loom_kernel-0.2.0/tests/unit/rest/__init__.py +0 -0
- loom_kernel-0.2.0/tests/unit/rest/test_autocrud.py +363 -0
- loom_kernel-0.2.0/tests/unit/rest/test_fastapi_auto_logger.py +128 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/rest/test_pydantic_adapter.py +2 -6
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/rest/test_rest_adapter.py +2 -1
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/rest/test_rest_compiler.py +86 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/rest/test_rest_model.py +74 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/rest/test_router_runtime.py +302 -2
- loom_kernel-0.2.0/tests/unit/testing/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/testing/test_golden.py +30 -2
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/testing/test_in_memory.py +50 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/testing/test_runner.py +2 -2
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/uv.lock +295 -15
- loom_kernel-0.0.0/.github/workflows/ci-main.yml +0 -49
- loom_kernel-0.0.0/CHANGELOG_RELEASE.md +0 -3
- loom_kernel-0.0.0/PKG-INFO +0 -165
- loom_kernel-0.0.0/README.md +0 -141
- loom_kernel-0.0.0/src/loom/__init__.py +0 -1
- loom_kernel-0.0.0/src/loom/core/backend/sqlalchemy.py +0 -281
- loom_kernel-0.0.0/src/loom/core/cache/abc/config.py +0 -59
- loom_kernel-0.0.0/src/loom/core/cache/gateway.py +0 -151
- loom_kernel-0.0.0/src/loom/core/command/base.py +0 -60
- loom_kernel-0.0.0/src/loom/core/discovery/_utils.py +0 -77
- loom_kernel-0.0.0/src/loom/core/discovery/manifest.py +0 -43
- loom_kernel-0.0.0/src/loom/core/discovery/modules.py +0 -25
- loom_kernel-0.0.0/src/loom/core/engine/compiler.py +0 -207
- loom_kernel-0.0.0/src/loom/core/engine/executor.py +0 -384
- loom_kernel-0.0.0/src/loom/core/logger/__init__.py +0 -12
- loom_kernel-0.0.0/src/loom/core/logger/registry.py +0 -21
- loom_kernel-0.0.0/src/loom/core/logger/std.py +0 -86
- loom_kernel-0.0.0/src/loom/core/model/projection.py +0 -36
- loom_kernel-0.0.0/src/loom/core/repository/sqlalchemy/loaders.py +0 -235
- loom_kernel-0.0.0/src/loom/core/repository/sqlalchemy/mixins.py +0 -436
- loom_kernel-0.0.0/src/loom/core/use_case/compute.py +0 -109
- loom_kernel-0.0.0/src/loom/core/use_case/field_ref.py +0 -45
- loom_kernel-0.0.0/src/loom/core/use_case/markers.py +0 -78
- loom_kernel-0.0.0/src/loom/core/use_case/rule.py +0 -147
- loom_kernel-0.0.0/src/loom/rest/errors.py +0 -58
- loom_kernel-0.0.0/src/loom/rest/fastapi/auto.py +0 -203
- loom_kernel-0.0.0/tests/integration/fake_repo/config/conf.yaml +0 -24
- loom_kernel-0.0.0/tests/integration/fake_repo/main.py +0 -12
- loom_kernel-0.0.0/tests/integration/fake_repo/product/interface.py +0 -44
- loom_kernel-0.0.0/tests/integration/fake_repo/product/use_cases.py +0 -38
- loom_kernel-0.0.0/tests/integration/fake_repo/src/__init__.py +0 -1
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/__init__.py +0 -1
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/manifest.py +0 -31
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/__init__.py +0 -3
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/category/__init__.py +0 -1
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/category/model.py +0 -10
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/category/schemas.py +0 -7
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/model.py +0 -68
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/relations.py +0 -17
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/review/__init__.py +0 -1
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/review/model.py +0 -12
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/review/schemas.py +0 -9
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/schemas.py +0 -13
- loom_kernel-0.0.0/tests/integration/fake_repo/src/app/product/use_cases.py +0 -43
- loom_kernel-0.0.0/tests/integration/fake_repo/src/config/conf.interfaces.yaml +0 -24
- loom_kernel-0.0.0/tests/integration/fake_repo/src/config/conf.modules.yaml +0 -28
- loom_kernel-0.0.0/tests/unit/core/backend/test_backend_compiler.py +0 -85
- loom_kernel-0.0.0/tests/unit/core/use_case/test_markers.py +0 -26
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/LICENSE +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/Makefile +0 -0
- {loom_kernel-0.0.0/tests/golden/baselines → loom_kernel-0.2.0/docs/_static}/.gitkeep +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/backend/protocol.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/abc/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/abc/backend.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/abc/dependency.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/codec.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/decorators.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/dependency.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/cache/keys.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/command/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/command/adapter.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/config/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/config/errors.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/config/model.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/di/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/di/scope.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/discovery/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/discovery/base.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/engine/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/engine/metrics.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/errors/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/logger/abc.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/enums.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/relation.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/types.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/model/types_postgres.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/abc/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/abc/query.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/mutation.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/tracing/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/tracing/context.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/transport/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/core/uow/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/prometheus/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/fastapi/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/rest/fastapi/response.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/src/loom/testing/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/conftest.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/golden/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/golden/outputs → loom_kernel-0.2.0/tests/golden/baselines}/.gitkeep +0 -0
- {loom_kernel-0.0.0/tests/golden/plans → loom_kernel-0.2.0/tests/golden/outputs}/.gitkeep +0 -0
- /loom_kernel-0.0.0/tests/integration/__init__.py → /loom_kernel-0.2.0/tests/golden/plans/.gitkeep +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/helpers/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/integration/core → loom_kernel-0.2.0/tests/integration}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/integration/core/repository → loom_kernel-0.2.0/tests/integration/celery_bootstrap}/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/conftest.py +0 -0
- {loom_kernel-0.0.0/tests/integration/core/repository/sqlalchemy → loom_kernel-0.2.0/tests/integration/core}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/integration/fake_repo → loom_kernel-0.2.0/tests/integration/core/repository}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/integration/fake_repo/product/category → loom_kernel-0.2.0/tests/integration/core/repository/sqlalchemy}/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/core/repository/sqlalchemy/conftest.py +0 -0
- {loom_kernel-0.0.0/tests/integration/fake_repo/product/review → loom_kernel-0.2.0/tests/integration/core/rest}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/backend → loom_kernel-0.2.0/tests/integration/fake_repo}/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/config/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/product/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/bootstrap → loom_kernel-0.2.0/tests/integration/fake_repo/product/category}/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/product/category/model.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/product/category/schemas.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/product/relations.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/command → loom_kernel-0.2.0/tests/integration/fake_repo/product/review}/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/product/review/model.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/product/review/schemas.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/integration/fake_repo/product/schemas.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/config → loom_kernel-0.2.0/tests/unit/celery_bootstrap}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/di → loom_kernel-0.2.0/tests/unit/celery_jobs}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/engine → loom_kernel-0.2.0/tests/unit/core/backend}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/errors → loom_kernel-0.2.0/tests/unit/core/bootstrap}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/model → loom_kernel-0.2.0/tests/unit/core/command}/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/command/test_command_field.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/command/test_introspection.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/tracing → loom_kernel-0.2.0/tests/unit/core/config}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/uow → loom_kernel-0.2.0/tests/unit/core/di}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/core/use_case → loom_kernel-0.2.0/tests/unit/core/engine}/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/engine/test_executor_trace.py +0 -0
- {loom_kernel-0.0.0/tests/unit/prometheus → loom_kernel-0.2.0/tests/unit/core/errors}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/rest → loom_kernel-0.2.0/tests/unit/core/job}/__init__.py +0 -0
- {loom_kernel-0.0.0/tests/unit/testing → loom_kernel-0.2.0/tests/unit/core/model}/__init__.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/model/test_model.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/repository/abc/conftest.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/repository/abc/test_query.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/repository/abc/test_repository_contract.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/repository/sqlalchemy/conftest.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/repository/sqlalchemy/test_transactional.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/uow/test_sqlalchemy_uow.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/uow/test_uow_protocols.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/use_case/test_factory.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/core/use_case/test_use_case.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/rest/test_middleware.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/rest/test_response.py +0 -0
- {loom_kernel-0.0.0 → loom_kernel-0.2.0}/tests/unit/testing/test_http_harness.py +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
name: ci-main
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["master"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
validate:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
env:
|
|
14
|
+
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
15
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
16
|
+
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
|
17
|
+
SONAR_PROJECT_KEY: ${{ vars.SONAR_PROJECT_KEY }}
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
|
|
23
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.11"
|
|
26
|
+
|
|
27
|
+
- uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
28
|
+
|
|
29
|
+
- name: Quality report (strict)
|
|
30
|
+
uses: the-reacher-data/loom-actions/actions/python/quality-report@e731576f4f9cf4ec2b36fddfc895d328c856d29f # v1
|
|
31
|
+
with:
|
|
32
|
+
src-dir: src
|
|
33
|
+
test-dir: tests
|
|
34
|
+
coverage-threshold: "80"
|
|
35
|
+
fail-on-quality: "any"
|
|
36
|
+
fail-on-security: "high"
|
|
37
|
+
include-security: "true"
|
|
38
|
+
|
|
39
|
+
- name: Run pytest with coverage and JUnit output
|
|
40
|
+
shell: bash
|
|
41
|
+
run: |
|
|
42
|
+
set -euo pipefail
|
|
43
|
+
uv run --with pytest-cov pytest --cov --junitxml=junit.xml -o junit_family=legacy
|
|
44
|
+
|
|
45
|
+
- name: Upload coverage to Codecov
|
|
46
|
+
if: ${{ hashFiles('coverage.xml') != '' }}
|
|
47
|
+
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
|
|
48
|
+
with:
|
|
49
|
+
files: ./coverage.xml
|
|
50
|
+
fail_ci_if_error: false
|
|
51
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
52
|
+
|
|
53
|
+
- name: Upload test results to Codecov
|
|
54
|
+
if: ${{ !cancelled() && hashFiles('junit.xml') != '' }}
|
|
55
|
+
uses: codecov/test-results-action@0fa95f0e1eeaafde2c782583b36b28ad0d8c77d3 # v1
|
|
56
|
+
with:
|
|
57
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
58
|
+
|
|
59
|
+
- name: SonarQube scan
|
|
60
|
+
if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' && env.SONAR_PROJECT_KEY != '' }}
|
|
61
|
+
uses: SonarSource/sonarqube-scan-action@2f77a1ec69fb1d595b06f35ab27e97605bdef703 # v5
|
|
62
|
+
with:
|
|
63
|
+
args: >
|
|
64
|
+
-Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }}
|
|
65
|
+
env:
|
|
66
|
+
SONAR_TOKEN: ${{ env.SONAR_TOKEN }}
|
|
67
|
+
SONAR_HOST_URL: ${{ env.SONAR_HOST_URL }}
|
|
68
|
+
|
|
69
|
+
- name: Snyk dependency monitor
|
|
70
|
+
if: ${{ env.SNYK_TOKEN != '' }}
|
|
71
|
+
uses: snyk/actions/setup@9adf32b1121593767fc3c057af55b55db032dc04 # master
|
|
72
|
+
env:
|
|
73
|
+
SNYK_TOKEN: ${{ env.SNYK_TOKEN }}
|
|
74
|
+
|
|
75
|
+
- name: Snyk monitor by dependency scope (core/dev/extras)
|
|
76
|
+
if: ${{ env.SNYK_TOKEN != '' }}
|
|
77
|
+
shell: bash
|
|
78
|
+
env:
|
|
79
|
+
SNYK_TOKEN: ${{ env.SNYK_TOKEN }}
|
|
80
|
+
run: |
|
|
81
|
+
set -euo pipefail
|
|
82
|
+
|
|
83
|
+
MANIFEST_DIR="$RUNNER_TEMP/snyk-manifests"
|
|
84
|
+
mkdir -p "$MANIFEST_DIR"
|
|
85
|
+
|
|
86
|
+
uv export --frozen --no-default-groups --no-dev --no-hashes --no-emit-project \
|
|
87
|
+
-o "$MANIFEST_DIR/requirements-core.txt"
|
|
88
|
+
uv export --frozen --only-group dev --no-hashes --no-emit-project \
|
|
89
|
+
-o "$MANIFEST_DIR/requirements-dev.txt"
|
|
90
|
+
|
|
91
|
+
for extra in rest sqlalchemy config cache pyspark prometheus celery; do
|
|
92
|
+
uv export --frozen --no-default-groups --no-dev --extra "$extra" \
|
|
93
|
+
--no-hashes --no-emit-project \
|
|
94
|
+
-o "$MANIFEST_DIR/requirements-extra-${extra}.txt"
|
|
95
|
+
done
|
|
96
|
+
|
|
97
|
+
python -m pip install -r "$MANIFEST_DIR/requirements-core.txt"
|
|
98
|
+
snyk monitor --skip-unresolved \
|
|
99
|
+
--file="$MANIFEST_DIR/requirements-core.txt" --package-manager=pip \
|
|
100
|
+
--project-name="loom-py/core" --target-reference="${GITHUB_REF_NAME:-master}"
|
|
101
|
+
python -m pip install -r "$MANIFEST_DIR/requirements-dev.txt"
|
|
102
|
+
snyk monitor --skip-unresolved \
|
|
103
|
+
--file="$MANIFEST_DIR/requirements-dev.txt" --package-manager=pip \
|
|
104
|
+
--project-name="loom-py/dev" --target-reference="${GITHUB_REF_NAME:-master}"
|
|
105
|
+
|
|
106
|
+
for extra in rest sqlalchemy config cache pyspark prometheus celery; do
|
|
107
|
+
python -m pip install -r "$MANIFEST_DIR/requirements-extra-${extra}.txt"
|
|
108
|
+
snyk monitor --skip-unresolved \
|
|
109
|
+
--file="$MANIFEST_DIR/requirements-extra-${extra}.txt" \
|
|
110
|
+
--package-manager=pip \
|
|
111
|
+
--project-name="loom-py/extra-${extra}" \
|
|
112
|
+
--target-reference="${GITHUB_REF_NAME:-master}"
|
|
113
|
+
done
|
|
@@ -15,17 +15,20 @@ jobs:
|
|
|
15
15
|
env:
|
|
16
16
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
17
17
|
TEST_PYPI_API_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
|
18
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
19
|
+
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
|
20
|
+
SONAR_PROJECT_KEY: ${{ vars.SONAR_PROJECT_KEY }}
|
|
18
21
|
steps:
|
|
19
|
-
- uses: actions/checkout@v4
|
|
22
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
20
23
|
with:
|
|
21
24
|
fetch-depth: 0
|
|
22
25
|
ref: ${{ github.event.pull_request.head.sha }}
|
|
23
26
|
|
|
24
|
-
- uses: actions/setup-python@v5
|
|
27
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
25
28
|
with:
|
|
26
29
|
python-version: "3.11"
|
|
27
30
|
|
|
28
|
-
- uses: astral-sh/setup-uv@v3
|
|
31
|
+
- uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
29
32
|
|
|
30
33
|
- name: Configure uv environment path
|
|
31
34
|
shell: bash
|
|
@@ -43,7 +46,7 @@ jobs:
|
|
|
43
46
|
- name: Quality report (strict gate)
|
|
44
47
|
id: quality
|
|
45
48
|
continue-on-error: true
|
|
46
|
-
uses: the-reacher-data/loom-actions/actions/python/quality-report@v1
|
|
49
|
+
uses: the-reacher-data/loom-actions/actions/python/quality-report@e731576f4f9cf4ec2b36fddfc895d328c856d29f # v1
|
|
47
50
|
with:
|
|
48
51
|
src-dir: src
|
|
49
52
|
test-dir: tests
|
|
@@ -54,7 +57,7 @@ jobs:
|
|
|
54
57
|
|
|
55
58
|
- name: Publish PR quality comment
|
|
56
59
|
if: ${{ always() && steps.quality.outputs.report-file != '' }}
|
|
57
|
-
uses: the-reacher-data/loom-actions/actions/core/pr-comment-update@v1
|
|
60
|
+
uses: the-reacher-data/loom-actions/actions/core/pr-comment-update@e731576f4f9cf4ec2b36fddfc895d328c856d29f # v1
|
|
58
61
|
with:
|
|
59
62
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
60
63
|
tags: "<!-- loom-quality-report -->"
|
|
@@ -62,7 +65,7 @@ jobs:
|
|
|
62
65
|
|
|
63
66
|
- name: Compute candidate prerelease version
|
|
64
67
|
id: version
|
|
65
|
-
uses: the-reacher-data/loom-actions/actions/release/versioning-branch-semantic@v1
|
|
68
|
+
uses: the-reacher-data/loom-actions/actions/release/versioning-branch-semantic@e731576f4f9cf4ec2b36fddfc895d328c856d29f # v1
|
|
66
69
|
with:
|
|
67
70
|
branch: ${{ github.head_ref }}
|
|
68
71
|
prerelease: "true"
|
|
@@ -70,7 +73,7 @@ jobs:
|
|
|
70
73
|
- name: Generate changelog preview
|
|
71
74
|
id: changelog
|
|
72
75
|
continue-on-error: true
|
|
73
|
-
uses: the-reacher-data/loom-actions/actions/release/changelog-conventional-commit@v1
|
|
76
|
+
uses: the-reacher-data/loom-actions/actions/release/changelog-conventional-commit@e731576f4f9cf4ec2b36fddfc895d328c856d29f # v1
|
|
74
77
|
with:
|
|
75
78
|
mode: "pr"
|
|
76
79
|
branch: ${{ github.event.pull_request.head.sha }}
|
|
@@ -81,36 +84,92 @@ jobs:
|
|
|
81
84
|
|
|
82
85
|
- name: Publish PR changelog comment
|
|
83
86
|
if: ${{ steps.changelog.outcome == 'success' && steps.changelog.outputs.output_path != '' }}
|
|
84
|
-
uses: the-reacher-data/loom-actions/actions/core/pr-comment-update@v1
|
|
87
|
+
uses: the-reacher-data/loom-actions/actions/core/pr-comment-update@e731576f4f9cf4ec2b36fddfc895d328c856d29f # v1
|
|
85
88
|
with:
|
|
86
89
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
87
90
|
tags: "<!-- changelog-preview -->,<!-- branch-source:${{ github.head_ref }} -->"
|
|
88
91
|
body-file: ${{ steps.changelog.outputs.output_path }}
|
|
89
92
|
|
|
93
|
+
- name: Run pytest with coverage and JUnit output
|
|
94
|
+
shell: bash
|
|
95
|
+
run: |
|
|
96
|
+
set -euo pipefail
|
|
97
|
+
uv run --with pytest-cov pytest --cov --junitxml=junit.xml -o junit_family=legacy
|
|
98
|
+
|
|
90
99
|
- name: Upload coverage to Codecov
|
|
91
100
|
if: ${{ always() && hashFiles('coverage.xml') != '' }}
|
|
92
|
-
uses: codecov/codecov-action@v5
|
|
101
|
+
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
|
|
93
102
|
with:
|
|
94
103
|
files: ./coverage.xml
|
|
95
104
|
fail_ci_if_error: false
|
|
96
105
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
97
106
|
|
|
98
|
-
- name:
|
|
107
|
+
- name: Upload test results to Codecov
|
|
108
|
+
if: ${{ !cancelled() && hashFiles('junit.xml') != '' }}
|
|
109
|
+
uses: codecov/test-results-action@0fa95f0e1eeaafde2c782583b36b28ad0d8c77d3 # v1
|
|
110
|
+
with:
|
|
111
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
112
|
+
|
|
113
|
+
- name: SonarQube scan
|
|
114
|
+
if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' && env.SONAR_PROJECT_KEY != '' }}
|
|
115
|
+
uses: SonarSource/sonarqube-scan-action@2f77a1ec69fb1d595b06f35ab27e97605bdef703 # v5
|
|
116
|
+
with:
|
|
117
|
+
args: >
|
|
118
|
+
-Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }}
|
|
119
|
+
env:
|
|
120
|
+
SONAR_TOKEN: ${{ env.SONAR_TOKEN }}
|
|
121
|
+
SONAR_HOST_URL: ${{ env.SONAR_HOST_URL }}
|
|
122
|
+
|
|
123
|
+
- name: Setup Snyk CLI
|
|
124
|
+
if: ${{ env.SNYK_TOKEN != '' }}
|
|
125
|
+
uses: snyk/actions/setup@9adf32b1121593767fc3c057af55b55db032dc04 # master
|
|
126
|
+
|
|
127
|
+
- name: Snyk dependency scan by scope (core/dev/extras)
|
|
99
128
|
id: snyk
|
|
100
129
|
if: ${{ env.SNYK_TOKEN != '' }}
|
|
101
130
|
continue-on-error: true
|
|
102
|
-
|
|
103
|
-
with:
|
|
104
|
-
command: test
|
|
105
|
-
args: --severity-threshold=high --all-projects --sarif-file-output=snyk.sarif
|
|
131
|
+
shell: bash
|
|
106
132
|
env:
|
|
107
133
|
SNYK_TOKEN: ${{ env.SNYK_TOKEN }}
|
|
134
|
+
run: |
|
|
135
|
+
set -euo pipefail
|
|
108
136
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
137
|
+
MANIFEST_DIR="$RUNNER_TEMP/snyk-manifests"
|
|
138
|
+
mkdir -p "$MANIFEST_DIR"
|
|
139
|
+
|
|
140
|
+
uv export --frozen --no-default-groups --no-dev --no-hashes --no-emit-project \
|
|
141
|
+
-o "$MANIFEST_DIR/requirements-core.txt"
|
|
142
|
+
uv export --frozen --only-group dev --no-hashes --no-emit-project \
|
|
143
|
+
-o "$MANIFEST_DIR/requirements-dev.txt"
|
|
144
|
+
|
|
145
|
+
for extra in rest sqlalchemy config cache pyspark prometheus celery; do
|
|
146
|
+
uv export --frozen --no-default-groups --no-dev --extra "$extra" \
|
|
147
|
+
--no-hashes --no-emit-project \
|
|
148
|
+
-o "$MANIFEST_DIR/requirements-extra-${extra}.txt"
|
|
149
|
+
done
|
|
150
|
+
|
|
151
|
+
python -m pip install -r "$MANIFEST_DIR/requirements-core.txt"
|
|
152
|
+
snyk test --severity-threshold=high \
|
|
153
|
+
--skip-unresolved \
|
|
154
|
+
--file="$MANIFEST_DIR/requirements-core.txt" \
|
|
155
|
+
--package-manager=pip \
|
|
156
|
+
--project-name="loom-py/core"
|
|
157
|
+
|
|
158
|
+
python -m pip install -r "$MANIFEST_DIR/requirements-dev.txt"
|
|
159
|
+
snyk test --severity-threshold=high \
|
|
160
|
+
--skip-unresolved \
|
|
161
|
+
--file="$MANIFEST_DIR/requirements-dev.txt" \
|
|
162
|
+
--package-manager=pip \
|
|
163
|
+
--project-name="loom-py/dev"
|
|
164
|
+
|
|
165
|
+
for extra in rest sqlalchemy config cache pyspark prometheus celery; do
|
|
166
|
+
python -m pip install -r "$MANIFEST_DIR/requirements-extra-${extra}.txt"
|
|
167
|
+
snyk test --severity-threshold=high \
|
|
168
|
+
--skip-unresolved \
|
|
169
|
+
--file="$MANIFEST_DIR/requirements-extra-${extra}.txt" \
|
|
170
|
+
--package-manager=pip \
|
|
171
|
+
--project-name="loom-py/extra-${extra}"
|
|
172
|
+
done
|
|
114
173
|
|
|
115
174
|
- name: Publish prerelease package to TestPyPI
|
|
116
175
|
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && env.TEST_PYPI_API_TOKEN != '' && steps.version.outputs.deploy == 'true' }}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: ["master"]
|
|
6
|
+
paths:
|
|
7
|
+
- "docs/**"
|
|
8
|
+
- "src/**/*.py"
|
|
9
|
+
- "README.md"
|
|
10
|
+
- "pyproject.toml"
|
|
11
|
+
- ".github/workflows/docs.yml"
|
|
12
|
+
push:
|
|
13
|
+
branches: ["master"]
|
|
14
|
+
paths:
|
|
15
|
+
- "docs/**"
|
|
16
|
+
- "src/**/*.py"
|
|
17
|
+
- "README.md"
|
|
18
|
+
- "pyproject.toml"
|
|
19
|
+
- ".github/workflows/docs.yml"
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
|
|
22
|
+
# Prevent concurrent deploys; let an in-progress run finish.
|
|
23
|
+
concurrency:
|
|
24
|
+
group: pages
|
|
25
|
+
cancel-in-progress: false
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
build:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
# contents: read is scoped here — build does not need pages or id-token.
|
|
31
|
+
permissions:
|
|
32
|
+
contents: read
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
35
|
+
|
|
36
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
37
|
+
with:
|
|
38
|
+
python-version: "3.11"
|
|
39
|
+
|
|
40
|
+
- uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
41
|
+
|
|
42
|
+
- name: Build docs (strict)
|
|
43
|
+
shell: bash
|
|
44
|
+
run: |
|
|
45
|
+
set -euo pipefail
|
|
46
|
+
uv run \
|
|
47
|
+
--extra rest \
|
|
48
|
+
--extra sqlalchemy \
|
|
49
|
+
--extra cache \
|
|
50
|
+
--extra config \
|
|
51
|
+
--extra prometheus \
|
|
52
|
+
--with 'sphinx>=8.0' \
|
|
53
|
+
--with 'furo>=2024.8.6' \
|
|
54
|
+
--with 'myst-parser>=3.0' \
|
|
55
|
+
--with 'sphinx-copybutton>=0.5' \
|
|
56
|
+
--with 'sphinx-design>=0.6' \
|
|
57
|
+
sphinx-build -W -b html docs docs/_build/html
|
|
58
|
+
|
|
59
|
+
# upload-pages-artifact creates the zip format required by deploy-pages.
|
|
60
|
+
# Used instead of upload-artifact so the deploy job can consume it directly.
|
|
61
|
+
- name: Upload Pages artifact
|
|
62
|
+
uses: actions/upload-pages-artifact@v3
|
|
63
|
+
with:
|
|
64
|
+
path: docs/_build/html
|
|
65
|
+
|
|
66
|
+
deploy:
|
|
67
|
+
needs: build
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
# Only deploy on push to master, not on PRs.
|
|
70
|
+
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
|
71
|
+
# pages: write + id-token: write are required for OIDC-based Pages deployment.
|
|
72
|
+
# Scoped here — deploy does not need contents read.
|
|
73
|
+
permissions:
|
|
74
|
+
pages: write
|
|
75
|
+
id-token: write
|
|
76
|
+
environment:
|
|
77
|
+
name: github-pages
|
|
78
|
+
url: ${{ steps.deploy.outputs.page_url }}
|
|
79
|
+
steps:
|
|
80
|
+
- name: Deploy to GitHub Pages
|
|
81
|
+
id: deploy
|
|
82
|
+
uses: actions/deploy-pages@v4
|
|
@@ -27,15 +27,15 @@ jobs:
|
|
|
27
27
|
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
28
28
|
RELEASE_BRANCH: ${{ github.event_name == 'workflow_dispatch' && inputs.source_branch || github.event.pull_request.head.ref }}
|
|
29
29
|
steps:
|
|
30
|
-
- uses: actions/checkout@v4
|
|
30
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
31
31
|
with:
|
|
32
32
|
fetch-depth: 0
|
|
33
33
|
|
|
34
|
-
- uses: actions/setup-python@v5
|
|
34
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
35
35
|
with:
|
|
36
36
|
python-version: "3.11"
|
|
37
37
|
|
|
38
|
-
- uses: astral-sh/setup-uv@v3
|
|
38
|
+
- uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
39
39
|
|
|
40
40
|
- name: Configure uv environment path
|
|
41
41
|
shell: bash
|
|
@@ -45,7 +45,7 @@ jobs:
|
|
|
45
45
|
|
|
46
46
|
- name: Compute release version from merged branch
|
|
47
47
|
id: version
|
|
48
|
-
uses: the-reacher-data/loom-actions/actions/release/versioning-branch-semantic@v1
|
|
48
|
+
uses: the-reacher-data/loom-actions/actions/release/versioning-branch-semantic@e731576f4f9cf4ec2b36fddfc895d328c856d29f # v1
|
|
49
49
|
with:
|
|
50
50
|
branch: ${{ env.RELEASE_BRANCH }}
|
|
51
51
|
prerelease: "false"
|
|
@@ -53,7 +53,7 @@ jobs:
|
|
|
53
53
|
- name: Generate release changelog
|
|
54
54
|
id: changelog
|
|
55
55
|
if: ${{ steps.version.outputs.deploy == 'true' && github.event_name != 'workflow_dispatch' }}
|
|
56
|
-
uses: the-reacher-data/loom-actions/actions/release/changelog-conventional-commit@v1
|
|
56
|
+
uses: the-reacher-data/loom-actions/actions/release/changelog-conventional-commit@e731576f4f9cf4ec2b36fddfc895d328c856d29f # v1
|
|
57
57
|
with:
|
|
58
58
|
mode: "release"
|
|
59
59
|
branch: ${{ env.RELEASE_BRANCH }}
|
|
@@ -94,13 +94,13 @@ jobs:
|
|
|
94
94
|
|
|
95
95
|
- name: Publish package to PyPI (token mode)
|
|
96
96
|
if: ${{ steps.version.outputs.deploy == 'true' && env.PYPI_API_TOKEN != '' }}
|
|
97
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
97
|
+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
|
|
98
98
|
with:
|
|
99
99
|
password: ${{ env.PYPI_API_TOKEN }}
|
|
100
100
|
|
|
101
101
|
- name: Publish package to PyPI (trusted publisher)
|
|
102
102
|
if: ${{ steps.version.outputs.deploy == 'true' && env.PYPI_API_TOKEN == '' }}
|
|
103
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
103
|
+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
|
|
104
104
|
|
|
105
105
|
- name: Create and push tags
|
|
106
106
|
if: ${{ steps.version.outputs.deploy == 'true' }}
|
|
@@ -127,7 +127,7 @@ jobs:
|
|
|
127
127
|
|
|
128
128
|
- name: Create GitHub release
|
|
129
129
|
if: ${{ steps.version.outputs.deploy == 'true' }}
|
|
130
|
-
uses: softprops/action-gh-release@v2
|
|
130
|
+
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
|
|
131
131
|
with:
|
|
132
132
|
tag_name: v${{ steps.version.outputs.version }}
|
|
133
133
|
name: v${{ steps.version.outputs.version }}
|
|
@@ -8,7 +8,6 @@ wheels/
|
|
|
8
8
|
|
|
9
9
|
# Virtual environments
|
|
10
10
|
.venv
|
|
11
|
-
|
|
12
11
|
# Local/editor/cache noise
|
|
13
12
|
.mypy_cache/
|
|
14
13
|
.pytest_cache/
|
|
@@ -17,10 +16,16 @@ wheels/
|
|
|
17
16
|
coverage.xml
|
|
18
17
|
htmlcov/
|
|
19
18
|
.vscode/
|
|
20
|
-
docs/
|
|
19
|
+
docs/__pycache__/
|
|
21
20
|
.claude/
|
|
22
21
|
.claude.md
|
|
23
22
|
AGENTS.md
|
|
24
23
|
|
|
25
24
|
# Internal discussion docs (not part of distributable source)
|
|
26
25
|
specs/
|
|
26
|
+
|
|
27
|
+
# Sphinx build output — generated by ReadTheDocs, never commit
|
|
28
|
+
docs/_build/
|
|
29
|
+
|
|
30
|
+
# autosummary stubs — regenerated by Sphinx on every build
|
|
31
|
+
docs/reference/api/generated/
|
|
@@ -24,6 +24,13 @@ repos:
|
|
|
24
24
|
|
|
25
25
|
- id: mypy
|
|
26
26
|
name: mypy strict
|
|
27
|
-
entry: uv run mypy --no-incremental src
|
|
27
|
+
entry: uv run mypy --no-incremental src
|
|
28
28
|
language: system
|
|
29
29
|
pass_filenames: false
|
|
30
|
+
|
|
31
|
+
- id: pyright
|
|
32
|
+
name: pyright
|
|
33
|
+
entry: uv run pyright
|
|
34
|
+
language: system
|
|
35
|
+
pass_filenames: false
|
|
36
|
+
types: [python]
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# 🚀 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))
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## ✨ Features
|
|
5
|
+
### core
|
|
6
|
+
- **core:** typed repository abstractions and SQLAlchemy backend<br>
|
|
7
|
+
> Async repository protocol (RepositoryRead, RepositoryWrite, RepoFor) backed
|
|
8
|
+
> by SQLAlchemy 2.0 async session. Struct-based model system using
|
|
9
|
+
> msgspec.Struct
|
|
10
|
+
> as the single source of truth — models compile to SA mapped classes at startup
|
|
11
|
+
> via compile_all(). count() and UPDATE RETURNING included as first-class
|
|
12
|
+
> operations.
|
|
13
|
+
|
|
14
|
+
- **core:** use-case DSL with field refs, compute, rules and typed markers<br>
|
|
15
|
+
> Declarative use-case definition via Input, Load, LoadById, Exists, Compute and
|
|
16
|
+
> Rule markers. Signature inspection runs once at compile time; RuntimeExecutor
|
|
17
|
+
> drives execution from an immutable ExecutionPlan. No per-request reflection.
|
|
18
|
+
|
|
19
|
+
- **core:** ApplicationInvoker and named use-case registry<br>
|
|
20
|
+
> Use cases and job callbacks invoke other use cases by type through
|
|
21
|
+
> ApplicationInvoker without direct coupling. A named registry maps use-case
|
|
22
|
+
> keys to compiled instances at bootstrap, providing a stable cross-invocation
|
|
23
|
+
> contract.
|
|
24
|
+
|
|
25
|
+
- **core:** compiled model artifact and cache entity keys<br>
|
|
26
|
+
> compile_all() produces a typed CompiledCore artifact exposing stable entity
|
|
27
|
+
> keys used by the cache layer for deterministic repository-level invalidation
|
|
28
|
+
> across reads and writes.
|
|
29
|
+
|
|
30
|
+
- **core:** executor skips UoW for read-only use cases and GET routes<br>
|
|
31
|
+
> UseCase.read_only=True and all GET routes bypass UoW.begin/commit, removing
|
|
32
|
+
> at minimum one BEGIN+COMMIT round-trip from every read request on PostgreSQL.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### projection
|
|
36
|
+
- **projection:** compiler-driven memory/SQL routing<br>
|
|
37
|
+
> Projections are source-agnostic at declaration time. The backend compiler
|
|
38
|
+
> decides at compile_all() whether each projection runs in-memory (relation
|
|
39
|
+
> already loaded in the active profile) or via SQL. Users declare only
|
|
40
|
+
> CountLoader, ExistsLoader, or JoinFieldsLoader — no source= parameter.
|
|
41
|
+
> Internal _Memory* and _Sql* loaders are synthesized at compile time.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### cache
|
|
45
|
+
- **cache:** aiocache gateway with auto-inferred invalidation specs<br>
|
|
46
|
+
> CachedRepository wraps any repository with read-through/write-through caching.
|
|
47
|
+
> ONE_TO_MANY depends_on specs are auto-generated from field annotations — no
|
|
48
|
+
> explicit declaration needed. Explicit depends_on always wins.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### job
|
|
52
|
+
- **job:** async job domain model and orchestration primitives<br>
|
|
53
|
+
> Job[ResultT] base class with Celery routing ClassVars. JobHandle / JobGroup
|
|
54
|
+
> with dual-mode waiting (Celery + inline). JobCallback lifecycle with
|
|
55
|
+
> on_success/on_failure. Dispatch is transactionally safe — jobs flush on
|
|
56
|
+
> UoW commit and are cleared on rollback.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### celery
|
|
60
|
+
- **celery:** production-ready Celery integration layer<br>
|
|
61
|
+
> CeleryJobService, persistent worker event loop, trace propagation, eager
|
|
62
|
+
> fallback, and task_default_queue routing so callbacks land on the correct
|
|
63
|
+
> consumed queue. bootstrap_worker compiles use cases, repositories, and
|
|
64
|
+
> registers Celery tasks in a single call.
|
|
65
|
+
|
|
66
|
+
- **celery:** worker job discovery from modules or manifest<br>
|
|
67
|
+
> bootstrap_worker discovers and registers Job classes automatically from
|
|
68
|
+
> module include paths (mode: modules) or from a typed WorkerManifest
|
|
69
|
+
> (mode: manifest). WorkerManifest replaces scattered JOBS/USE_CASES/INTERFACES
|
|
70
|
+
> module attributes with a single typed contract.
|
|
71
|
+
|
|
72
|
+
- **celery:** interfaces= and use_cases= on bootstrap_worker<br>
|
|
73
|
+
> Callbacks that call ApplicationInvoker need matching use-case keys compiled
|
|
74
|
+
> in the worker. interfaces= extracts use-case types from RestInterface route
|
|
75
|
+
> declarations (including AutoCRUD-generated ones). use_cases= handles
|
|
76
|
+
> non-AutoCRUD scenarios. Both can be combined with discovery mode.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
### rest
|
|
80
|
+
- **rest:** AutoCRUD and FastAPI adapter<br>
|
|
81
|
+
> RestInterface.auto=True generates full CRUD routes at class definition time
|
|
82
|
+
> via build_auto_routes(). OpenAPI contracts expose query params, pagination
|
|
83
|
+
> defaults, and decoupled CreateInput/UpdateInput write DTOs. Discovery engine
|
|
84
|
+
> mounts all declared interfaces at bootstrap.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
### observability
|
|
88
|
+
- **observability:** trace_id propagation and Prometheus adapter<br>
|
|
89
|
+
> trace_id injected into every request context and propagated to job callbacks.
|
|
90
|
+
> MetricsAdapter protocol emits execution events; PrometheusAdapter records
|
|
91
|
+
> latency histograms and error counters with low cardinality labels.
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
## 📖 Documentation
|
|
97
|
+
- Sphinx documentation platform with full public guides<br>
|
|
98
|
+
> Quickstart, use-case DSL reference, AutoCRUD guide, Celery integration guide
|
|
99
|
+
> (job definition, dispatch, callbacks, YAML reference, bootstrap options,
|
|
100
|
+
> ApplicationInvoker, Docker-compose stack), and dummy-loom examples-repo
|
|
101
|
+
> walkthrough. Deployed to Read the Docs.
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
## ⚡ Performance
|
|
108
|
+
### repository
|
|
109
|
+
- **repository:** single-query total count for offset pagination<br>
|
|
110
|
+
> list_with_query with PaginationMode.OFFSET issues a single SELECT COUNT(*)
|
|
111
|
+
> instead of a separate full-table scan, eliminating one round-trip per
|
|
112
|
+
> paginated list operation.
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
### engine
|
|
116
|
+
- **engine:** UPDATE RETURNING replaces SELECT + flush + refresh<br>
|
|
117
|
+
> SQLAlchemyUpdateMixin.update() issues a single UPDATE ... RETURNING
|
|
118
|
+
> round-trip.
|
|
119
|
+
> Server-side onupdate expressions are pre-computed at init time and injected
|
|
120
|
+
> into the SET clause automatically.
|