loom-kernel 0.9.1__tar.gz → 0.9.2__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.9.1 → loom_kernel-0.9.2}/CHANGELOG.md +17 -0
- loom_kernel-0.9.2/CHANGELOG_RELEASE.md +15 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/PKG-INFO +1 -1
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/pyproject.toml +2 -2
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/__init__.py +2 -0
- loom_kernel-0.9.2/src/loom/core/config/_resolver_utils.py +116 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/loader.py +1 -1
- loom_kernel-0.9.2/src/loom/core/config/secrets.py +144 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/ssm.py +6 -105
- loom_kernel-0.9.2/tests/unit/core/config/test_resolver_utils.py +130 -0
- loom_kernel-0.9.2/tests/unit/core/config/test_secrets.py +229 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/config/test_ssm.py +23 -7
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/uv.lock +1 -1
- loom_kernel-0.9.1/CHANGELOG_RELEASE.md +0 -52
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/.github/workflows/ci-main.yml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/.github/workflows/ci-pr.yml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/.github/workflows/docs.yml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/.github/workflows/release.yml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/.gitignore +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/.pre-commit-config.yaml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/.readthedocs.yaml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/LICENSE +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/Makefile +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/README.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/codecov.yml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/_static/.gitkeep +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/_static/custom.css +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/_static/logo-transparent.png +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/_static/logo.svg +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/architecture/adr/README.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/architecture/clean-architecture.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/architecture/overview.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/conf.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/etl/examples.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/etl/pipelines.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/etl/testing.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/examples-repo/index.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/getting-started/etl.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/getting-started/rest.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/getting-started/streaming.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/guides/autocrud.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/guides/celery.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/guides/etl.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/guides/fake-repo-examples.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/guides/quickstart.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/guides/use-case-dsl.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/index.rst +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/overview.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/reference/api/core.rst +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/reference/api/etl.rst +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/reference/api/repository.rst +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/reference/api/rest.rst +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/reference/api/streaming.rst +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/reference/api/testing.rst +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/reference/index.rst +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/requirements.txt +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/rest/autocrud.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/rest/celery.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/rest/examples.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/rest/testing.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/rest/use-case-dsl.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/docs/streaming/bytewax.md +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/sonar-project.properties +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/celery/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/celery/auto.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/celery/bootstrap.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/celery/config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/celery/constants.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/celery/runner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/celery/service.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/async_bridge.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/backend/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/backend/core_model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/backend/protocol.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/backend/sqlalchemy.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/bootstrap/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/bootstrap/bootstrap.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/bootstrap/kernel.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/abc/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/abc/backend.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/abc/config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/abc/dependency.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/codec.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/decorators.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/dependency.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/gateway.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/keys.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/repository.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/cache/serializer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/command/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/command/adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/command/base.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/command/field.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/command/introspection.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/binder.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/configurable.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/context.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/keys.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/observability.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/config/resolver.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/contracts/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/contracts/manifest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/di/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/di/container.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/di/scope.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/discovery/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/discovery/_utils.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/discovery/base.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/discovery/interfaces.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/discovery/manifest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/discovery/modules.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/engine/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/engine/compilable.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/engine/compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/engine/events.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/engine/executor.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/engine/metrics.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/engine/plan.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/errors/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/errors/codes.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/errors/errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/expr/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/expr/eval.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/expr/nodes.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/expr/refs.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/job/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/job/callback.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/job/context.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/job/handle.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/job/job.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/job/service.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/logger/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/logger/abc.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/logger/config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/logger/registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/logger/structlogger.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/base.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/enums.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/field.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/introspection.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/projection.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/relation.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/struct.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/timestamped.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/types.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/model/types_postgres.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/event.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/observer/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/observer/noop.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/observer/otel.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/observer/structlog.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/protocol.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/runtime.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/observability/topology.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/projection/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/projection/loaders.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/projection/runtime.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/abc/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/abc/query.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/abc/repo_for.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/abc/repository.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/mutation.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/registration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/mixins.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/session_manager.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/response/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/response/base.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/routing/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/routing/ref.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/routing/resolver.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/runner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/schema/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/schema/schema_mode.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/tracing/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/tracing/context.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/transport/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/transport/adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/uow/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/uow/abc.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/uow/context.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/_predicates.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/compute.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/constants.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/factory.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/field_ref.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/invoker.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/keys.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/markers.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/rule.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/core/use_case/use_case.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_format_registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_historify/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_historify/_common.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_historify/_log.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_historify/_ops.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_historify/_transform.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_merge.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_predicate.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_schema_aligner/_policy.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/_write_policy.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/_dtype.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/_file_writer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/_historify.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/_predicate.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/_reader.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/_schema.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/_writer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/polars/provider.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/spark/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/spark/_dtype.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/spark/_historify.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/spark/_reader.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/spark/_schema.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/spark/_writer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/backends/spark/provider.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/checkpoint/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/checkpoint/_backends/_polars.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/checkpoint/_cleaners.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/checkpoint/_paths.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/checkpoint/_scope.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/checkpoint/_store.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/compiler/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/compiler/_binding.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/compiler/_compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/compiler/_errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/compiler/_plan.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/compiler/_validators.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/compiler/_validators_plan.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/compiler/_validators_step.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/_format.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/_read_options.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/_utils.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/_write_options.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/expr/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/expr/_params.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/expr/_predicate.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/expr/_refs.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/source/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/source/_from.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/source/_specs.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_file.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_history/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_history/_builder.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_history/_errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_history/_report.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_history/_spec.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_into.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_schema_mode.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_table.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/declarative/target/_temp.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/executor/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/executor/_dispatcher.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/executor/_executor.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/_registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/sources/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/sources/_clickhouse.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/sources/_mongo.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/targets/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/io/targets/_clickhouse.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/lineage/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/lineage/_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/lineage/_observer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/lineage/_records.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/lineage/sinks/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/lineage/sinks/_table.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/lineage/sinks/_writer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/pipeline/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/pipeline/_generics.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/pipeline/_params.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/pipeline/_pipeline.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/pipeline/_process.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/pipeline/_sql.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/pipeline/_step.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/pipeline/_step_sql.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runner/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runner/_providers.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runner/_wiring.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runner/config_loader.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runner/core.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runner/errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runner/filtering.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runtime/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/runtime/contracts.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/schema/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/schema/_contract.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/schema/_schema.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/storage/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/storage/_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/storage/_file_locator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/storage/_locator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/storage/routing.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/testing/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/testing/_result.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/testing/_runners.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/testing/_scenario.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/testing/_stubs.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/etl/testing/spark.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/prometheus/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/prometheus/adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/prometheus/kafka.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/prometheus/lifecycle.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/prometheus/middleware.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/py.typed +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/autocrud.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/constants.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/fastapi/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/fastapi/app.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/fastapi/auto.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/fastapi/openapi.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/fastapi/response.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/fastapi/router_runtime.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/middleware.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/rest/rest_adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/_adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/_dlq.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/_operators.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/_runtime_io.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/_shared.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/steps.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/bytewax/runner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/compiler/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/compiler/_bindings.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/compiler/_compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/compiler/_plan.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/compiler/phases/build_plan.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/compiler/phases/validate.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/core/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/core/_errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/core/_exceptions.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/core/_message.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/core/_typing.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/graph/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/graph/_flow.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/_codec.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/_errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/_key_resolver.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/_message.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/_record.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/_wire.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/client/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/client/_consumer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/client/_producer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/client/_protocol.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/message/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/message/_consumer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/message/_producer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/kafka/message/_protocol.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/mongo/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/mongo/_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/mongo/_event.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/mongo/_normalize.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_boundary.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_broadcast.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_capabilities.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_decompose.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_expand_routes.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_expr_eval.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_fork.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_helpers.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_mongo.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_protocols.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_router.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_shape.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_sink.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_step.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_table/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_table/common.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_table/config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/_with.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/nodes/refs.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/streaming/testing.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/testing/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/testing/golden.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/testing/http_harness.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/testing/in_memory.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/testing/repository_harness.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/src/loom/testing/runner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/golden/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/golden/baselines/.gitkeep +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/golden/outputs/.gitkeep +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/golden/plans/.gitkeep +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/helpers/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/celery_bootstrap/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/celery_bootstrap/config/conf.celery.integration.yaml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/celery_bootstrap/test_auto_create_app_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/celery_bootstrap/test_bootstrap_worker.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/bootstrap/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/bootstrap/test_bootstrap_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/repository/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/repository/sqlalchemy/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/repository/sqlalchemy/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/repository/sqlalchemy/test_cache_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/repository/sqlalchemy/test_repository_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/rest/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/rest/test_auto_interface_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/rest/test_fastapi_app_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/rest/test_rest_error_mapping.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/rest/test_rest_observability.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/use_case/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/use_case/test_custom_repository_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/core/use_case/test_use_case_crud_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/etl/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/etl/test_runner_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/config/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/config/conf.interfaces.yaml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/config/conf.manifest.yaml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/config/conf.modules.yaml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/config/conf.yaml +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/main.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/manifest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/category/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/category/model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/category/schemas.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/interface.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/jobs.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/relations.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/repository.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/repository_contract.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/review/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/review/model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/review/schemas.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/schemas.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/fake_repo/product/use_cases.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/streaming/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/streaming/test_into_table_integration.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/support/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/integration/support/logical_repo_fixtures.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/celery_bootstrap/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/celery_bootstrap/test_async_runtime.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/celery_bootstrap/test_bootstrap.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/celery_jobs/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/celery_jobs/test_auto.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/celery_jobs/test_celery_service.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/celery_jobs/test_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/celery_jobs/test_runner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/backend/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/backend/test_backend_compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/bootstrap/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/bootstrap/test_bootstrap.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/bootstrap/test_bootstrap_metrics.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/bootstrap/test_kernel.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/cache/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/cache/test_cached_repository.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/command/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/command/test_command_base.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/command/test_command_field.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/command/test_command_patch.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/command/test_introspection.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/config/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/config/test_binder.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/config/test_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/config/test_configurable.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/config/test_context.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/di/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/di/test_container.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/discovery/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/discovery/test_manifest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/engine/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/engine/test_compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/engine/test_executor.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/engine/test_executor_trace.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/engine/test_executor_uow.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/engine/test_metrics.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/engine/test_plan.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/errors/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/errors/test_errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/expr/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/expr/test_expr.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/job/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/job/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/job/test_callback.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/job/test_context.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/job/test_handle.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/job/test_inline_service.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/job/test_job.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/logger/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/logger/test_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/logger/test_registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/model/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/model/test_model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/model/test_struct.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/model/test_timestamped.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/observability/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/observability/test_observers.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/observability/test_runtime.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/projection/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/projection/test_runtime.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/abc/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/abc/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/abc/test_query.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/abc/test_repository_contract.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/sqlalchemy/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/sqlalchemy/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/sqlalchemy/test_loaders.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/sqlalchemy/test_repository.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/repository/sqlalchemy/test_transactional.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/routing/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/routing/test_routing.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/test_async_bridge.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/test_compiler_contracts.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/test_runner_contracts.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/tracing/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/tracing/test_context.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/uow/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/uow/test_executor_uow.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/uow/test_sqlalchemy_uow.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/uow/test_uow_protocols.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/use_case/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/use_case/test_compute.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/use_case/test_factory.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/use_case/test_field_ref.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/use_case/test_invoker.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/use_case/test_markers.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/use_case/test_rule.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/core/use_case/test_use_case.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/_historify_contract.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_historify_common.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_apply_schema.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_backend.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_dtype.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_file_writer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_historify_polars.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_predicate_pushdown.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_reader_columns.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_reader_json_columns.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_step_execution.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_upsert_writer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_writer_null_schema.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_polars/test_writer_to_frame.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_spark/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_spark/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_spark/test_dtype.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_spark/test_historify_spark.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_spark/test_spark_apply_schema.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_spark/test_step_execution.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_spark/test_writer_to_frame.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/backends/test_write_policy_historify.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/checkpoint/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/checkpoint/backends/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/checkpoint/backends/test_checkpoint_polars.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/checkpoint/test_checkpoint_paths.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/checkpoint/test_cleaners.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/checkpoint/test_store.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_catalog_validator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_compiler_catalog.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_compiler_upsert.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_errors_additional_factories.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_errors_runtime_factories.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_historify_validator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_param_exprs_validator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_plan_traversal.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_step_validator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_structural.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_temp_validator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/compiler/test_upsert_validator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/sources/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/sources/test_clickhouse_reader.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/sources/test_from_clickhouse.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/sources/test_from_mongo.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/sources/test_mongo_predicate.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/sources/test_mongo_reader.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/targets/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/targets/test_clickhouse_writer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/targets/test_into_clickhouse.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/test_history_target.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/test_registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/test_source.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/test_source_json.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/test_source_options.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/test_target.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/test_utils.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/io/test_variants.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/lineage/test_observer.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/lineage/test_records.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/lineage/test_store.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/pipeline/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/pipeline/test_pipeline_process.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/pipeline/test_proxy.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/pipeline/test_step.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/schema/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/schema/test_contract.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/schema/test_schema.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/schema/test_table.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/sql/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/sql/test_merge.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/sql/test_predicate.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/sql/test_predicate_dialect.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/sql/test_sql_runtime.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/storage/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/storage/test_backend_factory.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/storage/test_io_protocols.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/storage/test_locator.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/storage/test_observability_and_protocols.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/storage/test_route_build.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/storage/test_schema_readers.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/storage/test_storage_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_config_loader.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_executor.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_format_registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_module_contracts.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_public_api_discovery.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_record_schema_coverage.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_runner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_runner_errors.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/test_spark_testing.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/testing/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/testing/test_runners.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/testing/test_scenario_and_stubs.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/etl/testing/test_spark_helpers.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/prometheus/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/prometheus/test_adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/prometheus/test_middleware.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_autocrud.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_fastapi_auto_logger.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_middleware.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_pydantic_adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_response.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_rest_adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_rest_compiler.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_rest_model.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/rest/test_router_runtime.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/cases.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_adapter.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_batch_key.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_bytewax_dispatcher.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_collect_batch.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_dlq.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_error_boundary.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_operators.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_resource_manager.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_runner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_runtime_io.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_runtime_sink.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_runtime_source.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_sink_registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_steps.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/bytewax/test_storage.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/cases.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/test_async_walk.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/test_basics.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/test_config_bindings.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/test_mongo_source.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/test_multi_source.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/test_router.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/test_window.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/compiler/test_with.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/contracts/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/contracts/cases.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/contracts/test_boundary.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/contracts/test_message.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/contracts/test_mongo_contracts.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/contracts/test_multi_boundary.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/contracts/test_steps.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/cases/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/cases/batch.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/cases/explode.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/cases/fork.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/cases/router.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/cases/shared.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/cases/simple.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/test_compiler_examples.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/flows/test_flow_examples.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/cases.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/fakes.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_client.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_key_resolver.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_message.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_message_client.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_multi_wire.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_observability.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_settings.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/kafka/test_wire.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/mongo/test_bytewax_source.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/nodes/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/nodes/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/nodes/test_broadcast.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/nodes/test_delta_config.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/nodes/test_logging.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/nodes/test_table_package.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/observability/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/observability/cases.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/observability/conftest.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/observability/test_observability_runner.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/observability/test_protocols.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/observability/test_registry.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/observability/test_structlog.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/support/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/support/flow_cases.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/test_expand_routes.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/test_fork.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/test_otel_observability.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/test_routing.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/test_testing_mongo.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/streaming/test_with.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/testing/__init__.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/testing/test_golden.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/testing/test_http_harness.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/testing/test_in_memory.py +0 -0
- {loom_kernel-0.9.1 → loom_kernel-0.9.2}/tests/unit/testing/test_runner.py +0 -0
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# 🚀 Release 0.9.2 ([#39](https://github.com/the-reacher-data/loom-py/pull/39)) ([`f1a482d`](https://github.com/the-reacher-data/loom-py/commit/f1a482d03f8b83f8e0c7725e7af6160466ac6126))
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## ✨ Features
|
|
5
|
+
### config
|
|
6
|
+
- **config:** add SecretsManagerResolver + shared resolver utilities
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
1
18
|
# 🚀 Release 0.9.1 ([#36](https://github.com/the-reacher-data/loom-py/pull/36)) ([`5c420c9`](https://github.com/the-reacher-data/loom-py/commit/5c420c9dd4efe0f697affb8a921054bc6504358f))
|
|
2
19
|
|
|
3
20
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# 🚀 Release 0.9.2 ([#39](https://github.com/the-reacher-data/loom-py/pull/39)) ([`f1a482d`](https://github.com/the-reacher-data/loom-py/commit/f1a482d03f8b83f8e0c7725e7af6160466ac6126))
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## ✨ Features
|
|
5
|
+
### config
|
|
6
|
+
- **config:** add SecretsManagerResolver + shared resolver utilities
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "loom-kernel"
|
|
3
|
-
version = "0.9.
|
|
3
|
+
version = "0.9.2"
|
|
4
4
|
description = "Loom Python project"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -247,7 +247,7 @@ markers = [
|
|
|
247
247
|
|
|
248
248
|
[tool.commitizen]
|
|
249
249
|
name = "cz_conventional_commits"
|
|
250
|
-
version = "0.9.
|
|
250
|
+
version = "0.9.2"
|
|
251
251
|
tag_format = "v$version"
|
|
252
252
|
version_files = [
|
|
253
253
|
"pyproject.toml:project.version",
|
|
@@ -20,6 +20,7 @@ from loom.core.config.keys import ConfigKey
|
|
|
20
20
|
from loom.core.config.loader import load_config, section
|
|
21
21
|
from loom.core.config.observability import OtelConfig
|
|
22
22
|
from loom.core.config.resolver import ConfigResolver
|
|
23
|
+
from loom.core.config.secrets import SecretsManagerResolver
|
|
23
24
|
from loom.core.config.ssm import SsmResolver
|
|
24
25
|
|
|
25
26
|
__all__ = [
|
|
@@ -30,6 +31,7 @@ __all__ = [
|
|
|
30
31
|
"ConfigResolver",
|
|
31
32
|
"Configurable",
|
|
32
33
|
"OtelConfig",
|
|
34
|
+
"SecretsManagerResolver",
|
|
33
35
|
"SsmResolver",
|
|
34
36
|
"StructBinder",
|
|
35
37
|
"load_config",
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Shared utilities for config resolvers (SSM, Secrets Manager, etc.)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
|
|
9
|
+
from loom.core.config.errors import ConfigError
|
|
10
|
+
|
|
11
|
+
_ENV_VAR_PATTERN = re.compile(r"%([A-Z][A-Z0-9_]*)%")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _expand_env_vars(key: str) -> str:
|
|
15
|
+
"""Expand ``%VAR_NAME%`` placeholders in *key* using environment variables.
|
|
16
|
+
|
|
17
|
+
Only uppercase identifiers matching ``[A-Z][A-Z0-9_]*`` are expanded.
|
|
18
|
+
The ``%VAR%`` syntax avoids conflicts with OmegaConf's ANTLR grammar,
|
|
19
|
+
which rejects bare ``{`` inside ``${resolver:...}`` interpolations.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
key: Resolver path, possibly containing ``%VAR_NAME%`` tokens.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Path with all tokens replaced by their environment variable values.
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
ConfigError: When a referenced variable is absent from the environment.
|
|
29
|
+
"""
|
|
30
|
+
if not _ENV_VAR_PATTERN.search(key):
|
|
31
|
+
return key
|
|
32
|
+
|
|
33
|
+
def _replace(match: re.Match[str]) -> str:
|
|
34
|
+
var_name = match.group(1)
|
|
35
|
+
value = os.environ.get(var_name)
|
|
36
|
+
if value is None:
|
|
37
|
+
raise ConfigError(
|
|
38
|
+
f"Env var {var_name!r} not found in environment "
|
|
39
|
+
f"(referenced in resolver path {key!r})"
|
|
40
|
+
)
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
return _ENV_VAR_PATTERN.sub(_replace, key)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _split_resolver_key(key: str) -> tuple[str, list[str]]:
|
|
47
|
+
"""Split a resolver key into the base path and JSON navigation keys.
|
|
48
|
+
|
|
49
|
+
The first dot after the last '/' separator marks the start of a JSON key
|
|
50
|
+
path. Both SSM and Secrets Manager use '/' as path separator, so a dot
|
|
51
|
+
is unambiguously a JSON navigation token.
|
|
52
|
+
|
|
53
|
+
Note: ARN-style SecretIds (``arn:aws:secretsmanager:...``) are not
|
|
54
|
+
supported for dot-notation — use short names instead.
|
|
55
|
+
|
|
56
|
+
**Limitation — env-var values with dots in the final path segment:**
|
|
57
|
+
If a ``%VAR%`` token expands to a value that contains a dot *and* that
|
|
58
|
+
token appears in the last path segment (after the final ``/``), the dot
|
|
59
|
+
will be interpreted as a JSON navigation separator, producing a confusing
|
|
60
|
+
``ConfigError``. Example: ``/app/svc/%ENV%`` where ``ENV=db.prod`` becomes
|
|
61
|
+
``/app/svc/db`` with JSON key ``["prod"]``. Use env-var tokens only in
|
|
62
|
+
path segments that are guaranteed to be dot-free (environment names,
|
|
63
|
+
region codes, etc.).
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
key: Expanded resolver key, e.g. ``"/app/prod/db_config.host"``.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
A 2-tuple ``(base_path, json_keys)`` where *base_path* is the path
|
|
70
|
+
to fetch and *json_keys* is a list of dict keys to navigate
|
|
71
|
+
(empty list when no dot-notation is present).
|
|
72
|
+
"""
|
|
73
|
+
if not key:
|
|
74
|
+
return key, []
|
|
75
|
+
last_slash = key.rfind("/")
|
|
76
|
+
after_last_slash = key[last_slash + 1 :] if last_slash != -1 else key
|
|
77
|
+
dot_pos = after_last_slash.find(".")
|
|
78
|
+
if dot_pos == -1:
|
|
79
|
+
return key, []
|
|
80
|
+
base_end = (last_slash + 1 + dot_pos) if last_slash != -1 else dot_pos
|
|
81
|
+
json_tail = key[base_end + 1 :]
|
|
82
|
+
return key[:base_end], [k for k in json_tail.split(".") if k]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _navigate_json(raw: str, keys: list[str], path: str) -> object:
|
|
86
|
+
"""Parse *raw* as JSON and navigate to the value at *keys*.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
raw: Raw string value from the resolver backend.
|
|
90
|
+
keys: Ordered list of dict keys to traverse.
|
|
91
|
+
path: Original path, used only in error messages.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
The value at the navigated position. May be any JSON-compatible type.
|
|
95
|
+
|
|
96
|
+
Raises:
|
|
97
|
+
ConfigError: When *raw* is not valid JSON, or a key is absent.
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
data: object = json.loads(raw)
|
|
101
|
+
except json.JSONDecodeError as exc:
|
|
102
|
+
# Suppress chain (from None) — JSONDecodeError.doc holds the raw secret
|
|
103
|
+
# and would be exposed via __cause__ in tracebacks / APM serialisation.
|
|
104
|
+
raise ConfigError(
|
|
105
|
+
f"Resolver path {path!r} value is not valid JSON "
|
|
106
|
+
f"(required for key navigation): {exc.msg} at position {exc.pos}"
|
|
107
|
+
) from None
|
|
108
|
+
current: object = data
|
|
109
|
+
for k in keys:
|
|
110
|
+
if not isinstance(current, dict) or k not in current:
|
|
111
|
+
raise ConfigError(f"Key {k!r} not found at resolver path {path!r}")
|
|
112
|
+
current = current[k]
|
|
113
|
+
return current
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
__all__ = ["_expand_env_vars", "_split_resolver_key", "_navigate_json"]
|
|
@@ -212,7 +212,7 @@ def _register_resolvers(resolvers: Sequence[Any], omega_conf: Any) -> None:
|
|
|
212
212
|
"""
|
|
213
213
|
for resolver in resolvers:
|
|
214
214
|
with contextlib.suppress(Exception):
|
|
215
|
-
omega_conf.register_new_resolver(resolver.name, resolver.resolve)
|
|
215
|
+
omega_conf.register_new_resolver(resolver.name, resolver.resolve, use_cache=True)
|
|
216
216
|
|
|
217
217
|
|
|
218
218
|
def load_config(
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""AWS Secrets Manager resolver for loom configuration.
|
|
2
|
+
|
|
3
|
+
Resolves ``${secrets:/path/to/secret}`` placeholders in OmegaConf configs
|
|
4
|
+
by fetching values from AWS Secrets Manager at parse time.
|
|
5
|
+
|
|
6
|
+
Example::
|
|
7
|
+
|
|
8
|
+
from loom.core.config import load_config
|
|
9
|
+
from loom.core.config.secrets import SecretsManagerResolver
|
|
10
|
+
|
|
11
|
+
cfg = load_config("config/prod.yaml", resolvers=[SecretsManagerResolver("eu-west-1")])
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
import boto3 as _boto3_module # type: ignore[import-untyped]
|
|
21
|
+
except ImportError:
|
|
22
|
+
_boto3_module = None
|
|
23
|
+
|
|
24
|
+
from loom.core.config._resolver_utils import (
|
|
25
|
+
_expand_env_vars,
|
|
26
|
+
_navigate_json,
|
|
27
|
+
_split_resolver_key,
|
|
28
|
+
)
|
|
29
|
+
from loom.core.config.errors import ConfigError
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _fetch_secret(client: Any, name: str) -> str:
|
|
35
|
+
"""Fetch a string secret value from AWS Secrets Manager.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
client: Boto3 secretsmanager client.
|
|
39
|
+
name: Secret name or short ARN. ARN-style names are supported for
|
|
40
|
+
plain fetches but not for dot-notation JSON navigation.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The secret value as a string.
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
ConfigError: When the secret is binary, or on any API error.
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
result = client.get_secret_value(SecretId=name)
|
|
50
|
+
except Exception as exc:
|
|
51
|
+
raise ConfigError(f"Failed to fetch Secrets Manager secret {name!r}: {exc}") from exc
|
|
52
|
+
if "SecretString" not in result:
|
|
53
|
+
raise ConfigError(
|
|
54
|
+
f"Secrets Manager secret {name!r} is binary — only string secrets are supported"
|
|
55
|
+
)
|
|
56
|
+
return str(result["SecretString"])
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class SecretsManagerResolver:
|
|
60
|
+
"""Resolves AWS Secrets Manager paths for use with :func:`~loom.core.config.load_config`.
|
|
61
|
+
|
|
62
|
+
Fetches secret values from AWS Secrets Manager. The boto3 client is
|
|
63
|
+
created lazily on first use and reused across calls.
|
|
64
|
+
|
|
65
|
+
Env-var tokens in the form ``%VAR_NAME%`` (uppercase letters, digits,
|
|
66
|
+
and underscores only) are expanded from ``os.environ`` before the
|
|
67
|
+
request is made.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
region: AWS region name. Passed directly to ``boto3.client``.
|
|
71
|
+
Defaults to ``None``, which lets boto3 use its own resolution
|
|
72
|
+
chain (env vars, instance metadata, etc.).
|
|
73
|
+
|
|
74
|
+
Example::
|
|
75
|
+
|
|
76
|
+
resolver = SecretsManagerResolver("eu-west-1")
|
|
77
|
+
value = resolver.resolve("/myapp/%ENV%/db_password")
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init__(self, region: str | None = None) -> None:
|
|
81
|
+
self._region = region
|
|
82
|
+
self._client: Any = None
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def name(self) -> str:
|
|
86
|
+
"""OmegaConf resolver prefix.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
The string ``"secrets"``.
|
|
90
|
+
"""
|
|
91
|
+
return "secrets"
|
|
92
|
+
|
|
93
|
+
def _get_client(self) -> Any:
|
|
94
|
+
"""Return the boto3 secretsmanager client, creating it on first call.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
A boto3 secretsmanager client instance.
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
ConfigError: When boto3 is not installed.
|
|
101
|
+
"""
|
|
102
|
+
if self._client is None:
|
|
103
|
+
if _boto3_module is None:
|
|
104
|
+
raise ConfigError(
|
|
105
|
+
"boto3 is required for SecretsManagerResolver. "
|
|
106
|
+
"Install it with: pip install loom[config-ssm]"
|
|
107
|
+
)
|
|
108
|
+
self._client = _boto3_module.client("secretsmanager", region_name=self._region)
|
|
109
|
+
return self._client
|
|
110
|
+
|
|
111
|
+
def resolve(self, key: str) -> object:
|
|
112
|
+
"""Resolve an AWS Secrets Manager path to its stored value.
|
|
113
|
+
|
|
114
|
+
Expands ``%VAR_NAME%`` tokens in *key* from the environment, then
|
|
115
|
+
fetches the secret from AWS Secrets Manager.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
key: Secret path, optionally containing ``%VAR_NAME%``
|
|
119
|
+
placeholders that are replaced with environment variable values.
|
|
120
|
+
Supports dot-notation for JSON key navigation: ``/path/secret.key``
|
|
121
|
+
fetches ``/path/secret`` and returns ``secret["key"]``.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Resolved value. A plain string for secrets without dot-notation;
|
|
125
|
+
a structured value (string, int, dict, etc.) when dot-notation
|
|
126
|
+
navigates into a JSON secret.
|
|
127
|
+
|
|
128
|
+
Raises:
|
|
129
|
+
ConfigError: When *key* is empty, an env-var placeholder is
|
|
130
|
+
missing, boto3 is not installed, the secret is binary,
|
|
131
|
+
or the API call fails.
|
|
132
|
+
"""
|
|
133
|
+
if not key:
|
|
134
|
+
raise ConfigError("Secrets Manager key must not be empty")
|
|
135
|
+
expanded = _expand_env_vars(key)
|
|
136
|
+
path, json_keys = _split_resolver_key(expanded)
|
|
137
|
+
logger.info("secrets_resolver: fetching %s", path)
|
|
138
|
+
raw = _fetch_secret(self._get_client(), path)
|
|
139
|
+
if not json_keys:
|
|
140
|
+
return raw
|
|
141
|
+
return _navigate_json(raw, json_keys, path)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
__all__ = ["SecretsManagerResolver"]
|
|
@@ -13,10 +13,7 @@ Example::
|
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
|
-
import json
|
|
17
16
|
import logging
|
|
18
|
-
import os
|
|
19
|
-
import re
|
|
20
17
|
from typing import Any
|
|
21
18
|
|
|
22
19
|
try:
|
|
@@ -24,42 +21,11 @@ try:
|
|
|
24
21
|
except ImportError:
|
|
25
22
|
_boto3_module = None
|
|
26
23
|
|
|
24
|
+
from loom.core.config._resolver_utils import _expand_env_vars, _navigate_json, _split_resolver_key
|
|
27
25
|
from loom.core.config.errors import ConfigError
|
|
28
26
|
|
|
29
27
|
logger = logging.getLogger(__name__)
|
|
30
28
|
|
|
31
|
-
_ENV_VAR_PATTERN = re.compile(r"\{([A-Z][A-Z0-9_]*)\}")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _expand_env_vars(key: str) -> str:
|
|
35
|
-
"""Expand ``{VAR_NAME}`` placeholders in *key* using environment variables.
|
|
36
|
-
|
|
37
|
-
Only uppercase identifiers matching ``[A-Z][A-Z0-9_]*`` are expanded.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
key: SSM parameter path, possibly containing ``{VAR_NAME}`` tokens.
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
Path with all tokens replaced by their environment variable values.
|
|
44
|
-
|
|
45
|
-
Raises:
|
|
46
|
-
ConfigError: When a referenced variable is absent from the environment.
|
|
47
|
-
"""
|
|
48
|
-
matches = _ENV_VAR_PATTERN.findall(key)
|
|
49
|
-
if not matches:
|
|
50
|
-
return key
|
|
51
|
-
|
|
52
|
-
def _replace(match: re.Match[str]) -> str:
|
|
53
|
-
var_name = match.group(1)
|
|
54
|
-
value = os.environ.get(var_name)
|
|
55
|
-
if value is None:
|
|
56
|
-
raise ConfigError(
|
|
57
|
-
f"Env var {var_name!r} not found in environment (referenced in SSM path {key!r})"
|
|
58
|
-
)
|
|
59
|
-
return value
|
|
60
|
-
|
|
61
|
-
return _ENV_VAR_PATTERN.sub(_replace, key)
|
|
62
|
-
|
|
63
29
|
|
|
64
30
|
def _fetch_parameter(client: Any, name: str, with_decryption: bool) -> str:
|
|
65
31
|
"""Fetch a single parameter value from AWS SSM.
|
|
@@ -82,78 +48,13 @@ def _fetch_parameter(client: Any, name: str, with_decryption: bool) -> str:
|
|
|
82
48
|
return str(result["Parameter"]["Value"])
|
|
83
49
|
|
|
84
50
|
|
|
85
|
-
def _split_ssm_key(key: str) -> tuple[str, list[str]]:
|
|
86
|
-
"""Split an SSM key into the parameter path and JSON navigation keys.
|
|
87
|
-
|
|
88
|
-
The first dot after the last '/' separator marks the start of a JSON key
|
|
89
|
-
path. SSM paths use '/' as their separator, so a dot is unambiguously a
|
|
90
|
-
JSON navigation token.
|
|
91
|
-
|
|
92
|
-
Args:
|
|
93
|
-
key: Expanded SSM key, e.g. ``"/app/prod/db_config.host"``.
|
|
94
|
-
|
|
95
|
-
Returns:
|
|
96
|
-
A 2-tuple ``(ssm_path, json_keys)`` where *ssm_path* is the SSM
|
|
97
|
-
parameter path to fetch and *json_keys* is a list of dict keys to
|
|
98
|
-
navigate (empty list when no dot-notation is present).
|
|
99
|
-
|
|
100
|
-
Examples:
|
|
101
|
-
>>> _split_ssm_key("/app/prod/token")
|
|
102
|
-
('/app/prod/token', [])
|
|
103
|
-
>>> _split_ssm_key("/app/prod/db_config.host")
|
|
104
|
-
('/app/prod/db_config', ['host'])
|
|
105
|
-
>>> _split_ssm_key("/app/prod/db.connection.host")
|
|
106
|
-
('/app/prod/db', ['connection', 'host'])
|
|
107
|
-
"""
|
|
108
|
-
if not key:
|
|
109
|
-
return key, []
|
|
110
|
-
last_slash = key.rfind("/")
|
|
111
|
-
after_last_slash = key[last_slash + 1 :] if last_slash != -1 else key
|
|
112
|
-
dot_pos = after_last_slash.find(".")
|
|
113
|
-
if dot_pos == -1:
|
|
114
|
-
return key, []
|
|
115
|
-
base_end = (last_slash + 1 + dot_pos) if last_slash != -1 else dot_pos
|
|
116
|
-
json_tail = key[base_end + 1 :]
|
|
117
|
-
return key[:base_end], [k for k in json_tail.split(".") if k]
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def _navigate_json(raw: str, keys: list[str], ssm_path: str) -> object:
|
|
121
|
-
"""Parse *raw* as JSON and navigate to the value at *keys*.
|
|
122
|
-
|
|
123
|
-
Args:
|
|
124
|
-
raw: Raw string value from SSM.
|
|
125
|
-
keys: Ordered list of dict keys to traverse.
|
|
126
|
-
ssm_path: Original SSM path, used only in error messages.
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
The value at the navigated position. May be any JSON-compatible type.
|
|
130
|
-
|
|
131
|
-
Raises:
|
|
132
|
-
ConfigError: When *raw* is not valid JSON, or a key is absent.
|
|
133
|
-
"""
|
|
134
|
-
try:
|
|
135
|
-
data: object = json.loads(
|
|
136
|
-
raw
|
|
137
|
-
) # json.loads returns Any; annotated as object to avoid implicit Any propagation
|
|
138
|
-
except json.JSONDecodeError as exc:
|
|
139
|
-
raise ConfigError(
|
|
140
|
-
f"SSM parameter {ssm_path!r} is not valid JSON (required for key navigation): {exc}"
|
|
141
|
-
) from exc
|
|
142
|
-
current: object = data
|
|
143
|
-
for k in keys:
|
|
144
|
-
if not isinstance(current, dict) or k not in current:
|
|
145
|
-
raise ConfigError(f"Key {k!r} not found in SSM parameter {ssm_path!r}")
|
|
146
|
-
current = current[k]
|
|
147
|
-
return current
|
|
148
|
-
|
|
149
|
-
|
|
150
51
|
class SsmResolver:
|
|
151
52
|
"""Resolves SSM Parameter Store paths for use with :func:`~loom.core.config.load_config`.
|
|
152
53
|
|
|
153
54
|
Fetches parameter values from AWS Systems Manager Parameter Store.
|
|
154
55
|
The boto3 client is created lazily on first use and reused across calls.
|
|
155
56
|
|
|
156
|
-
Env-var tokens in the form
|
|
57
|
+
Env-var tokens in the form ``%VAR_NAME%`` (uppercase letters, digits,
|
|
157
58
|
and underscores only) are expanded from ``os.environ`` before the
|
|
158
59
|
SSM request is made.
|
|
159
60
|
|
|
@@ -167,7 +68,7 @@ class SsmResolver:
|
|
|
167
68
|
Example::
|
|
168
69
|
|
|
169
70
|
resolver = SsmResolver("eu-west-1")
|
|
170
|
-
value = resolver.resolve("/myapp
|
|
71
|
+
value = resolver.resolve("/myapp/%ENV%/db_password")
|
|
171
72
|
"""
|
|
172
73
|
|
|
173
74
|
def __init__(
|
|
@@ -210,11 +111,11 @@ class SsmResolver:
|
|
|
210
111
|
def resolve(self, key: str) -> object:
|
|
211
112
|
"""Resolve an SSM parameter path to its stored value.
|
|
212
113
|
|
|
213
|
-
Expands
|
|
114
|
+
Expands ``%VAR_NAME%`` tokens in *key* from the environment, then
|
|
214
115
|
fetches the parameter from AWS SSM Parameter Store.
|
|
215
116
|
|
|
216
117
|
Args:
|
|
217
|
-
key: SSM parameter path, optionally containing
|
|
118
|
+
key: SSM parameter path, optionally containing ``%VAR_NAME%``
|
|
218
119
|
placeholders that are replaced with environment variable values.
|
|
219
120
|
Supports dot-notation for JSON key navigation: ``/path/param.key``
|
|
220
121
|
fetches ``/path/param`` and returns ``param["key"]``.
|
|
@@ -231,7 +132,7 @@ class SsmResolver:
|
|
|
231
132
|
if not key:
|
|
232
133
|
raise ConfigError("SSM key must not be empty")
|
|
233
134
|
expanded = _expand_env_vars(key)
|
|
234
|
-
ssm_path, json_keys =
|
|
135
|
+
ssm_path, json_keys = _split_resolver_key(expanded)
|
|
235
136
|
logger.info("ssm_resolver: fetching %s", ssm_path)
|
|
236
137
|
client = self._get_client()
|
|
237
138
|
raw = _fetch_parameter(client, ssm_path, self._with_decryption)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Unit tests for shared resolver utilities (_resolver_utils).
|
|
2
|
+
|
|
3
|
+
Tests _split_resolver_key, _expand_env_vars, and _navigate_json directly
|
|
4
|
+
to catch edge-case regressions that are only indirectly covered by the
|
|
5
|
+
SSM and Secrets Manager resolver test suites.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from loom.core.config._resolver_utils import (
|
|
13
|
+
_expand_env_vars,
|
|
14
|
+
_navigate_json,
|
|
15
|
+
_split_resolver_key,
|
|
16
|
+
)
|
|
17
|
+
from loom.core.config.errors import ConfigError
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# _split_resolver_key
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestSplitResolverKey:
|
|
25
|
+
def test_empty_string_returns_empty_and_no_keys(self) -> None:
|
|
26
|
+
assert _split_resolver_key("") == ("", [])
|
|
27
|
+
|
|
28
|
+
def test_plain_path_no_dot_returns_path_and_empty_keys(self) -> None:
|
|
29
|
+
assert _split_resolver_key("/prod/token") == ("/prod/token", [])
|
|
30
|
+
|
|
31
|
+
def test_single_dot_notation(self) -> None:
|
|
32
|
+
path, keys = _split_resolver_key("/prod/db_config.host")
|
|
33
|
+
assert path == "/prod/db_config"
|
|
34
|
+
assert keys == ["host"]
|
|
35
|
+
|
|
36
|
+
def test_nested_dot_notation(self) -> None:
|
|
37
|
+
path, keys = _split_resolver_key("/prod/db.connection.host")
|
|
38
|
+
assert path == "/prod/db"
|
|
39
|
+
assert keys == ["connection", "host"]
|
|
40
|
+
|
|
41
|
+
def test_no_slash_with_dot(self) -> None:
|
|
42
|
+
path, keys = _split_resolver_key("param.key")
|
|
43
|
+
assert path == "param"
|
|
44
|
+
assert keys == ["key"]
|
|
45
|
+
|
|
46
|
+
def test_no_slash_no_dot(self) -> None:
|
|
47
|
+
assert _split_resolver_key("simple") == ("simple", [])
|
|
48
|
+
|
|
49
|
+
def test_dot_only_in_first_segment_not_last(self) -> None:
|
|
50
|
+
# dot is in segment "db.prod" which is NOT the last segment
|
|
51
|
+
path, keys = _split_resolver_key("/app/db.prod/token")
|
|
52
|
+
assert path == "/app/db.prod/token"
|
|
53
|
+
assert keys == []
|
|
54
|
+
|
|
55
|
+
def test_trailing_dot_ignored(self) -> None:
|
|
56
|
+
# trailing dot produces an empty segment that is filtered out
|
|
57
|
+
path, keys = _split_resolver_key("/prod/db.")
|
|
58
|
+
assert path == "/prod/db"
|
|
59
|
+
assert keys == []
|
|
60
|
+
|
|
61
|
+
def test_consecutive_dots_filtered(self) -> None:
|
|
62
|
+
path, keys = _split_resolver_key("/prod/db..host")
|
|
63
|
+
assert path == "/prod/db"
|
|
64
|
+
assert keys == ["host"]
|
|
65
|
+
|
|
66
|
+
def test_path_with_only_slash(self) -> None:
|
|
67
|
+
assert _split_resolver_key("/") == ("/", [])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
# _expand_env_vars
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class TestExpandEnvVars:
|
|
76
|
+
def test_no_placeholders_returns_unchanged(self) -> None:
|
|
77
|
+
assert _expand_env_vars("/prod/token") == "/prod/token"
|
|
78
|
+
|
|
79
|
+
def test_single_placeholder_expanded(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
80
|
+
monkeypatch.setenv("ENV", "staging")
|
|
81
|
+
assert _expand_env_vars("/app/%ENV%/token") == "/app/staging/token"
|
|
82
|
+
|
|
83
|
+
def test_multiple_placeholders_expanded(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
84
|
+
monkeypatch.setenv("REGION", "eu-west-1")
|
|
85
|
+
monkeypatch.setenv("ENV", "prod")
|
|
86
|
+
assert _expand_env_vars("/%REGION%/%ENV%/key") == "/eu-west-1/prod/key"
|
|
87
|
+
|
|
88
|
+
def test_missing_env_var_raises_config_error(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
89
|
+
monkeypatch.delenv("MISSING", raising=False)
|
|
90
|
+
with pytest.raises(ConfigError, match="MISSING"):
|
|
91
|
+
_expand_env_vars("/path/%MISSING%/token")
|
|
92
|
+
|
|
93
|
+
def test_lowercase_not_expanded(self) -> None:
|
|
94
|
+
assert _expand_env_vars("/path/%env%/token") == "/path/%env%/token"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
# _navigate_json
|
|
99
|
+
# ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class TestNavigateJson:
|
|
103
|
+
def test_single_key(self) -> None:
|
|
104
|
+
result = _navigate_json('{"host": "db.internal"}', ["host"], "/path")
|
|
105
|
+
assert result == "db.internal"
|
|
106
|
+
|
|
107
|
+
def test_nested_keys(self) -> None:
|
|
108
|
+
result = _navigate_json('{"conn": {"host": "db"}}', ["conn", "host"], "/path")
|
|
109
|
+
assert result == "db"
|
|
110
|
+
|
|
111
|
+
def test_missing_key_raises_config_error(self) -> None:
|
|
112
|
+
with pytest.raises(ConfigError, match="absent"):
|
|
113
|
+
_navigate_json('{"host": "db"}', ["absent"], "/path")
|
|
114
|
+
|
|
115
|
+
def test_invalid_json_raises_config_error(self) -> None:
|
|
116
|
+
with pytest.raises(ConfigError, match="not valid JSON"):
|
|
117
|
+
_navigate_json("not-json", ["key"], "/path")
|
|
118
|
+
|
|
119
|
+
def test_invalid_json_error_does_not_expose_raw_value(self) -> None:
|
|
120
|
+
"""Security: JSONDecodeError.__cause__ must not hold the raw secret."""
|
|
121
|
+
secret_value = "my_raw_secret_value"
|
|
122
|
+
with pytest.raises(ConfigError) as exc_info:
|
|
123
|
+
_navigate_json(secret_value, ["key"], "/path")
|
|
124
|
+
assert exc_info.value.__cause__ is None, (
|
|
125
|
+
"ConfigError must not chain JSONDecodeError — its .doc attribute holds the raw secret"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def test_non_dict_intermediate_raises_config_error(self) -> None:
|
|
129
|
+
with pytest.raises(ConfigError):
|
|
130
|
+
_navigate_json('{"host": "db"}', ["host", "nested"], "/path")
|