loom-kernel 2.9.0__tar.gz → 2.11.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/PKG-INFO +1 -1
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/pyproject.toml +3 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/authz/_decide.py +94 -24
- loom_kernel-2.11.0/src/loom/core/authz/_grants.py +135 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/authz/_scope.py +17 -13
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/__init__.py +2 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/session_manager.py +55 -1
- loom_kernel-2.11.0/src/loom/core/repository/sqlalchemy/session_settings.py +83 -0
- loom_kernel-2.9.0/src/loom/core/authz/_grants.py +0 -79
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/.gitignore +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/CHANGELOG.md +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/LICENSE +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/README.md +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_concurrency.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_filters.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_roles.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_startup.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_transport.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_usecase.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/_binding.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/_handlers.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/_rpc.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/card.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/events.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/server.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/abc.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/_compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/_plan.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_capabilities.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_conversation.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_feedable.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_hook.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_instructions.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_limits.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_model_role.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_output.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_state.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/_envelope.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/_schema.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/_v1.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/schemas/agent-spec-v1.schema.json +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/describe.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_a2a.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_capabilities.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_engine.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_escape.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_events.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_guards.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_history.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_instructions.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_limits.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_mcp.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_models.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_native.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_output.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_returns.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_schemas.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_spec.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/a2a.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/handlebars.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/mcp.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/skills.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/provider.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/_shared.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/anthropic.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/bedrock.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/gateway.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/openai.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/typesafe.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/fastapi/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/fastapi/endpoints.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/fastapi/response.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/fastapi/streaming.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/inference.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/remote_auth.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_bounded.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_chain.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_conversation.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_grants.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_handle.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_health.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_hooks.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_lifecycle.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_limits.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_mcp.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/validate/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/validate/__main__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/auto.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/bootstrap.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/constants.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/runner.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/service.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/async_bridge.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/authz/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/authz/_roles.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/backend/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/backend/core_model.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/backend/protocol.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/backend/sqlalchemy.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/bootstrap/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/bootstrap/kernel.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/_batching.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/_single_flight.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/abc/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/abc/backend.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/abc/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/abc/dependency.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/calls.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/codec.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/decorators.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/dependency.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/gateway.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/keys.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/memory.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/repository.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/result_codec.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/serializer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/wiring.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/adapter.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/base.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/field.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/introspection.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/_boto3.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/_includes.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/_resolver_utils.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/binder.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/configurable.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/context.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/keys.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/loader.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/model.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/observability.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/resolver.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/secrets.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/ssm.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/contracts/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/contracts/manifest.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/di/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/di/container.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/di/scope.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/_utils.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/base.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/interfaces.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/manifest.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/modules.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/compilable.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/events.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/executor.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/metrics.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/plan.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/post_commit.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/errors/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/errors/codes.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/errors/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/expr/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/expr/eval.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/expr/nodes.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/expr/refs.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/context.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/identity.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/issuer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/wire.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/introspection/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/introspection/base.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/introspection/describe.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/callback.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/context.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/handle.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/job.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/service.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/abc.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/structlogger.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/_loom_type.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/base.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/convert.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/enums.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/field.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/introspection.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/projection.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/relation.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/struct.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/timestamped.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/types.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/types_postgres.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/event.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/observer/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/observer/noop.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/observer/otel.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/observer/structlog.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/otel_ids.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/protocol.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/runtime.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/span.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/topology.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/persistence/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/persistence/abc.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/persistence/none.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/persistence/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/plugins/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/plugins/entrypoints.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/plugins/optional.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/projection/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/projection/loaders.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/projection/runtime.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/cursor.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/query.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/query_compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/repo_for.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/repository.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/session_scope.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/backend.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/repository.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/uow.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/backend.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/ids.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/query_compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/repository.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/uow.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/values.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mutation.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/registration.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/backend.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/mixins.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/response/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/response/base.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/routing/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/routing/ref.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/routing/resolver.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/runner.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/schema/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/schema/schema_mode.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/abc/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/abc/contracts.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/abc/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/caller_bound.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/clickhouse/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/clickhouse/_client.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/clickhouse/executor.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/clickhouse/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/roles.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/service.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/symbols.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/tracing/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/tracing/context.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/transaction.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/transport/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/transport/adapter.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/uow/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/uow/abc.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/uow/context.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/_predicates.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/agent_markers.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/compute.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/constants.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/factory.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/field_ref.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/invoker.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/keys.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/markers.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/mcp_markers.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/rule.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/use_case.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_format_registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_common.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_log.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_ops.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_transform.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_merge.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_path_template.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_predicate.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_schema_aligner/_policy.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_write_policy.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_dtype.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_file_writer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_historify.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_predicate.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_reader.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_schema.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_streaming.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_writer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/provider.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_dtype.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_historify.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_reader.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_schema.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_writer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/provider.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_backends/_polars.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_cleaners.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_options.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_paths.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_scope.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_store.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_binding.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_plan.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_validators.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_validators_config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_validators_plan.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_validators_step.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/_format.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/_read_options.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/_utils.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/_write_options.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/_params.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/_predicate.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/_refs.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from_config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from_dynamodb.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_specs.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_client.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_file.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_builder.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_report.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_spec.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_into.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_schema_mode.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_table.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_temp.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/executor/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/executor/_dispatcher.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/executor/_executor.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/_registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_clickhouse.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_dynamodb.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_dynamodb_items.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_dynamodb_predicate.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_mongo.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_serialization.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/targets/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/targets/_clickhouse.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/_config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/_observer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/_records.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/sinks/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/sinks/_table.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/sinks/_writer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_builder.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_ops.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_protocol.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_runner.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_step.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/backends/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/backends/_delta_rs.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_generics.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_params.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_pipeline.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_process.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_sql.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_step.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_step_client.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_step_sql.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/_providers.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/_wiring.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/config_loader.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/core.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/filtering.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runtime/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runtime/_config_values.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runtime/contracts.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/schema/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/schema/_contract.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/schema/_schema.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/_config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/_file_locator.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/_locator.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/routing.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/_result.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/_runners.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/_scenario.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/_stubs.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/spark.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_async.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_ctx.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_flow_yaml.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_meta.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_placeholders.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_summary.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/_discovery.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/_schedule.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/_yaml_etls.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/entrypoint.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_assemble.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_backfill.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_backfill_body.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_body.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_common.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_factory.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_hooks.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_maintenance.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_params.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_run_name.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_runtime.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_signature.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_stages.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/manifest/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/manifest/_model.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/manifest/_s3.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/manifest/_store.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/_event.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/_factory.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/_port.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/_slack.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/_flow.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/_logging_bridge.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/_manifest.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/_task_run.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/_instruments.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/adapter.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/kafka.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/lifecycle.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/middleware.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/py.typed +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/_body.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/adapter.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/abc.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/jwt.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/middleware.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/autocrud.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/constants.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/cors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/_errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/_exclusions.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/app.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/auto.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/health.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/openapi.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/response.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/router_runtime.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/sql.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/middleware.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/model.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/rest_adapter.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_adapter.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_batch_spans.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_dlq.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_operators.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_runtime_io.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/_shared.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/steps.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/runner.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/_bindings.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/_compiler.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/_errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/_plan.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/phases/build_plan.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/phases/validate.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_exceptions.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_message.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_tracing.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_typing.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/graph/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/graph/_flow.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_codec.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_errors.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_key_resolver.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_message.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_record.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_wire.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/_consumer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/_producer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/_protocol.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/_retry.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/message/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/message/_consumer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/message/_producer.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/message/_protocol.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/_config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/_event.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/_normalize.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_boundary.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_branches.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_broadcast.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_capabilities.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_decompose.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_expand_routes.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_expr_eval.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_fork.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_helpers.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_mongo.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_protocols.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_router.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_shape.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_sink.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_step.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_table/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_table/common.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_table/config.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_with.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/refs.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/testing.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/__init__.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/agents.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/golden.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/http_harness.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/in_memory.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/repository_harness.py +0 -0
- {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/runner.py +0 -0
|
@@ -224,6 +224,7 @@ mcp-tests = [
|
|
|
224
224
|
dev = [
|
|
225
225
|
"aiocache>=0.12,<1.0",
|
|
226
226
|
"aiosqlite>=0.20.0",
|
|
227
|
+
"asyncpg>=0.30",
|
|
227
228
|
# Declared, not merely transitive: one cache test pins what the key renderer
|
|
228
229
|
# cannot separate inside an object msgspec expands itself, and an attrs class
|
|
229
230
|
# is the only such object the stdlib can build.
|
|
@@ -477,6 +478,7 @@ prerelease_ignore = [
|
|
|
477
478
|
"ci/.*",
|
|
478
479
|
"test/.*",
|
|
479
480
|
"build/.*",
|
|
481
|
+
"dependabot/.*",
|
|
480
482
|
]
|
|
481
483
|
release_ignore = [
|
|
482
484
|
"wip/.*",
|
|
@@ -485,4 +487,5 @@ release_ignore = [
|
|
|
485
487
|
"ci/.*",
|
|
486
488
|
"test/.*",
|
|
487
489
|
"build/.*",
|
|
490
|
+
"dependabot/.*",
|
|
488
491
|
]
|
|
@@ -4,8 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from collections.abc import Iterable
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
+
from datetime import datetime
|
|
7
8
|
|
|
8
|
-
from loom.core.authz._grants import Grant
|
|
9
|
+
from loom.core.authz._grants import Grant, require_aware
|
|
9
10
|
from loom.core.authz._roles import Permission, RoleCatalog
|
|
10
11
|
from loom.core.authz._scope import Scope
|
|
11
12
|
|
|
@@ -54,8 +55,41 @@ class GrantCheck:
|
|
|
54
55
|
return self.allowed
|
|
55
56
|
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
_FOREVER = float("-inf")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _rank(grant: Grant) -> tuple[int, str, str, float]:
|
|
62
|
+
lifetime = _FOREVER if grant.expires_at is None else -grant.expires_at.timestamp()
|
|
63
|
+
return (-len(grant.scope.path), grant.role, grant.subject, lifetime)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _check_now(now: datetime | None) -> None:
|
|
67
|
+
if now is not None:
|
|
68
|
+
require_aware("now", now)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _require_now_for_expiring(grants: tuple[Grant, ...], now: datetime | None) -> None:
|
|
72
|
+
expiry = next((grant.expires_at for grant in grants if grant.expires_at is not None), None)
|
|
73
|
+
if now is None and expiry is not None:
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"A grant expires at {expiry.isoformat()}; pass now= to decide whether it is alive."
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _alive(grant: Grant, now: datetime | None) -> bool:
|
|
80
|
+
return grant.expires_at is None or (now is not None and now < grant.expires_at)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _covering_paths(scope: Scope) -> frozenset[tuple[str, ...]]:
|
|
84
|
+
return frozenset(scope.path[:depth] for depth in range(len(scope.path) + 1))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _outermost(scopes: set[Scope]) -> frozenset[Scope]:
|
|
88
|
+
return frozenset(
|
|
89
|
+
scope
|
|
90
|
+
for scope in scopes
|
|
91
|
+
if not any(other != scope and other.covers(scope) for other in scopes)
|
|
92
|
+
)
|
|
59
93
|
|
|
60
94
|
|
|
61
95
|
def evaluate(
|
|
@@ -63,6 +97,8 @@ def evaluate(
|
|
|
63
97
|
grants: Iterable[Grant],
|
|
64
98
|
permission: Permission,
|
|
65
99
|
scope: Scope,
|
|
100
|
+
*,
|
|
101
|
+
now: datetime | None = None,
|
|
66
102
|
) -> Decision:
|
|
67
103
|
"""Decide whether a subject holds *permission* on *scope*.
|
|
68
104
|
|
|
@@ -70,30 +106,38 @@ def evaluate(
|
|
|
70
106
|
scope covering *scope*. A grant whose role the catalog does not declare
|
|
71
107
|
allows nothing. When several grants allow, the decision names the one on
|
|
72
108
|
the deepest scope, then the first by role name and subject, regardless of
|
|
73
|
-
the order of *grants
|
|
109
|
+
the order of *grants*; among grants that tie there, the one that lives
|
|
110
|
+
longest. A grant is alive while *now* is before its expiry; an expired
|
|
111
|
+
grant counts as absent.
|
|
74
112
|
|
|
75
113
|
Args:
|
|
76
114
|
catalog: The product's roles.
|
|
77
115
|
grants: The grants of one subject.
|
|
78
116
|
permission: The capability being exercised.
|
|
79
117
|
scope: Where it is exercised.
|
|
118
|
+
now: The timezone-aware instant of the decision; needed only when
|
|
119
|
+
some grant carries an expiry.
|
|
80
120
|
|
|
81
121
|
Returns:
|
|
82
122
|
The decision, carrying the grant that allowed it.
|
|
83
123
|
|
|
84
124
|
Raises:
|
|
85
125
|
UnknownPermission: When *permission* is not declared in the catalog.
|
|
126
|
+
TypeError: When *now* is not a datetime.
|
|
127
|
+
ValueError: When *now* is naive, or is ``None`` while some grant
|
|
128
|
+
carries an expiry.
|
|
86
129
|
"""
|
|
130
|
+
_check_now(now)
|
|
131
|
+
held = tuple(grants)
|
|
132
|
+
_require_now_for_expiring(held, now)
|
|
87
133
|
roles = catalog.roles_with(permission)
|
|
88
|
-
covering =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
):
|
|
96
|
-
winner = grant
|
|
134
|
+
covering = _covering_paths(scope)
|
|
135
|
+
allowing = [
|
|
136
|
+
grant
|
|
137
|
+
for grant in held
|
|
138
|
+
if grant.role in roles and grant.scope.path in covering and _alive(grant, now)
|
|
139
|
+
]
|
|
140
|
+
winner = min(allowing, key=_rank, default=None)
|
|
97
141
|
return Decision(winner is not None, winner)
|
|
98
142
|
|
|
99
143
|
|
|
@@ -101,28 +145,36 @@ def scopes_with(
|
|
|
101
145
|
catalog: RoleCatalog,
|
|
102
146
|
grants: Iterable[Grant],
|
|
103
147
|
permission: Permission,
|
|
148
|
+
*,
|
|
149
|
+
now: datetime | None = None,
|
|
104
150
|
) -> frozenset[Scope]:
|
|
105
151
|
"""Return the outermost scopes on which a subject holds *permission*.
|
|
106
152
|
|
|
107
153
|
A scope covered by another returned scope is left out, so a listing can
|
|
108
|
-
be filtered with one :meth:`Scope.covers` test per returned scope.
|
|
154
|
+
be filtered with one :meth:`Scope.covers` test per returned scope. An
|
|
155
|
+
expired grant counts as absent.
|
|
109
156
|
|
|
110
157
|
Args:
|
|
111
158
|
catalog: The product's roles.
|
|
112
159
|
grants: The grants of one subject.
|
|
113
160
|
permission: The capability being listed.
|
|
161
|
+
now: The timezone-aware instant of the listing; needed only when
|
|
162
|
+
some grant carries an expiry.
|
|
114
163
|
|
|
115
164
|
Returns:
|
|
116
165
|
The minimal set of scopes covering everything the subject may reach.
|
|
117
166
|
|
|
118
167
|
Raises:
|
|
119
168
|
UnknownPermission: When *permission* is not declared in the catalog.
|
|
169
|
+
TypeError: When *now* is not a datetime.
|
|
170
|
+
ValueError: When *now* is naive, or is ``None`` while some grant
|
|
171
|
+
carries an expiry.
|
|
120
172
|
"""
|
|
173
|
+
_check_now(now)
|
|
174
|
+
held = tuple(grants)
|
|
175
|
+
_require_now_for_expiring(held, now)
|
|
121
176
|
roles = catalog.roles_with(permission)
|
|
122
|
-
|
|
123
|
-
return frozenset(
|
|
124
|
-
scope for scope in held if not any(other != scope and other.covers(scope) for other in held)
|
|
125
|
-
)
|
|
177
|
+
return _outermost({grant.scope for grant in held if grant.role in roles and _alive(grant, now)})
|
|
126
178
|
|
|
127
179
|
|
|
128
180
|
def _delegation_check(
|
|
@@ -130,10 +182,13 @@ def _delegation_check(
|
|
|
130
182
|
granter_grants: Iterable[Grant],
|
|
131
183
|
needed: Iterable[Permission],
|
|
132
184
|
scope: Scope,
|
|
185
|
+
now: datetime | None,
|
|
133
186
|
) -> GrantCheck:
|
|
134
187
|
held = tuple(granter_grants)
|
|
135
188
|
missing = frozenset(
|
|
136
|
-
permission
|
|
189
|
+
permission
|
|
190
|
+
for permission in needed
|
|
191
|
+
if not evaluate(catalog, held, permission, scope, now=now)
|
|
137
192
|
)
|
|
138
193
|
return GrantCheck(not missing, missing)
|
|
139
194
|
|
|
@@ -145,11 +200,12 @@ def can_grant(
|
|
|
145
200
|
scope: Scope,
|
|
146
201
|
*,
|
|
147
202
|
delegate: Permission,
|
|
203
|
+
now: datetime | None = None,
|
|
148
204
|
) -> GrantCheck:
|
|
149
205
|
"""Decide whether a granter may assign *role* on *scope*.
|
|
150
206
|
|
|
151
207
|
The granter needs *delegate* and every permission of *role*, each held on
|
|
152
|
-
a scope covering *scope*.
|
|
208
|
+
a scope covering *scope* by a grant that is alive at *now*.
|
|
153
209
|
|
|
154
210
|
Args:
|
|
155
211
|
catalog: The product's roles.
|
|
@@ -157,6 +213,8 @@ def can_grant(
|
|
|
157
213
|
role: Name of the role to assign.
|
|
158
214
|
scope: Where it would apply.
|
|
159
215
|
delegate: The permission that allows assigning roles at all.
|
|
216
|
+
now: The timezone-aware instant of the check; needed only when some
|
|
217
|
+
of the granter's grants carry an expiry.
|
|
160
218
|
|
|
161
219
|
Returns:
|
|
162
220
|
The check, listing the permissions the granter lacks there.
|
|
@@ -164,9 +222,13 @@ def can_grant(
|
|
|
164
222
|
Raises:
|
|
165
223
|
UnknownRole: When *role* is not declared in the catalog.
|
|
166
224
|
UnknownPermission: When *delegate* is not declared in the catalog.
|
|
225
|
+
TypeError: When *now* is not a datetime.
|
|
226
|
+
ValueError: When *now* is naive, or is ``None`` while some of the
|
|
227
|
+
granter's grants carry an expiry.
|
|
167
228
|
"""
|
|
229
|
+
_check_now(now)
|
|
168
230
|
needed = {delegate, *catalog.role(role).permissions}
|
|
169
|
-
return _delegation_check(catalog, granter_grants, needed, scope)
|
|
231
|
+
return _delegation_check(catalog, granter_grants, needed, scope, now)
|
|
170
232
|
|
|
171
233
|
|
|
172
234
|
def can_revoke(
|
|
@@ -175,23 +237,31 @@ def can_revoke(
|
|
|
175
237
|
grant: Grant,
|
|
176
238
|
*,
|
|
177
239
|
delegate: Permission,
|
|
240
|
+
now: datetime | None = None,
|
|
178
241
|
) -> GrantCheck:
|
|
179
242
|
"""Decide whether a granter may remove *grant*.
|
|
180
243
|
|
|
181
|
-
Revoking needs what granting it would
|
|
182
|
-
not declare allows nothing, so
|
|
244
|
+
Revoking needs what granting it would, whether or not *grant* has
|
|
245
|
+
expired. A grant whose role the code does not declare allows nothing, so
|
|
246
|
+
removing it needs *delegate* only.
|
|
183
247
|
|
|
184
248
|
Args:
|
|
185
249
|
catalog: The product's roles.
|
|
186
250
|
granter_grants: The granter's grants.
|
|
187
251
|
grant: The assignment to remove.
|
|
188
252
|
delegate: The permission that allows assigning roles at all.
|
|
253
|
+
now: The timezone-aware instant of the check; needed only when some
|
|
254
|
+
of the granter's grants carry an expiry.
|
|
189
255
|
|
|
190
256
|
Returns:
|
|
191
257
|
The check, listing the permissions the granter lacks there.
|
|
192
258
|
|
|
193
259
|
Raises:
|
|
194
260
|
UnknownPermission: When *delegate* is not declared in the catalog.
|
|
261
|
+
TypeError: When *now* is not a datetime.
|
|
262
|
+
ValueError: When *now* is naive, or is ``None`` while some of the
|
|
263
|
+
granter's grants carry an expiry.
|
|
195
264
|
"""
|
|
265
|
+
_check_now(now)
|
|
196
266
|
needed = {delegate, *(catalog.permissions_of(grant.role) or frozenset())}
|
|
197
|
-
return _delegation_check(catalog, granter_grants, needed, grant.scope)
|
|
267
|
+
return _delegation_check(catalog, granter_grants, needed, grant.scope, now)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Who holds which role where, and where those assignments come from."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
from collections.abc import Collection, Iterable
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from datetime import UTC, datetime
|
|
9
|
+
from typing import Protocol
|
|
10
|
+
|
|
11
|
+
from loom.core.authz._roles import require_name
|
|
12
|
+
from loom.core.authz._scope import Scope
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def require_aware(name: str, moment: datetime) -> None:
|
|
16
|
+
"""Reject a moment that does not name a single instant.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
name: What the moment is, for the error message.
|
|
20
|
+
moment: The moment to check.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
TypeError: When *moment* is not a datetime.
|
|
24
|
+
ValueError: When *moment* is naive.
|
|
25
|
+
"""
|
|
26
|
+
if not isinstance(moment, datetime):
|
|
27
|
+
raise TypeError(f"{name} must be a datetime, not {type(moment).__name__}.")
|
|
28
|
+
if moment.utcoffset() is None:
|
|
29
|
+
raise ValueError(f"{name} must be timezone-aware: {moment!r}.")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _require_subject(subject: str) -> None:
|
|
33
|
+
if not subject:
|
|
34
|
+
raise ValueError("A grant needs a subject.")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _require_scope(scope: object) -> None:
|
|
38
|
+
if not isinstance(scope, Scope):
|
|
39
|
+
raise TypeError(f"A grant scope must be a Scope, not {type(scope).__name__}.")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _utc_or_none(name: str, moment: datetime | None) -> datetime | None:
|
|
43
|
+
if moment is None:
|
|
44
|
+
return None
|
|
45
|
+
require_aware(name, moment)
|
|
46
|
+
return moment.astimezone(UTC)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
_NEVER = (0,)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@functools.total_ordering
|
|
53
|
+
@dataclass(frozen=True, slots=True)
|
|
54
|
+
class Grant:
|
|
55
|
+
"""An assignment of a role to a subject on a scope, possibly until a moment.
|
|
56
|
+
|
|
57
|
+
Grants order by subject, role, scope and then expiry, with grants that
|
|
58
|
+
never expire before those that do, soonest first.
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
subject: Opaque identifier of the holder, such as an identity subject
|
|
62
|
+
or a service account id.
|
|
63
|
+
role: Name of the role; its permissions are looked up in the catalog
|
|
64
|
+
at decision time.
|
|
65
|
+
scope: Where the role applies, including everything below it.
|
|
66
|
+
expires_at: The timezone-aware instant from which the grant allows
|
|
67
|
+
nothing; ``None`` when it never expires.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
subject: str
|
|
71
|
+
role: str
|
|
72
|
+
scope: Scope
|
|
73
|
+
expires_at: datetime | None = None
|
|
74
|
+
|
|
75
|
+
def __post_init__(self) -> None:
|
|
76
|
+
"""Reject a grant with no holder, an unusable role name, no scope or a naive expiry."""
|
|
77
|
+
_require_subject(self.subject)
|
|
78
|
+
require_name("role", self.role)
|
|
79
|
+
_require_scope(self.scope)
|
|
80
|
+
object.__setattr__(self, "expires_at", _utc_or_none("A grant expiry", self.expires_at))
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def _sort_key(self) -> tuple[str, str, Scope, tuple[int] | tuple[int, datetime]]:
|
|
84
|
+
expiry = _NEVER if self.expires_at is None else (1, self.expires_at)
|
|
85
|
+
return (self.subject, self.role, self.scope, expiry)
|
|
86
|
+
|
|
87
|
+
def __lt__(self, other: object) -> bool:
|
|
88
|
+
"""Order by subject, role, scope, then expiry."""
|
|
89
|
+
if not isinstance(other, Grant):
|
|
90
|
+
return NotImplemented
|
|
91
|
+
return self._sort_key < other._sort_key
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class GrantSource(Protocol):
|
|
95
|
+
"""Where the grants of a subject are loaded from.
|
|
96
|
+
|
|
97
|
+
Any class with this method satisfies the protocol structurally, with no
|
|
98
|
+
inheritance required.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
async def grants_for(self, subject: str) -> Collection[Grant]:
|
|
102
|
+
"""Return every grant held by *subject*.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
subject: Identifier of the holder.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
The subject's grants; empty when it holds none.
|
|
109
|
+
"""
|
|
110
|
+
...
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class InMemoryGrantSource:
|
|
114
|
+
"""A :class:`GrantSource` over a fixed list, for tests and examples."""
|
|
115
|
+
|
|
116
|
+
__slots__ = ("_grants",)
|
|
117
|
+
|
|
118
|
+
def __init__(self, grants: Iterable[Grant]) -> None:
|
|
119
|
+
"""Hold *grants*, deduplicated in their original order.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
grants: Grants of any number of subjects.
|
|
123
|
+
"""
|
|
124
|
+
self._grants = tuple(dict.fromkeys(grants))
|
|
125
|
+
|
|
126
|
+
async def grants_for(self, subject: str) -> Collection[Grant]: # NOSONAR S7503 - protocol
|
|
127
|
+
"""Return the grants of *subject*, in the order they were given.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
subject: Identifier of the holder.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
The subject's grants.
|
|
134
|
+
"""
|
|
135
|
+
return tuple(grant for grant in self._grants if grant.subject == subject)
|
|
@@ -8,6 +8,22 @@ from dataclasses import dataclass
|
|
|
8
8
|
_SEPARATOR = "/"
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
def _segments_of(path: Iterable[str]) -> tuple[str, ...]:
|
|
12
|
+
if isinstance(path, str):
|
|
13
|
+
raise TypeError("A scope path is a sequence of segments, not a string; use Scope.parse().")
|
|
14
|
+
return tuple(map(_segment, path))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _segment(value: object) -> str:
|
|
18
|
+
if not isinstance(value, str):
|
|
19
|
+
raise TypeError(f"A scope segment must be a string: {value!r}.")
|
|
20
|
+
if not value or _SEPARATOR in value:
|
|
21
|
+
raise ValueError(
|
|
22
|
+
f"A scope segment must be non-empty and free of {_SEPARATOR!r}: {value!r}."
|
|
23
|
+
)
|
|
24
|
+
return value
|
|
25
|
+
|
|
26
|
+
|
|
11
27
|
@dataclass(frozen=True, slots=True, order=True, init=False)
|
|
12
28
|
class Scope:
|
|
13
29
|
"""A node in the product's resource hierarchy.
|
|
@@ -43,19 +59,7 @@ class Scope:
|
|
|
43
59
|
TypeError: When *path* is a single string or holds a non-string.
|
|
44
60
|
ValueError: When a segment is empty or contains ``/``.
|
|
45
61
|
"""
|
|
46
|
-
|
|
47
|
-
raise TypeError(
|
|
48
|
-
"A scope path is a sequence of segments, not a string; use Scope.parse()."
|
|
49
|
-
)
|
|
50
|
-
segments = tuple(path)
|
|
51
|
-
for segment in segments:
|
|
52
|
-
if not isinstance(segment, str):
|
|
53
|
-
raise TypeError(f"A scope segment must be a string: {segment!r}.")
|
|
54
|
-
if not segment or _SEPARATOR in segment:
|
|
55
|
-
raise ValueError(
|
|
56
|
-
f"A scope segment must be non-empty and free of {_SEPARATOR!r}: {segment!r}."
|
|
57
|
-
)
|
|
58
|
-
object.__setattr__(self, "path", segments)
|
|
62
|
+
object.__setattr__(self, "path", _segments_of(path))
|
|
59
63
|
|
|
60
64
|
@classmethod
|
|
61
65
|
def root(cls) -> Scope:
|
|
@@ -13,6 +13,7 @@ from loom.core.repository.sqlalchemy.registry import (
|
|
|
13
13
|
)
|
|
14
14
|
from loom.core.repository.sqlalchemy.repository import RepositorySQLAlchemy, with_session_scope
|
|
15
15
|
from loom.core.repository.sqlalchemy.session_manager import SessionManager
|
|
16
|
+
from loom.core.repository.sqlalchemy.session_settings import SessionSettings
|
|
16
17
|
from loom.core.repository.sqlalchemy.transactional import SupportsPostCommit, transactional
|
|
17
18
|
|
|
18
19
|
__all__ = [
|
|
@@ -24,6 +25,7 @@ __all__ = [
|
|
|
24
25
|
"Projection",
|
|
25
26
|
"RepositorySQLAlchemy",
|
|
26
27
|
"SessionManager",
|
|
28
|
+
"SessionSettings",
|
|
27
29
|
"SupportsPostCommit",
|
|
28
30
|
"TimestampMixin",
|
|
29
31
|
"SQLAlchemyDefaultRepositoryBuilder",
|
{loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/session_manager.py
RENAMED
|
@@ -5,14 +5,20 @@ from contextlib import asynccontextmanager
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
from sqlalchemy import event
|
|
8
|
+
from sqlalchemy.engine import make_url
|
|
8
9
|
from sqlalchemy.ext.asyncio import (
|
|
9
10
|
AsyncEngine,
|
|
10
11
|
AsyncSession,
|
|
11
12
|
async_sessionmaker,
|
|
12
13
|
create_async_engine,
|
|
13
14
|
)
|
|
15
|
+
from sqlalchemy.orm import Session
|
|
14
16
|
|
|
15
17
|
from loom.core.logger import get_logger
|
|
18
|
+
from loom.core.repository.sqlalchemy.session_settings import (
|
|
19
|
+
SessionSettings,
|
|
20
|
+
install_session_settings,
|
|
21
|
+
)
|
|
16
22
|
from loom.core.tracing import get_trace_id
|
|
17
23
|
|
|
18
24
|
|
|
@@ -25,6 +31,7 @@ class SessionManager:
|
|
|
25
31
|
config: Mapping[str, Any],
|
|
26
32
|
*,
|
|
27
33
|
inject_trace_id: bool = True,
|
|
34
|
+
session_settings: SessionSettings | None = None,
|
|
28
35
|
**engine_kwargs: object,
|
|
29
36
|
) -> SessionManager:
|
|
30
37
|
"""Build a session manager from a resolved SQLAlchemy config mapping.
|
|
@@ -34,6 +41,8 @@ class SessionManager:
|
|
|
34
41
|
optional pool tuning keys.
|
|
35
42
|
inject_trace_id: When ``True``, prefixes SQL statements with the
|
|
36
43
|
active trace id when available.
|
|
44
|
+
session_settings: Optional provider of transaction-local Postgres
|
|
45
|
+
settings; see :meth:`SessionManager.__init__` for the contract.
|
|
37
46
|
**engine_kwargs: Additional keyword arguments forwarded to the
|
|
38
47
|
async engine constructor.
|
|
39
48
|
|
|
@@ -41,7 +50,8 @@ class SessionManager:
|
|
|
41
50
|
A configured :class:`SessionManager`.
|
|
42
51
|
|
|
43
52
|
Raises:
|
|
44
|
-
ValueError: If ``url`` is missing or empty
|
|
53
|
+
ValueError: If ``url`` is missing or empty, or if ``session_settings``
|
|
54
|
+
is given and ``url`` is not a Postgres URL.
|
|
45
55
|
"""
|
|
46
56
|
url = config.get("url")
|
|
47
57
|
if not url:
|
|
@@ -56,6 +66,7 @@ class SessionManager:
|
|
|
56
66
|
pool_recycle=_optional_int(config.get("pool_recycle"), 1800),
|
|
57
67
|
connect_args=dict(config.get("connect_args") or {}),
|
|
58
68
|
inject_trace_id=inject_trace_id,
|
|
69
|
+
session_settings=session_settings,
|
|
59
70
|
**engine_kwargs,
|
|
60
71
|
)
|
|
61
72
|
|
|
@@ -71,6 +82,7 @@ class SessionManager:
|
|
|
71
82
|
pool_recycle: int | None = 1800,
|
|
72
83
|
connect_args: dict[str, object] | None = None,
|
|
73
84
|
inject_trace_id: bool = True,
|
|
85
|
+
session_settings: SessionSettings | None = None,
|
|
74
86
|
**engine_kwargs: object,
|
|
75
87
|
) -> None:
|
|
76
88
|
"""Create a session manager backed by an async SQLAlchemy engine.
|
|
@@ -88,8 +100,32 @@ class SessionManager:
|
|
|
88
100
|
``/* trace_id=<id> */`` comment when a trace identifier is active
|
|
89
101
|
in the current async context. Visible in database slow-query logs
|
|
90
102
|
and ``pg_stat_activity``. Defaults to ``True``.
|
|
103
|
+
session_settings: When given, a callable that returns the settings for
|
|
104
|
+
the transaction about to start, or ``None`` to apply none. Each
|
|
105
|
+
outer transaction then begins with one ``SELECT`` that calls
|
|
106
|
+
``set_config(key, value, true)`` once per entry, with keys and
|
|
107
|
+
values bound as parameters. The settings are local to the
|
|
108
|
+
transaction, so the connection returns to the pool clean. Postgres
|
|
109
|
+
only, and incompatible with ``isolation_level="AUTOCOMMIT"``, which
|
|
110
|
+
would discard the settings after each statement; when ``None``,
|
|
111
|
+
the manager behaves exactly as it does without this option.
|
|
91
112
|
**engine_kwargs: Additional keyword arguments forwarded to ``create_async_engine``.
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
ValueError: If ``session_settings`` is given and ``url`` is not a
|
|
116
|
+
Postgres URL, or the engine is configured with
|
|
117
|
+
``isolation_level="AUTOCOMMIT"``.
|
|
92
118
|
"""
|
|
119
|
+
if session_settings is not None:
|
|
120
|
+
backend = make_url(url).get_backend_name()
|
|
121
|
+
if backend != "postgresql":
|
|
122
|
+
raise ValueError(
|
|
123
|
+
f"session_settings requires a postgresql URL, got backend {backend!r}"
|
|
124
|
+
)
|
|
125
|
+
if _autocommit(engine_kwargs):
|
|
126
|
+
raise ValueError(
|
|
127
|
+
"session_settings is incompatible with isolation_level='AUTOCOMMIT'"
|
|
128
|
+
)
|
|
93
129
|
engine_config: dict[str, object] = {
|
|
94
130
|
"echo": echo,
|
|
95
131
|
"pool_pre_ping": pool_pre_ping,
|
|
@@ -108,10 +144,16 @@ class SessionManager:
|
|
|
108
144
|
|
|
109
145
|
self._log = get_logger(__name__).bind(module="session_manager")
|
|
110
146
|
self._engine = create_async_engine(url, **engine_config)
|
|
147
|
+
factory_kwargs: dict[str, Any] = {}
|
|
148
|
+
if session_settings is not None:
|
|
149
|
+
session_class = type("SettingsSession", (Session,), {})
|
|
150
|
+
install_session_settings(session_class, session_settings)
|
|
151
|
+
factory_kwargs["sync_session_class"] = session_class
|
|
111
152
|
self._session_factory = async_sessionmaker(
|
|
112
153
|
bind=self._engine,
|
|
113
154
|
class_=AsyncSession,
|
|
114
155
|
expire_on_commit=False,
|
|
156
|
+
**factory_kwargs,
|
|
115
157
|
)
|
|
116
158
|
if inject_trace_id:
|
|
117
159
|
_register_trace_id_listener(self._engine)
|
|
@@ -120,6 +162,7 @@ class SessionManager:
|
|
|
120
162
|
backend=self._engine.url.get_backend_name(),
|
|
121
163
|
driver=self._engine.url.get_driver_name(),
|
|
122
164
|
inject_trace_id=inject_trace_id,
|
|
165
|
+
session_settings=session_settings is not None,
|
|
123
166
|
)
|
|
124
167
|
|
|
125
168
|
@asynccontextmanager
|
|
@@ -181,6 +224,17 @@ def _register_trace_id_listener(async_engine: AsyncEngine) -> None:
|
|
|
181
224
|
return statement, parameters
|
|
182
225
|
|
|
183
226
|
|
|
227
|
+
def _autocommit(engine_kwargs: Mapping[str, object]) -> bool:
|
|
228
|
+
execution_options = engine_kwargs.get("execution_options")
|
|
229
|
+
levels = (
|
|
230
|
+
engine_kwargs.get("isolation_level"),
|
|
231
|
+
execution_options.get("isolation_level")
|
|
232
|
+
if isinstance(execution_options, Mapping)
|
|
233
|
+
else None,
|
|
234
|
+
)
|
|
235
|
+
return any(isinstance(level, str) and level.upper() == "AUTOCOMMIT" for level in levels)
|
|
236
|
+
|
|
237
|
+
|
|
184
238
|
def _optional_int(value: Any, default: int) -> int:
|
|
185
239
|
if value is None:
|
|
186
240
|
return default
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from collections.abc import Callable, Mapping
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from sqlalchemy import TextClause, event, text
|
|
8
|
+
from sqlalchemy.orm import Session
|
|
9
|
+
|
|
10
|
+
SessionSettings = Callable[[], Mapping[str, str] | None]
|
|
11
|
+
"""Returns the settings to apply to the transaction about to start, or ``None`` to apply none.
|
|
12
|
+
|
|
13
|
+
loom does not interpret the keys or values. A product returns, for example, the tenant
|
|
14
|
+
and the subject of the current request, and writes its Postgres policies against
|
|
15
|
+
``current_setting(key, true)``.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
_KEY = re.compile(r"[A-Za-z_]\w*\.[A-Za-z_]\w*")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def settings_statement(
|
|
22
|
+
values: Mapping[str, str] | None,
|
|
23
|
+
) -> tuple[TextClause, dict[str, str]] | None:
|
|
24
|
+
"""Build the one statement that sets *values* for the current transaction.
|
|
25
|
+
|
|
26
|
+
Every key and value is bound as a parameter: the compiled SQL carries only
|
|
27
|
+
placeholders. Keys must be application-prefixed identifiers, ``prefix.name``,
|
|
28
|
+
which is what Postgres requires of a custom setting.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
values: The settings to apply, or ``None``.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
The ``SELECT set_config(...)`` clause with its parameters, or ``None``
|
|
35
|
+
when there is nothing to set.
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
ValueError: If a key is not a string of the form ``prefix.name``.
|
|
39
|
+
TypeError: If a value is not a ``str``.
|
|
40
|
+
"""
|
|
41
|
+
if not values:
|
|
42
|
+
return None
|
|
43
|
+
calls: list[str] = []
|
|
44
|
+
params: dict[str, str] = {}
|
|
45
|
+
for index, (key, value) in enumerate(values.items()):
|
|
46
|
+
if not isinstance(key, str) or _KEY.fullmatch(key) is None:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f"session setting key must be a str of the form 'prefix.name', got {key!r}"
|
|
49
|
+
)
|
|
50
|
+
if not isinstance(value, str):
|
|
51
|
+
raise TypeError(
|
|
52
|
+
f"session setting value for {key!r} must be str, got {type(value).__name__}"
|
|
53
|
+
)
|
|
54
|
+
calls.append(f"set_config(:k{index}, :v{index}, true)")
|
|
55
|
+
params[f"k{index}"] = key
|
|
56
|
+
params[f"v{index}"] = value
|
|
57
|
+
return text("SELECT " + ", ".join(calls)), params
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def install_session_settings(session_class: type[Session], provider: SessionSettings) -> None:
|
|
61
|
+
"""Apply *provider*'s settings at the start of every outer transaction of *session_class*.
|
|
62
|
+
|
|
63
|
+
The listener runs once per outer transaction and not for savepoints. A provider
|
|
64
|
+
that raises, an invalid key, or a non-``str`` value fails the transaction before
|
|
65
|
+
its first product statement reaches the database, and invalidates its connection,
|
|
66
|
+
so the session refuses further statements until it is rolled back.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
session_class: The synchronous ``Session`` subclass the listener is bound to.
|
|
70
|
+
provider: The settings provider called at the start of each transaction.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
@event.listens_for(session_class, "after_begin")
|
|
74
|
+
def _apply_session_settings(_session: Session, transaction: Any, connection: Any) -> None:
|
|
75
|
+
if transaction.nested:
|
|
76
|
+
return
|
|
77
|
+
try:
|
|
78
|
+
statement = settings_statement(provider())
|
|
79
|
+
if statement is not None:
|
|
80
|
+
connection.execute(*statement)
|
|
81
|
+
except BaseException:
|
|
82
|
+
connection.invalidate()
|
|
83
|
+
raise
|