loom-kernel 0.18.2__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/CHANGELOG.md +29 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/PKG-INFO +1 -1
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/rest/identity.md +1 -1
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/rest/sql.md +18 -4
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/pyproject.toml +3 -3
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/identity/__init__.py +3 -0
- loom_kernel-1.0.0/src/loom/core/identity/issuer.py +70 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/auth/__init__.py +4 -2
- loom_kernel-1.0.0/src/loom/rest/auth/config.py +317 -0
- loom_kernel-1.0.0/src/loom/rest/auth/jwt.py +431 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_app_hardening.py +5 -1
- loom_kernel-1.0.0/tests/unit/rest/test_jwt_issuer.py +615 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_jwt_middleware.py +55 -19
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_sql_endpoint_auth_gate.py +6 -2
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_sql_endpoint_roles.py +5 -1
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/uv.lock +3 -3
- loom_kernel-0.18.2/src/loom/rest/auth/config.py +0 -111
- loom_kernel-0.18.2/src/loom/rest/auth/jwt.py +0 -192
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/.github/workflows/ci-main.yml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/.github/workflows/ci-pr.yml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/.github/workflows/docs.yml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/.github/workflows/release.yml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/.gitignore +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/.pre-commit-config.yaml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/.readthedocs.yaml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/LICENSE +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/Makefile +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/README.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/codecov.yml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docker-compose.local.yaml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/_static/.gitkeep +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/_static/custom.css +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/_static/logo-transparent.png +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/_static/logo.svg +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/architecture/adr/README.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/architecture/clean-architecture.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/architecture/overview.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/conf.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/etl/examples.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/etl/pipelines.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/etl/testing.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/examples-repo/index.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/getting-started/etl.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/getting-started/rest.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/getting-started/streaming.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/guides/autocrud.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/guides/celery.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/guides/etl.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/guides/fake-repo-examples.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/guides/quickstart.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/guides/use-case-dsl.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/index.rst +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/overview.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/reference/api/core.rst +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/reference/api/etl.rst +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/reference/api/repository.rst +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/reference/api/rest.rst +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/reference/api/streaming.rst +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/reference/api/testing.rst +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/reference/index.rst +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/requirements.txt +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/rest/autocrud.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/rest/celery.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/rest/examples.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/rest/testing.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/rest/use-case-dsl.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/docs/streaming/bytewax.md +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/scripts/release/checkout_merged_release.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/sonar-project.properties +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/celery/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/celery/auto.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/celery/bootstrap.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/celery/config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/celery/constants.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/celery/runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/celery/service.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/async_bridge.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/backend/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/backend/core_model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/backend/protocol.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/backend/sqlalchemy.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/bootstrap/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/bootstrap/kernel.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/abc/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/abc/backend.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/abc/config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/abc/dependency.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/codec.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/decorators.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/dependency.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/gateway.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/keys.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/repository.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/cache/serializer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/command/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/command/adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/command/base.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/command/field.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/command/introspection.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/_resolver_utils.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/binder.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/configurable.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/keys.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/loader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/observability.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/resolver.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/secrets.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/config/ssm.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/contracts/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/contracts/manifest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/di/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/di/container.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/di/scope.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/discovery/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/discovery/_utils.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/discovery/base.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/discovery/interfaces.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/discovery/manifest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/discovery/modules.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/engine/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/engine/compilable.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/engine/compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/engine/events.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/engine/executor.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/engine/metrics.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/engine/plan.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/errors/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/errors/codes.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/errors/errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/expr/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/expr/eval.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/expr/nodes.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/expr/refs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/identity/context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/identity/identity.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/identity/wire.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/job/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/job/callback.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/job/context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/job/handle.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/job/job.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/job/service.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/logger/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/logger/abc.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/logger/config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/logger/registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/logger/structlogger.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/base.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/enums.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/field.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/introspection.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/projection.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/relation.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/struct.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/timestamped.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/types.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/model/types_postgres.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/event.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/observer/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/observer/noop.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/observer/otel.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/observer/structlog.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/protocol.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/observability/topology.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/projection/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/projection/loaders.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/projection/runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/abc/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/abc/query.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/abc/repo_for.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/abc/repository.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/dynamodb/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/dynamodb/registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/dynamodb/repository.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/dynamodb/uow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/mutation.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/registration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/mixins.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/session_manager.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/response/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/response/base.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/routing/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/routing/ref.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/routing/resolver.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/schema/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/schema/schema_mode.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/abc/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/abc/contracts.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/abc/errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/clickhouse/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/clickhouse/_client.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/clickhouse/executor.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/clickhouse/registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/sql/service.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/tracing/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/tracing/context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/transport/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/transport/adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/uow/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/uow/abc.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/uow/context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/_predicates.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/compute.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/constants.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/factory.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/field_ref.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/invoker.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/keys.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/markers.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/rule.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/core/use_case/use_case.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_format_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_historify/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_historify/_common.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_historify/_log.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_historify/_ops.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_historify/_transform.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_merge.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_predicate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_schema_aligner/_policy.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/_write_policy.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_dtype.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_file_writer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_historify.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_predicate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_reader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_schema.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_streaming.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/_writer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/polars/provider.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/spark/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/spark/_dtype.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/spark/_historify.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/spark/_reader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/spark/_schema.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/spark/_writer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/backends/spark/provider.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/checkpoint/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/checkpoint/_backends/_polars.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/checkpoint/_cleaners.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/checkpoint/_paths.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/checkpoint/_scope.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/checkpoint/_store.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/compiler/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/compiler/_binding.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/compiler/_compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/compiler/_errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/compiler/_plan.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/compiler/_validators.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/compiler/_validators_plan.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/compiler/_validators_step.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/_format.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/_read_options.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/_utils.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/_write_options.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/expr/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/expr/_params.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/expr/_predicate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/expr/_refs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/source/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/source/_from.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/source/_from_dynamodb.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/source/_specs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_client.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_file.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_history/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_history/_builder.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_history/_errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_history/_report.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_history/_spec.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_into.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_schema_mode.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_table.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/declarative/target/_temp.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/executor/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/executor/_dispatcher.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/executor/_executor.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_clickhouse.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_dynamodb.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_dynamodb_items.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_dynamodb_predicate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_mongo.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/sources/_serialization.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/targets/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/io/targets/_clickhouse.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/lineage/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/lineage/_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/lineage/_observer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/lineage/_records.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/lineage/sinks/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/lineage/sinks/_table.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/lineage/sinks/_writer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/maintenance/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/maintenance/_builder.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/maintenance/_ops.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/maintenance/_protocol.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/maintenance/_runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/maintenance/_step.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/maintenance/backends/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/maintenance/backends/_delta_rs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/_generics.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/_params.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/_pipeline.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/_process.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/_sql.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/_step.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/_step_client.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/pipeline/_step_sql.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runner/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runner/_providers.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runner/_wiring.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runner/config_loader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runner/core.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runner/errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runner/filtering.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runtime/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/runtime/contracts.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/schema/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/schema/_contract.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/schema/_schema.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/storage/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/storage/_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/storage/_file_locator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/storage/_locator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/storage/routing.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/testing/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/testing/_result.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/testing/_runners.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/testing/_scenario.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/testing/_stubs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/etl/testing/spark.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/_async.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/_ctx.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/_meta.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/_placeholders.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/_summary.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/deploy/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/deploy/_discovery.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/deploy/_schedule.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/deploy/_yaml.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_assemble.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_backfill.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_backfill_body.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_body.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_common.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_factory.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_hooks.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_maintenance.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_run_name.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_signature.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/flow/_stages.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/manifest/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/manifest/_model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/manifest/_s3.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/manifest/_store.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/notify/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/notify/_event.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/notify/_factory.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/notify/_port.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/notify/_slack.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/observer/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/observer/_flow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/observer/_logging_bridge.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/observer/_manifest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prefect/observer/_task_run.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prometheus/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prometheus/adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prometheus/kafka.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prometheus/lifecycle.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/prometheus/middleware.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/py.typed +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/_body.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/auth/abc.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/auth/middleware.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/autocrud.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/constants.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/cors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/_errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/_exclusions.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/_sql_roles.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/app.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/auto.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/openapi.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/response.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/router_runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/fastapi/sql.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/middleware.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/rest/rest_adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/_adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/_dlq.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/_operators.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/_runtime_io.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/_shared.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/steps.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/bytewax/runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/compiler/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/compiler/_bindings.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/compiler/_compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/compiler/_plan.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/compiler/phases/build_plan.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/compiler/phases/validate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/core/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/core/_errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/core/_exceptions.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/core/_message.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/core/_typing.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/graph/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/graph/_flow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/_codec.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/_errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/_key_resolver.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/_message.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/_record.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/_wire.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/client/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/client/_consumer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/client/_producer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/client/_protocol.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/message/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/message/_consumer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/message/_producer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/kafka/message/_protocol.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/mongo/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/mongo/_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/mongo/_event.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/mongo/_normalize.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_boundary.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_broadcast.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_capabilities.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_decompose.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_expand_routes.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_expr_eval.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_fork.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_helpers.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_mongo.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_protocols.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_router.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_shape.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_sink.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_step.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_table/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_table/common.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_table/config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/_with.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/nodes/refs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/streaming/testing.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/testing/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/testing/golden.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/testing/http_harness.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/testing/in_memory.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/testing/repository_harness.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/src/loom/testing/runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/golden/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/golden/baselines/.gitkeep +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/golden/outputs/.gitkeep +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/golden/plans/.gitkeep +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/helpers/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/celery_bootstrap/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/celery_bootstrap/config/conf.celery.integration.yaml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/celery_bootstrap/test_auto_create_app_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/celery_bootstrap/test_bootstrap_worker.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/bootstrap/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/bootstrap/test_bootstrap_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/repository/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/repository/sqlalchemy/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/repository/sqlalchemy/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/repository/sqlalchemy/test_cache_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/repository/sqlalchemy/test_repository_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/rest/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/rest/test_auto_interface_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/rest/test_fastapi_app_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/rest/test_rest_error_mapping.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/rest/test_rest_observability.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/use_case/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/use_case/test_custom_repository_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/core/use_case/test_use_case_crud_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/etl/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/etl/test_runner_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/config/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/config/conf.interfaces.yaml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/config/conf.manifest.yaml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/config/conf.modules.yaml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/config/conf.yaml +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/main.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/manifest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/category/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/category/model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/category/schemas.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/interface.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/jobs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/relations.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/repository.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/repository_contract.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/review/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/review/model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/review/schemas.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/schemas.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/fake_repo/product/use_cases.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/sql/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/sql/init/01_users_roles.sql +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/sql/test_clickhouse_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/streaming/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/streaming/test_into_table_integration.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/support/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/integration/support/logical_repo_fixtures.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_bootstrap/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_bootstrap/test_async_runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_bootstrap/test_bootstrap.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_jobs/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_jobs/test_auto.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_jobs/test_celery_service.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_jobs/test_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_jobs/test_identity_propagation.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/celery_jobs/test_runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/ci/test_workflow_supply_chain_contract.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/backend/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/backend/test_backend_compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/bootstrap/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/bootstrap/test_bootstrap.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/bootstrap/test_bootstrap_metrics.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/bootstrap/test_kernel.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/cache/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/cache/test_cached_repository.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/command/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/command/test_command_base.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/command/test_command_field.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/command/test_command_patch.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/command/test_introspection.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/config/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/config/test_binder.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/config/test_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/config/test_configurable.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/config/test_context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/config/test_resolver_utils.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/config/test_secrets.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/config/test_ssm.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/di/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/di/test_container.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/discovery/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/discovery/test_manifest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/engine/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/engine/test_caller_binding.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/engine/test_compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/engine/test_executor.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/engine/test_executor_trace.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/engine/test_executor_uow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/engine/test_metrics.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/engine/test_plan.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/errors/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/errors/test_errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/expr/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/expr/test_expr.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/identity/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/identity/test_context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/identity/test_identity.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/identity/test_wire.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/job/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/job/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/job/test_callback.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/job/test_context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/job/test_handle.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/job/test_inline_service.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/job/test_job.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/logger/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/logger/test_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/logger/test_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/model/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/model/test_model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/model/test_struct.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/model/test_timestamped.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/observability/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/observability/test_observers.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/observability/test_runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/projection/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/projection/test_runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/abc/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/abc/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/abc/test_query.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/abc/test_repository_contract.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/dynamodb/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/dynamodb/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/dynamodb/test_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/dynamodb/test_repository.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/sqlalchemy/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/sqlalchemy/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/sqlalchemy/test_loaders.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/sqlalchemy/test_repository.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/repository/sqlalchemy/test_transactional.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/routing/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/routing/test_routing.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/_fakes.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/test_clickhouse_executor.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/test_clickhouse_transport.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/test_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/test_isolation.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/test_null_service.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/test_pagination_limits.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/test_registry_lifecycle.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/sql/test_role_policy.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/test_async_bridge.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/test_compiler_contracts.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/test_runner_contracts.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/tracing/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/tracing/test_context.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/uow/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/uow/test_executor_uow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/uow/test_sqlalchemy_uow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/uow/test_uow_protocols.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/use_case/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/use_case/test_compute.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/use_case/test_factory.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/use_case/test_field_ref.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/use_case/test_invoker.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/use_case/test_markers.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/use_case/test_rule.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/core/use_case/test_use_case.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/_historify_contract.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_empty_write_warning.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_historify_common.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_apply_schema.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_backend.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_dtype.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_file_writer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_historify_polars.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_predicate_pushdown.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_reader_columns.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_reader_json_columns.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_step_execution.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_streaming_write.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_upsert_writer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_writer_null_schema.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_polars/test_writer_to_frame.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_spark/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_spark/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_spark/test_dtype.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_spark/test_historify_spark.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_spark/test_spark_apply_schema.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_spark/test_step_execution.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_spark/test_writer_to_frame.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/backends/test_write_policy_historify.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/checkpoint/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/checkpoint/backends/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/checkpoint/backends/test_checkpoint_polars.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/checkpoint/test_checkpoint_paths.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/checkpoint/test_cleaners.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/checkpoint/test_store.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/client_step/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/client_step/test_client_step.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_catalog_validator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_compiler_catalog.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_compiler_upsert.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_errors_additional_factories.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_errors_runtime_factories.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_historify_validator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_param_exprs_validator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_plan_traversal.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_step_validator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_structural.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_temp_validator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/compiler/test_upsert_validator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_clickhouse_reader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_dynamodb_predicate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_dynamodb_reader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_from_clickhouse.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_from_dynamodb.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_from_mongo.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_mongo_predicate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_mongo_reader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/sources/test_mongo_reader_memory.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/targets/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/targets/test_clickhouse_writer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/targets/test_into_clickhouse.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/test_history_target.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/test_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/test_source.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/test_source_json.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/test_source_options.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/test_target.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/test_utils.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/io/test_variants.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/lineage/test_observer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/lineage/test_records.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/lineage/test_store.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/maintenance/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/maintenance/backends/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/maintenance/backends/test_delta_rs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/maintenance/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/maintenance/test_builder.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/maintenance/test_runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/maintenance/test_step.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/pipeline/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/pipeline/test_pipeline_process.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/pipeline/test_proxy.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/pipeline/test_step.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/schema/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/schema/test_contract.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/schema/test_schema.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/schema/test_table.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/sql/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/sql/test_merge.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/sql/test_predicate.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/sql/test_predicate_dialect.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/sql/test_sql_runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/storage/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/storage/test_backend_factory.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/storage/test_io_protocols.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/storage/test_locator.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/storage/test_observability_and_protocols.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/storage/test_route_build.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/storage/test_schema_readers.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/storage/test_storage_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_config_loader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_executor.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_format_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_module_contracts.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_public_api_discovery.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_record_schema_coverage.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_runner_errors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/test_spark_testing.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/testing/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/testing/test_runners.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/testing/test_scenario_and_stubs.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/etl/testing/test_spark_helpers.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_backfill_flow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_ctx.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_etl_flow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_logging_bridge.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_maintenance_flow.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_manifest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_manifest_s3.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_notify.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_observer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_placeholders.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_task_run_observer.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prefect/test_yaml_loader.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prometheus/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prometheus/test_adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/prometheus/test_middleware.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/release/test_checkout_merged_release.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/release/test_release_workflow_contract.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/_fixture_app.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_auth_middleware.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_autocrud.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_cors.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_fastapi_auto_logger.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_fastapi_auto_persistence.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_middleware.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_pydantic_adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_request_hardening.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_response.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_rest_adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_rest_compiler.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_rest_model.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_route_rbac.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_router_identity.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_router_runtime.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_sql_endpoint.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/rest/test_sql_serialization.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/cases.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_adapter.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_batch_key.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_bytewax_dispatcher.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_collect_batch.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_dlq.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_error_boundary.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_operators.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_resource_manager.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_runtime_io.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_runtime_sink.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_runtime_source.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_sink_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_steps.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/bytewax/test_storage.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/cases.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/test_async_walk.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/test_basics.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/test_config_bindings.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/test_mongo_source.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/test_multi_source.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/test_router.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/test_window.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/compiler/test_with.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/contracts/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/contracts/cases.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/contracts/test_boundary.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/contracts/test_message.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/contracts/test_mongo_contracts.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/contracts/test_multi_boundary.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/contracts/test_steps.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/cases/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/cases/batch.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/cases/explode.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/cases/fork.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/cases/router.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/cases/shared.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/cases/simple.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/test_compiler_examples.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/flows/test_flow_examples.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/cases.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/fakes.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_client.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_key_resolver.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_message.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_message_client.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_multi_wire.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_observability.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_settings.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/kafka/test_wire.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/mongo/test_bytewax_source.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/nodes/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/nodes/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/nodes/test_broadcast.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/nodes/test_delta_config.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/nodes/test_logging.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/nodes/test_table_package.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/observability/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/observability/cases.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/observability/conftest.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/observability/test_observability_runner.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/observability/test_protocols.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/observability/test_registry.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/observability/test_structlog.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/support/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/support/flow_cases.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/test_expand_routes.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/test_fork.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/test_otel_observability.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/test_routing.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/test_testing_mongo.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/streaming/test_with.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/testing/__init__.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/testing/test_golden.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/testing/test_http_harness.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/testing/test_identity_harness.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/testing/test_in_memory.py +0 -0
- {loom_kernel-0.18.2 → loom_kernel-1.0.0}/tests/unit/testing/test_runner.py +0 -0
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
# 🚀 Release 1.0.0 ([#106](https://github.com/the-reacher-data/loom-py/pull/106)) ([`f8fe343`](https://github.com/the-reacher-data/loom-py/commit/f8fe3433a841711f2393c0def0c1796c1f3b05d8))
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## 🔖 Other
|
|
13
|
+
- and* signs. Public keys stay inline -- they only verify.<br>
|
|
14
|
+
> The signing key is probed once at construction, so a malformed PEM or a key that
|
|
15
|
+
> cannot serve the configured algorithm fails startup. Reading the key is not
|
|
16
|
+
> parsing it: `cryptography` raises a plain `ValueError`, which is neither a
|
|
17
|
+
> `PyJWTError` nor what the port documents `ValueError` to mean, so without the
|
|
18
|
+
> probe a broken deployment surfaced at the first login disguised as a bad login.
|
|
19
|
+
> Verification accepts a map of public keys selected by the token's `kid`, so a
|
|
20
|
+
> key can be rotated with an overlap window instead of a restart that invalidates
|
|
21
|
+
> every live token. The key is chosen by `kid` and never by trying each in turn:
|
|
22
|
+
> exhaustive trial would decouple every algorithm from its key family, which is
|
|
23
|
+
> what keeps algorithm confusion impossible.
|
|
24
|
+
> BREAKING CHANGE: `JwtAuthConfig.public_key: str` is now
|
|
25
|
+
> `public_keys: dict[str, str]`, keyed by `kid`; `JwtAuthConfig.secret: str` is
|
|
26
|
+
> now `secret_path: str`, the path of a file holding the secret; and
|
|
27
|
+
> `verification_key` is a method taking a `kid` instead of a property. Config
|
|
28
|
+
|
|
29
|
+
|
|
1
30
|
# 🚀 Release 0.18.2 ([#105](https://github.com/the-reacher-data/loom-py/pull/105)) ([`833a45d`](https://github.com/the-reacher-data/loom-py/commit/833a45db6cb8f2870f131eb54a80b12fbf06dd30))
|
|
2
31
|
|
|
3
32
|
|
|
@@ -447,8 +447,9 @@ app:
|
|
|
447
447
|
rest:
|
|
448
448
|
auth:
|
|
449
449
|
jwt:
|
|
450
|
-
|
|
451
|
-
#
|
|
450
|
+
secret_path: ${oc.env:LOOM_JWT_SECRET_PATH} # HS256 — a path, not the value
|
|
451
|
+
# public_keys: # RS256/ES256/EdDSA — one PEM per key id
|
|
452
|
+
# "2026-08": ${oc.env:LOOM_JWT_PUBLIC_KEY_PEM}
|
|
452
453
|
algorithms: [HS256] # explicit allowlist; 'none' always rejected
|
|
453
454
|
audience: loom-api # REQUIRED by any sql_endpoint with auth: identity
|
|
454
455
|
issuer: null # validated only when set
|
|
@@ -463,8 +464,21 @@ app:
|
|
|
463
464
|
needed; early token revocation is out of scope.
|
|
464
465
|
- **`sub` is mandatory.** A token without a subject carries no identity to authorize
|
|
465
466
|
against, nor to audit afterwards, so it is rejected with 401.
|
|
466
|
-
- Exactly one of `
|
|
467
|
-
the algorithm allowlist must match the key type — validated
|
|
467
|
+
- Exactly one of `secret_path` (HS*) or `public_keys` (RS*/ES*/EdDSA static PEMs, keyed by
|
|
468
|
+
key id) must be set, and the algorithm allowlist must match the key type — validated
|
|
469
|
+
fail-fast at startup.
|
|
470
|
+
- **`secret_path` is a path, not the value.** The config is a `msgspec.Struct`, so any
|
|
471
|
+
serializer emits its fields verbatim: holding an HS secret would let a config dump
|
|
472
|
+
publish the key that both verifies *and* signs. Public keys are safe to inline
|
|
473
|
+
because they only verify. The container has to materialize the value to a file:
|
|
474
|
+
Kubernetes mounts a `Secret` as a volume directly, while ECS/Fargate injects
|
|
475
|
+
task-definition secrets as **environment variables only**, so there an entrypoint
|
|
476
|
+
must write the value to a path on a `tmpfs` volume before the app starts.
|
|
477
|
+
- With `public_keys`, the key is chosen by the token's `kid` header, never by trying
|
|
478
|
+
each key in turn: exhaustive trial would decouple every algorithm from its key
|
|
479
|
+
family, which is what makes algorithm confusion impossible here. A token with no
|
|
480
|
+
`kid` verifies only when a single key is configured, so a rotation overlap needs the
|
|
481
|
+
issuer to stamp one.
|
|
468
482
|
- On success the verified claims are projected onto an
|
|
469
483
|
{class}`~loom.core.identity.Identity` published for the request; on failure
|
|
470
484
|
the response is a 401 with the standard error body, a `WWW-Authenticate` challenge
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "loom-kernel"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "1.0.0"
|
|
4
4
|
description = "Loom Python project"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -132,7 +132,7 @@ dev = [
|
|
|
132
132
|
"pyright>=1.1.390,<2.0",
|
|
133
133
|
"pytest>=8.3.0",
|
|
134
134
|
"pytest-asyncio>=0.24.0",
|
|
135
|
-
"pyjwt>=2.12.0",
|
|
135
|
+
"pyjwt[crypto]>=2.12.0",
|
|
136
136
|
"redis>=5.0.0",
|
|
137
137
|
"ruff>=0.9.0,<1.0",
|
|
138
138
|
"sqlalchemy>=2.0,<3.0",
|
|
@@ -278,7 +278,7 @@ markers = [
|
|
|
278
278
|
|
|
279
279
|
[tool.commitizen]
|
|
280
280
|
name = "cz_conventional_commits"
|
|
281
|
-
version = "0.
|
|
281
|
+
version = "1.0.0"
|
|
282
282
|
tag_format = "v$version"
|
|
283
283
|
version_files = [
|
|
284
284
|
"pyproject.toml:project.version",
|
|
@@ -8,10 +8,13 @@ no transport and no infrastructure.
|
|
|
8
8
|
|
|
9
9
|
from loom.core.identity.context import current_identity, reset_identity, set_identity
|
|
10
10
|
from loom.core.identity.identity import ANONYMOUS, Identity
|
|
11
|
+
from loom.core.identity.issuer import IssuedToken, TokenIssuer
|
|
11
12
|
|
|
12
13
|
__all__ = [
|
|
13
14
|
"ANONYMOUS",
|
|
14
15
|
"Identity",
|
|
16
|
+
"IssuedToken",
|
|
17
|
+
"TokenIssuer",
|
|
15
18
|
"current_identity",
|
|
16
19
|
"reset_identity",
|
|
17
20
|
"set_identity",
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Minting a credential for a verified :class:`Identity`.
|
|
2
|
+
|
|
3
|
+
The port lives beside the identity it consumes, not beside the transport that
|
|
4
|
+
implements it: the caller is a login use case, so putting the abstraction in
|
|
5
|
+
``loom.rest`` would make the application layer import infrastructure. What is
|
|
6
|
+
domain here is *"this service needs to mint a credential for this identity"*;
|
|
7
|
+
that a JWT comes out is the detail, and it belongs to the implementation.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from datetime import datetime, timedelta
|
|
14
|
+
from typing import Protocol
|
|
15
|
+
|
|
16
|
+
from loom.core.identity.identity import Identity
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True, slots=True)
|
|
20
|
+
class IssuedToken:
|
|
21
|
+
"""A minted credential together with what the issuer already knew about it.
|
|
22
|
+
|
|
23
|
+
Returned instead of a bare string so a login endpoint never has to decode
|
|
24
|
+
the token it just signed: the expiry the HTTP response advertises and the
|
|
25
|
+
identifier the audit trail records are both produced by the signing step.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
token: The encoded credential, ready to travel as a bearer token.
|
|
29
|
+
expires_at: Instant the credential stops being valid, timezone-aware.
|
|
30
|
+
jti: Unique identifier of this minting, for correlation and audit.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
token: str
|
|
34
|
+
expires_at: datetime
|
|
35
|
+
jti: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TokenIssuer(Protocol):
|
|
39
|
+
"""Mints a credential that an :class:`Authenticator` can later verify.
|
|
40
|
+
|
|
41
|
+
Implementations guarantee the round trip: whatever the identity carries —
|
|
42
|
+
subject, roles and attributes — a matching authenticator recovers intact.
|
|
43
|
+
Everything the credential says comes from the identity, so no caller can
|
|
44
|
+
smuggle a claim past it.
|
|
45
|
+
|
|
46
|
+
Example::
|
|
47
|
+
|
|
48
|
+
issued = issuer.issue(identity)
|
|
49
|
+
response = {"access_token": issued.token, "expires_at": issued.expires_at}
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def issue(self, identity: Identity, *, ttl: timedelta | None = None) -> IssuedToken:
|
|
53
|
+
"""Mint a credential for *identity*.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
identity: Verified caller the credential speaks for.
|
|
57
|
+
ttl: Lifetime override. ``None`` uses the configured one, which is
|
|
58
|
+
also the ceiling: a longer lifetime is refused.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
The minted credential and its metadata.
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
ValueError: If the identity cannot be represented — anonymous, or
|
|
65
|
+
carrying an attribute that would be unreadable once encoded —
|
|
66
|
+
or if *ttl* exceeds the configured lifetime.
|
|
67
|
+
RuntimeError: If the credential cannot be produced. Implementations
|
|
68
|
+
keep the cause out of the traceback: it can carry key material.
|
|
69
|
+
"""
|
|
70
|
+
...
|
|
@@ -13,8 +13,8 @@ Install the optional JWT dependency with::
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
from loom.rest.auth.abc import Authenticator, RequestCredentials
|
|
16
|
-
from loom.rest.auth.config import JwtAuthConfig
|
|
17
|
-
from loom.rest.auth.jwt import JwtAuthenticator
|
|
16
|
+
from loom.rest.auth.config import JwtAuthConfig, JwtIssuerConfig
|
|
17
|
+
from loom.rest.auth.jwt import JwtAuthenticator, JwtIssuer
|
|
18
18
|
from loom.rest.auth.middleware import AuthenticationMiddleware, JwtAuthMiddleware
|
|
19
19
|
|
|
20
20
|
__all__ = [
|
|
@@ -23,5 +23,7 @@ __all__ = [
|
|
|
23
23
|
"JwtAuthConfig",
|
|
24
24
|
"JwtAuthMiddleware",
|
|
25
25
|
"JwtAuthenticator",
|
|
26
|
+
"JwtIssuer",
|
|
27
|
+
"JwtIssuerConfig",
|
|
26
28
|
"RequestCredentials",
|
|
27
29
|
]
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"""Configuration for the native stateless JWT authentication middleware."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from loom.core.config.errors import ConfigError
|
|
8
|
+
from loom.core.model import LoomFrozenStruct
|
|
9
|
+
|
|
10
|
+
DEFAULT_EXCLUDE_PATHS: tuple[str, ...] = ("/docs", "/redoc", "/openapi.json", "/metrics")
|
|
11
|
+
"""Paths served without authentication unless the application says otherwise."""
|
|
12
|
+
|
|
13
|
+
_FORBIDDEN_ALGORITHM = "none"
|
|
14
|
+
|
|
15
|
+
MAX_ISSUER_TTL_SECONDS = 3600
|
|
16
|
+
"""Ceiling for a minted token: signing is reading, so a long-lived token is a
|
|
17
|
+
standing grant that stateless verification cannot revoke."""
|
|
18
|
+
|
|
19
|
+
SUPPORTED_ALGORITHMS: frozenset[str] = frozenset(
|
|
20
|
+
{
|
|
21
|
+
"EdDSA",
|
|
22
|
+
"ES256",
|
|
23
|
+
"ES384",
|
|
24
|
+
"ES512",
|
|
25
|
+
"HS256",
|
|
26
|
+
"HS384",
|
|
27
|
+
"HS512",
|
|
28
|
+
"PS256",
|
|
29
|
+
"PS384",
|
|
30
|
+
"PS512",
|
|
31
|
+
"RS256",
|
|
32
|
+
"RS384",
|
|
33
|
+
"RS512",
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
"""Algorithms this framework signs with, checked at startup rather than on the
|
|
37
|
+
first request: a typo like ``" HS256"`` would otherwise fail per-call."""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# RFC 7519 registered claims: a roles claim named after one of these is silently
|
|
41
|
+
# overwritten when the token is built, leaving no roles and no error.
|
|
42
|
+
RESERVED_CLAIMS: frozenset[str] = frozenset({"iss", "sub", "aud", "exp", "nbf", "iat", "jti"})
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _is_symmetric(algorithm: str) -> bool:
|
|
46
|
+
"""Return ``True`` when *algorithm* uses a shared secret (HS* family)."""
|
|
47
|
+
return algorithm.upper().startswith("HS")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _require_supported(algorithm: str, *, setting: str) -> None:
|
|
51
|
+
"""Reject ``none`` and anything outside the supported set, at startup.
|
|
52
|
+
|
|
53
|
+
Shared by both configs on purpose: a hardening applied to one and not the
|
|
54
|
+
other is how the two drift apart.
|
|
55
|
+
"""
|
|
56
|
+
if algorithm.lower() == _FORBIDDEN_ALGORITHM:
|
|
57
|
+
raise ConfigError("The 'none' JWT algorithm is always forbidden.")
|
|
58
|
+
if algorithm not in SUPPORTED_ALGORITHMS:
|
|
59
|
+
raise ConfigError(
|
|
60
|
+
f"{setting} {algorithm!r} is not supported. "
|
|
61
|
+
f"Choose one of: {', '.join(sorted(SUPPORTED_ALGORITHMS))}."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _read_key_file(path: str, *, setting: str) -> str:
|
|
66
|
+
"""Read key material from disk, never chaining the cause.
|
|
67
|
+
|
|
68
|
+
An ``OSError`` message carries the path and a ``UnicodeDecodeError`` carries
|
|
69
|
+
the whole file on ``exc.object``: either would publish key material through a
|
|
70
|
+
traceback or a structured log that serializes the exception.
|
|
71
|
+
"""
|
|
72
|
+
try:
|
|
73
|
+
return Path(path).read_text(encoding="utf-8")
|
|
74
|
+
except (OSError, UnicodeDecodeError):
|
|
75
|
+
raise ConfigError(f"Could not read {setting}.") from None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _require_usable_roles_claim(roles_claim: str) -> None:
|
|
79
|
+
"""Reject a roles claim that is blank or shadows a registered claim."""
|
|
80
|
+
if not roles_claim or not roles_claim.strip():
|
|
81
|
+
raise ConfigError("JWT issuer requires a non-blank 'roles_claim'.")
|
|
82
|
+
if roles_claim in RESERVED_CLAIMS:
|
|
83
|
+
raise ConfigError(
|
|
84
|
+
f"JWT issuer 'roles_claim' {roles_claim!r} is a registered claim: "
|
|
85
|
+
"the token would carry no roles and raise nothing."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class JwtAuthConfig(LoomFrozenStruct, frozen=True, kw_only=True):
|
|
90
|
+
"""Validated settings for :class:`~loom.rest.auth.JwtAuthMiddleware`.
|
|
91
|
+
|
|
92
|
+
Binds from the ``app.rest.auth.jwt`` config section. Validation runs on
|
|
93
|
+
construction (fail-fast): exactly one key source must be provided and the
|
|
94
|
+
algorithm allowlist must be non-empty and coherent with that key source.
|
|
95
|
+
|
|
96
|
+
Attributes:
|
|
97
|
+
secret_path: Filesystem path of the shared secret for symmetric
|
|
98
|
+
algorithms (HS*). A path and not the value: this is a
|
|
99
|
+
``msgspec.Struct``, so any serializer emits its fields verbatim and a
|
|
100
|
+
config dump would publish the key that verifies *and signs*.
|
|
101
|
+
Mutually exclusive with ``public_keys``.
|
|
102
|
+
public_keys: Static PEM-encoded public keys for asymmetric algorithms
|
|
103
|
+
(RS*/ES*/EdDSA), keyed by the ``kid`` that selects them. Mutually
|
|
104
|
+
exclusive with ``secret``.
|
|
105
|
+
algorithms: Explicit allowlist of accepted JWT algorithms. The
|
|
106
|
+
``none`` algorithm is always forbidden.
|
|
107
|
+
audience: Expected ``aud`` claim. Validated only when set.
|
|
108
|
+
issuer: Expected ``iss`` claim. Validated only when set.
|
|
109
|
+
leeway_seconds: Clock-skew tolerance applied to time-based claims.
|
|
110
|
+
exclude_paths: Exact request paths that bypass authentication.
|
|
111
|
+
roles_claim: Name of the verified claim carrying the roles the caller
|
|
112
|
+
is authorized to use. Consumed by the SQL endpoint: the effective
|
|
113
|
+
roles are the claim values intersected with the connection
|
|
114
|
+
allowlist, and the request body can only narrow that set.
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
ConfigError: If key sources, algorithms, leeway, or the roles claim
|
|
118
|
+
name are invalid.
|
|
119
|
+
|
|
120
|
+
Example YAML::
|
|
121
|
+
|
|
122
|
+
app:
|
|
123
|
+
rest:
|
|
124
|
+
auth:
|
|
125
|
+
jwt:
|
|
126
|
+
secret_path: ${oc.env:LOOM_JWT_SECRET_PATH}
|
|
127
|
+
algorithms: [HS256]
|
|
128
|
+
roles_claim: loom_sql_roles
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
secret_path: str | None = None
|
|
132
|
+
public_keys: dict[str, str] = {}
|
|
133
|
+
algorithms: tuple[str, ...] = ()
|
|
134
|
+
audience: str | None = None
|
|
135
|
+
issuer: str | None = None
|
|
136
|
+
leeway_seconds: int = 0
|
|
137
|
+
exclude_paths: tuple[str, ...] = DEFAULT_EXCLUDE_PATHS
|
|
138
|
+
roles_claim: str | None = None
|
|
139
|
+
|
|
140
|
+
def __repr__(self) -> str:
|
|
141
|
+
return (
|
|
142
|
+
f"JwtAuthConfig(secret_path={self.secret_path!r},"
|
|
143
|
+
f" public_keys={sorted(self.public_keys)!r},"
|
|
144
|
+
f" algorithms={self.algorithms!r},"
|
|
145
|
+
f" audience={self.audience!r},"
|
|
146
|
+
f" issuer={self.issuer!r},"
|
|
147
|
+
f" leeway_seconds={self.leeway_seconds!r},"
|
|
148
|
+
f" exclude_paths={self.exclude_paths!r},"
|
|
149
|
+
f" roles_claim={self.roles_claim!r})"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def __post_init__(self) -> None:
|
|
153
|
+
if (self.secret_path is None) == (not self.public_keys):
|
|
154
|
+
raise ConfigError("JWT auth requires exactly one of 'secret_path' or 'public_keys'.")
|
|
155
|
+
for key_id, material in self.public_keys.items():
|
|
156
|
+
if not key_id.strip() or not material.strip():
|
|
157
|
+
raise ConfigError("JWT auth 'public_keys' entries need a key id and material.")
|
|
158
|
+
if not self.algorithms:
|
|
159
|
+
raise ConfigError("JWT auth requires a non-empty 'algorithms' allowlist.")
|
|
160
|
+
if self.leeway_seconds < 0:
|
|
161
|
+
raise ConfigError("JWT auth 'leeway_seconds' must be >= 0.")
|
|
162
|
+
if self.roles_claim is not None and not self.roles_claim.strip():
|
|
163
|
+
raise ConfigError("JWT auth 'roles_claim' must not be blank.")
|
|
164
|
+
for algorithm in self.algorithms:
|
|
165
|
+
self._validate_algorithm(algorithm)
|
|
166
|
+
|
|
167
|
+
def _validate_algorithm(self, algorithm: str) -> None:
|
|
168
|
+
_require_supported(algorithm, setting="JWT auth 'algorithms' entry")
|
|
169
|
+
if _is_symmetric(algorithm) and self.secret_path is None:
|
|
170
|
+
raise ConfigError(
|
|
171
|
+
f"JWT algorithm {algorithm!r} requires 'secret_path', not 'public_keys'."
|
|
172
|
+
)
|
|
173
|
+
if not _is_symmetric(algorithm) and not self.public_keys:
|
|
174
|
+
raise ConfigError(f"JWT algorithm {algorithm!r} requires 'public_keys', not 'secret'.")
|
|
175
|
+
|
|
176
|
+
def verification_key(self, key_id: str | None) -> str | None:
|
|
177
|
+
"""Return the key that verifies a token, selected by its ``kid``.
|
|
178
|
+
|
|
179
|
+
Selection is explicit and never exhaustive: trying every configured key
|
|
180
|
+
in turn would decouple each algorithm from its key family, which is what
|
|
181
|
+
makes algorithm confusion structurally impossible here.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
key_id: ``kid`` header of the token, or ``None`` when it carries none.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
The key material, or ``None`` when no configured key applies — an
|
|
188
|
+
unknown ``kid``, or a missing one while several keys are configured.
|
|
189
|
+
"""
|
|
190
|
+
if self.secret_path is not None:
|
|
191
|
+
return _read_key_file(self.secret_path, setting="JWT auth 'secret_path'")
|
|
192
|
+
if key_id is not None:
|
|
193
|
+
return self.public_keys.get(key_id)
|
|
194
|
+
if len(self.public_keys) == 1:
|
|
195
|
+
return next(iter(self.public_keys.values()))
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class JwtIssuerConfig(LoomFrozenStruct, frozen=True, kw_only=True):
|
|
200
|
+
"""Validated settings for :class:`~loom.rest.auth.JwtIssuer`.
|
|
201
|
+
|
|
202
|
+
Separate from :class:`JwtAuthConfig` on purpose, and not a few extra fields
|
|
203
|
+
on it: a service that only verifies must have no configuration path through
|
|
204
|
+
which signing material can land in its process. The fields diverge anyway —
|
|
205
|
+
one algorithm instead of an allowlist, ``audience`` and ``issuer`` mandatory
|
|
206
|
+
rather than optional, a lifetime the verifier has no use for.
|
|
207
|
+
|
|
208
|
+
The private key is read from ``private_key_path`` and never held as a field.
|
|
209
|
+
``__repr__`` redaction would not be enough: this is a ``msgspec.Struct``, so
|
|
210
|
+
``msgspec.json.encode`` and ``to_builtins`` emit every field verbatim without
|
|
211
|
+
going through it, and a config dump would publish the signing key.
|
|
212
|
+
|
|
213
|
+
Attributes:
|
|
214
|
+
private_key_path: Filesystem path of the PEM signing key, for
|
|
215
|
+
asymmetric algorithms. Mutually exclusive with ``secret``.
|
|
216
|
+
secret_path: Filesystem path of the shared secret for HS* algorithms.
|
|
217
|
+
Requires ``allow_symmetric_signing``. Mutually exclusive with
|
|
218
|
+
``private_key_path``.
|
|
219
|
+
algorithm: The single algorithm tokens are signed with. Issuing chooses
|
|
220
|
+
one; only verification negotiates an allowlist.
|
|
221
|
+
audience: ``aud`` stamped on every token. Mandatory: a token without an
|
|
222
|
+
audience is valid at any service that shares the key.
|
|
223
|
+
issuer: ``iss`` stamped on every token. Mandatory.
|
|
224
|
+
roles_claim: Claim carrying the caller roles. Mandatory, and never a
|
|
225
|
+
registered claim: an issuer that does not own that name lets an
|
|
226
|
+
attribute impersonate it. An identity without roles is refused.
|
|
227
|
+
ttl_seconds: Lifetime of a minted token, in ``1..MAX_ISSUER_TTL_SECONDS``,
|
|
228
|
+
and the ceiling for any per-call override.
|
|
229
|
+
kid: Key identifier stamped on the token header, so a verifier can
|
|
230
|
+
select the right key during a rotation overlap.
|
|
231
|
+
allow_symmetric_signing: Opt-in required for HS*. With a shared secret
|
|
232
|
+
every verifier can also mint, so the choice must be deliberate.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
ConfigError: If key sources, algorithm, audience, issuer, roles claim
|
|
236
|
+
or lifetime are invalid.
|
|
237
|
+
|
|
238
|
+
Note:
|
|
239
|
+
Built programmatically, not bound from a config section: issuing happens in
|
|
240
|
+
an application use case that injects the issuer, not in the REST layer that
|
|
241
|
+
owns ``app.rest.auth``. Resolve the values however the service resolves its
|
|
242
|
+
own settings.
|
|
243
|
+
|
|
244
|
+
Example::
|
|
245
|
+
|
|
246
|
+
config = JwtIssuerConfig(
|
|
247
|
+
private_key_path=os.environ["JWT_SIGNING_KEY_PATH"],
|
|
248
|
+
algorithm="EdDSA",
|
|
249
|
+
audience="my-api",
|
|
250
|
+
issuer="my-gateway",
|
|
251
|
+
roles_claim="loom_sql_roles",
|
|
252
|
+
ttl_seconds=900,
|
|
253
|
+
kid="2026-08",
|
|
254
|
+
)
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
private_key_path: str | None = None
|
|
258
|
+
secret_path: str | None = None
|
|
259
|
+
algorithm: str = ""
|
|
260
|
+
audience: str = ""
|
|
261
|
+
issuer: str = ""
|
|
262
|
+
roles_claim: str = ""
|
|
263
|
+
ttl_seconds: int = 900
|
|
264
|
+
kid: str | None = None
|
|
265
|
+
allow_symmetric_signing: bool = False
|
|
266
|
+
|
|
267
|
+
def __post_init__(self) -> None:
|
|
268
|
+
if (self.private_key_path is None) == (self.secret_path is None):
|
|
269
|
+
raise ConfigError(
|
|
270
|
+
"JWT issuer requires exactly one of 'private_key_path' or 'secret_path'."
|
|
271
|
+
)
|
|
272
|
+
_require_supported(self.algorithm, setting="JWT issuer 'algorithm'")
|
|
273
|
+
if not self.audience.strip():
|
|
274
|
+
raise ConfigError("JWT issuer requires a non-blank 'audience'.")
|
|
275
|
+
if not self.issuer.strip():
|
|
276
|
+
raise ConfigError("JWT issuer requires a non-blank 'issuer'.")
|
|
277
|
+
# Optional here is what let an attribute impersonate the verifier's roles
|
|
278
|
+
# claim: the issuer must always own that name.
|
|
279
|
+
_require_usable_roles_claim(self.roles_claim)
|
|
280
|
+
if self.kid is not None and not self.kid.strip():
|
|
281
|
+
raise ConfigError("JWT issuer 'kid' must not be blank.")
|
|
282
|
+
if not 0 < self.ttl_seconds <= MAX_ISSUER_TTL_SECONDS:
|
|
283
|
+
raise ConfigError(f"JWT issuer 'ttl_seconds' must be in 1..{MAX_ISSUER_TTL_SECONDS}.")
|
|
284
|
+
self._validate_signing_material()
|
|
285
|
+
|
|
286
|
+
def _validate_signing_material(self) -> None:
|
|
287
|
+
symmetric = _is_symmetric(self.algorithm)
|
|
288
|
+
if symmetric and not self.allow_symmetric_signing:
|
|
289
|
+
raise ConfigError(
|
|
290
|
+
f"JWT algorithm {self.algorithm!r} shares one key between signer and "
|
|
291
|
+
"verifier, so every verifier could also mint. Set "
|
|
292
|
+
"'allow_symmetric_signing' to accept that."
|
|
293
|
+
)
|
|
294
|
+
if symmetric and self.secret_path is None:
|
|
295
|
+
raise ConfigError(
|
|
296
|
+
f"JWT algorithm {self.algorithm!r} requires 'secret_path', not 'private_key_path'."
|
|
297
|
+
)
|
|
298
|
+
if not symmetric and self.private_key_path is None:
|
|
299
|
+
raise ConfigError(
|
|
300
|
+
f"JWT algorithm {self.algorithm!r} requires 'private_key_path', not 'secret_path'."
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def load_signing_key(self) -> str:
|
|
304
|
+
"""Read the signing key, so it lives in the issuer and not in the config.
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
The key material read from disk.
|
|
308
|
+
|
|
309
|
+
Raises:
|
|
310
|
+
ConfigError: If the file cannot be read or is not UTF-8 text. The
|
|
311
|
+
cause is never chained: an OS error carries the path, and a
|
|
312
|
+
``UnicodeDecodeError`` carries the file contents on ``exc.object``.
|
|
313
|
+
"""
|
|
314
|
+
source = self.secret_path or self.private_key_path
|
|
315
|
+
if source is None: # pragma: no cover - __post_init__ rules this out
|
|
316
|
+
raise ConfigError("JWT issuer has no signing key configured.")
|
|
317
|
+
return _read_key_file(source, setting="the JWT issuer signing key")
|