loom-kernel 6.0.2__tar.gz → 8.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/CHANGELOG.md +66 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/PKG-INFO +1 -1
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/backend/sqlalchemy.py +4 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/__init__.py +4 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/_loom_type.py +3 -1
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/introspection.py +4 -2
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/types.py +2 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/backend.py +27 -1
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/mixins.py +29 -7
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +13 -6
- loom_kernel-8.0.0/src/loom/core/repository/sqlalchemy/values.py +130 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/_shared.py +22 -22
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/steps.py +39 -6
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_step.py +12 -3
- loom_kernel-6.0.2/src/loom/core/repository/sqlalchemy/values.py +0 -51
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/.gitignore +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/LICENSE +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/README.md +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/pyproject.toml +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/_concurrency.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/_filters.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/_paths.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/_roles.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/_startup.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/_transport.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/_usecase.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/a2a/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/a2a/_binding.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/a2a/_handlers.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/a2a/_rpc.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/a2a/card.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/a2a/events.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/a2a/server.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/abc.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/bootstrap.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/_compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/_fingerprint.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/_plan.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_capabilities.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_conversation.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_feedable.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_hook.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_instructions.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_limits.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_model_role.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_output.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/compiler/phases/_state.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/declarative/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/declarative/_envelope.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/declarative/_schema.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/declarative/_v1.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/declarative/schemas/agent-spec-v1.schema.json +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/describe.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_a2a.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_capabilities.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_engine.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_escape.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_events.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_guards.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_history.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_instructions.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_limits.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_mcp.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_models.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_native.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_output.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_returns.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_schemas.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/_spec.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/extras/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/extras/a2a.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/extras/handlebars.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/extras/mcp.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/extras/skills.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/provider.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/providers/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/providers/_shared.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/providers/anthropic.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/providers/bedrock.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/providers/gateway.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/providers/openai.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/engines/pydantic_ai/providers/typesafe.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/etl/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/etl/_batch.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/etl/_columns.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/etl/_frames.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/etl/_ledger.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/etl/_runner.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/etl/_validation.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/fastapi/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/fastapi/endpoints.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/fastapi/response.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/fastapi/streaming.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/inference.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/pricing.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/remote_auth.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_bounded.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_chain.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_conversation.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_grants.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_handle.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_health.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_hooks.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_lifecycle.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_limits.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/runtime/_mcp.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/validate/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/ai/validate/__main__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/celery/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/celery/auto.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/celery/bootstrap.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/celery/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/celery/constants.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/celery/runner.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/celery/service.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/cli/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/cli/app.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/cli/check.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/cli/schema.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/async_bridge.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/authz/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/authz/_decide.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/authz/_grants.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/authz/_roles.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/authz/_scope.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/authz/elevation.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/authz/product.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/backend/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/backend/core_model.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/backend/protocol.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/backend/scoped_ddl.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/bootstrap/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/bootstrap/kernel.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/_batching.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/_single_flight.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/abc/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/abc/backend.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/abc/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/abc/dependency.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/calls.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/codec.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/decorators.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/dependency.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/gateway.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/keys.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/memory.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/repository.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/result_codec.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/serializer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/cache/wiring.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/checks.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/command/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/command/adapter.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/command/base.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/command/field.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/command/introspection.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/_boto3.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/_includes.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/_resolver_utils.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/binder.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/configurable.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/context.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/keys.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/loader.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/model.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/observability.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/overrides.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/resolver.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/secrets.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/config/ssm.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/contracts/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/contracts/manifest.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/di/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/di/container.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/di/scope.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/discovery/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/discovery/_utils.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/discovery/base.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/discovery/interfaces.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/discovery/manifest.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/discovery/modules.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/engine/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/engine/compilable.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/engine/compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/engine/events.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/engine/executor.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/engine/metrics.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/engine/plan.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/engine/post_commit.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/environment.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/errors/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/errors/codes.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/errors/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/expr/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/expr/eval.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/expr/nodes.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/expr/refs.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/identity/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/identity/context.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/identity/identity.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/identity/issuer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/identity/wire.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/introspection/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/introspection/base.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/introspection/describe.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/job/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/job/callback.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/job/context.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/job/handle.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/job/job.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/job/service.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/locator.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/logger/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/logger/abc.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/logger/checks.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/logger/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/logger/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/logger/structlogger.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/_json_schema.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/base.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/convert.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/enums.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/field.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/partition.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/privilege.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/projection.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/relation.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/scoped.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/struct.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/timestamped.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/model/types_postgres.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/event.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/observer/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/observer/noop.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/observer/otel.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/observer/structlog.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/otel_ids.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/protocol.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/runtime.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/span.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/observability/topology.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/persistence/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/persistence/abc.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/persistence/none.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/persistence/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/plugins/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/plugins/entrypoints.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/plugins/optional.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/projection/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/projection/loaders.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/projection/runtime.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/abc/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/abc/cursor.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/abc/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/abc/query.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/abc/query_compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/abc/repo_for.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/abc/repository.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/abc/session_scope.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/dynamodb/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/dynamodb/backend.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/dynamodb/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/dynamodb/repository.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/dynamodb/uow.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mongo/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mongo/backend.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mongo/ids.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mongo/query_compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mongo/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mongo/repository.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mongo/uow.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mongo/values.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/mutation.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/registration.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/migrations/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/migrations/env_template.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/migrations/hook.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/migrations/operations.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/migrations/runners.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/bootstrap.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/elevate.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/guard/0001.sql +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/guard/0002.sql +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/guard/preflight.sql +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/guard_manifest.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/integrity.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/partitions.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/provider.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/schema.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/sources.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/rls/verify.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/session_manager.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/session_settings.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/response/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/response/base.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/routing/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/routing/ref.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/routing/resolver.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/runner.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/schema/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/schema/schema_mode.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/schema_names.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/abc/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/abc/contracts.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/abc/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/caller_bound.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/clickhouse/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/clickhouse/_client.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/clickhouse/executor.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/clickhouse/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/roles.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/sql/service.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/symbols.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/tracing/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/tracing/context.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/transaction.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/transport/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/transport/adapter.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/uow/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/uow/abc.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/uow/context.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/_predicates.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/agent_markers.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/compute.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/constants.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/factory.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/field_ref.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/invoker.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/keys.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/markers.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/mcp_markers.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/outcome.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/rule.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/core/use_case/use_case.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/_uri.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_format_registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_historify/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_historify/_common.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_historify/_log.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_historify/_ops.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_historify/_transform.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_merge.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_path_template.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_predicate.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_schema_aligner/_policy.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/_write_policy.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_dtype.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_file_writer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_frame.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_historify.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_predicate.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_reader.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_schema.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_streaming.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/_writer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/polars/provider.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/spark/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/spark/_dtype.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/spark/_historify.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/spark/_reader.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/spark/_schema.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/spark/_writer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/backends/spark/provider.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/checkpoint/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/checkpoint/_backends/_polars.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/checkpoint/_cleaners.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/checkpoint/_options.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/checkpoint/_paths.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/checkpoint/_scope.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/checkpoint/_store.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_binding.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_filter.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_plan.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_validators.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_validators_agents.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_validators_config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_validators_plan.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/compiler/_validators_step.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/_format.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/_read_options.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/_utils.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/_with_agent.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/_write_options.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/expr/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/expr/_params.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/expr/_predicate.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/expr/_refs.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/source/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/source/_from.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/source/_from_config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/source/_from_dynamodb.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/source/_specs.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_client.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_file.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_history/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_history/_builder.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_history/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_history/_report.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_history/_spec.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_into.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_schema_mode.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_table.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/declarative/target/_temp.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/executor/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/executor/_agents.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/executor/_dispatcher.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/executor/_executor.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/_registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_clickhouse.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_dynamodb.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_dynamodb_items.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_dynamodb_predicate.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_mongo.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/sources/_serialization.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/targets/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/io/targets/_clickhouse.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/lineage/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/lineage/_config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/lineage/_observer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/lineage/_records.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/lineage/sinks/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/lineage/sinks/_table.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/lineage/sinks/_writer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/maintenance/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/maintenance/_builder.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/maintenance/_ops.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/maintenance/_protocol.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/maintenance/_runner.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/maintenance/_step.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/maintenance/backends/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/maintenance/backends/_delta_rs.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/_generics.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/_params.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/_pipeline.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/_process.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/_sql.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/_step.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/_step_client.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/pipeline/_step_sql.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runner/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runner/_agents.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runner/_providers.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runner/_wiring.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runner/config_loader.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runner/core.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runner/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runner/filtering.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runtime/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runtime/_config_values.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/runtime/contracts.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/schema/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/schema/_contract.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/schema/_schema.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/storage/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/storage/_config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/storage/_file_locator.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/storage/_locator.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/storage/routing.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/testing/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/testing/_result.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/testing/_runners.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/testing/_scenario.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/testing/_stubs.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/etl/testing/spark.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/_async.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/_config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/_ctx.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/_flow_yaml.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/_meta.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/_placeholders.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/_summary.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/deploy/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/deploy/_discovery.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/deploy/_schedule.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/deploy/_yaml_etls.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/deploy/entrypoint.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_assemble.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_backfill.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_backfill_body.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_body.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_common.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_factory.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_hooks.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_maintenance.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_params.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_run_name.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_runtime.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_signature.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/flow/_stages.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/manifest/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/manifest/_model.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/manifest/_s3.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/manifest/_store.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/notify/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/notify/_event.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/notify/_factory.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/notify/_format.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/notify/_port.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/notify/_slack.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/notify/_sns.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/observer/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/observer/_flow.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/observer/_logging_bridge.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/observer/_manifest.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prefect/observer/_task_run.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prometheus/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prometheus/_instruments.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prometheus/adapter.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prometheus/kafka.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prometheus/lifecycle.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/prometheus/middleware.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/py.typed +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/_body.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/adapter.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/auth/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/auth/abc.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/auth/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/auth/jwt.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/auth/middleware.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/autocrud.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/checks.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/constants.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/cors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/_exclusions.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/app.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/auto.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/health.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/openapi.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/response.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/router_runtime.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/fastapi/sql.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/middleware.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/model.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/rest/rest_adapter.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_adapter.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_batch_spans.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_operators.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_runtime_io.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/bytewax/runner.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/compiler/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/compiler/_bindings.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/compiler/_compiler.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/compiler/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/compiler/_plan.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/compiler/phases/build_plan.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/compiler/phases/validate.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/core/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/core/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/core/_exceptions.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/core/_message.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/core/_tracing.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/core/_typing.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/graph/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/graph/_flow.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/_codec.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/_config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/_errors.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/_key_resolver.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/_message.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/_record.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/_wire.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/client/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/client/_consumer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/client/_producer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/client/_protocol.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/client/_retry.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/message/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/message/_consumer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/message/_producer.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/kafka/message/_protocol.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/mongo/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/mongo/_config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/mongo/_event.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/mongo/_normalize.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_boundary.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_branches.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_broadcast.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_capabilities.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_decompose.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_expand_routes.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_expr_eval.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_fork.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_helpers.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_mongo.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_protocols.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_router.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_shape.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_sink.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_table/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_table/common.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_table/config.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/_with.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/nodes/refs.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/streaming/testing.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/testing/__init__.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/testing/agents.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/testing/golden.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/testing/http_harness.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/testing/in_memory.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/testing/repository_harness.py +0 -0
- {loom_kernel-6.0.2 → loom_kernel-8.0.0}/src/loom/testing/runner.py +0 -0
|
@@ -623,6 +623,46 @@
|
|
|
623
623
|
settings take effect: `primary_key=True` adds the column to the primary key,
|
|
624
624
|
which can turn a model's key composite, and `nullable=True` makes the column
|
|
625
625
|
nullable. Review such fields before upgrading.
|
|
626
|
+
- **core:** a `date` field is inferred as a `Date` column and a `time` field
|
|
627
|
+
as a `Time` column (`loom.core.model.Date`, `loom.core.model.Time`, new),
|
|
628
|
+
where both used to be inferred as an unbounded `String`; an enum mixed with
|
|
629
|
+
`date` or `time` follows to `Date` or `Time`. The SQLAlchemy repository
|
|
630
|
+
binds `date` and `time` values natively, so on Postgres with asyncpg writing
|
|
631
|
+
either field failed (`expected str, got date`, and the same for `time`). The
|
|
632
|
+
SQLAlchemy repository now refuses a `time` that carries a UTC offset when it
|
|
633
|
+
is written to, or compared with, a column that would drop the offset, with a
|
|
634
|
+
`BoundaryValidationError` (a `ValueError`) naming the column and not the
|
|
635
|
+
value: `boundary_validation` for a write (REST answers `422`),
|
|
636
|
+
`query_validation` for a filter, `get_by`, `exists_by` or `list_paginated`
|
|
637
|
+
value (`400`). Without the check, Postgres and SQLite would store
|
|
638
|
+
`08:30+02:00` in a `Time` column as `08:30`, and an aware filter value would
|
|
639
|
+
match the row holding `08:30`. A JSON column and a `Time` column declared
|
|
640
|
+
with `ColumnType("Time", kwargs={"timezone": True})` accept it; the JSON
|
|
641
|
+
column keeps the written offset, and so does the `Time` column on Postgres
|
|
642
|
+
(`timetz`), which takes only a `time` with an offset: one without (naive, or
|
|
643
|
+
with a zone but no fixed offset) is refused the same way, under
|
|
644
|
+
`time must carry a UTC offset`, since asyncpg cannot encode it for `timetz`;
|
|
645
|
+
every refused column of a write is reported, in name order. On any other
|
|
646
|
+
dialect startup refuses a `Time(timezone=True)` column with a `ConfigError`
|
|
647
|
+
naming `table.column`, since the dialect would not keep the offset. A
|
|
648
|
+
`datetime` field (`DateTime(tz=True)`) keeps the instant on Postgres
|
|
649
|
+
(`timestamptz`) and MongoDB, read back in UTC, not the written offset.
|
|
650
|
+
`get_by`, `exists_by` and the `filters` of `list_paginated` now convert
|
|
651
|
+
their value as a write converts it, as `QuerySpec` filters already did, so a
|
|
652
|
+
plain `Enum` member matches the value the write stored instead of failing to
|
|
653
|
+
bind. A `list_paginated` filter, `get_by` or `exists_by` on a name that is
|
|
654
|
+
not a mapped column of the model (a missing field, a relation, an attribute
|
|
655
|
+
such as `metadata`) raises `ValueError` naming it. An existing Postgres
|
|
656
|
+
table holding these columns as `varchar` needs a migration: Alembic
|
|
657
|
+
autogenerate detects the type change, but Postgres refuses it without a
|
|
658
|
+
cast, so the revision passes `postgresql_using="c::date"` (`"c::time"` for a
|
|
659
|
+
`time` field) to `op.alter_column`, which is
|
|
660
|
+
`ALTER TABLE t ALTER COLUMN c TYPE date USING c::date`. `c::time` drops any
|
|
661
|
+
offset the stored text holds (`'08:30+02'::time` is `08:30`): check first
|
|
662
|
+
with `SELECT c FROM t WHERE c ~ '[+-]\d{2}(:?\d{2})?$'`, and if offsets are
|
|
663
|
+
present convert those rows deliberately (for example to UTC with
|
|
664
|
+
`(c::timetz AT TIME ZONE 'UTC')::time`) before changing the type. MongoDB is
|
|
665
|
+
unaffected: it stores `date` and `time` values as ISO 8601 strings.
|
|
626
666
|
|
|
627
667
|
### ai
|
|
628
668
|
|
|
@@ -909,6 +949,24 @@
|
|
|
909
949
|
|
|
910
950
|
### streaming
|
|
911
951
|
|
|
952
|
+
- **streaming:** `BatchExpandStep.execute` returns one list of payloads per
|
|
953
|
+
message of its batch, in batch order, instead of one flat list. List `i`
|
|
954
|
+
holds what `messages[i]` expands into; each output takes that message's
|
|
955
|
+
metadata, and an empty list filters the message out. A result whose length
|
|
956
|
+
differs from the batch, a flat list of payloads, a `Message` among the
|
|
957
|
+
outputs, or a `str`, `bytes`, `bytearray` or mapping in place of the result
|
|
958
|
+
or of one of its lists raises `TypeError`, and the batch becomes error
|
|
959
|
+
envelopes.
|
|
960
|
+
|
|
961
|
+
```python
|
|
962
|
+
# before
|
|
963
|
+
def execute(self, messages: list[Message[Event]], **kwargs: object) -> list[Score]:
|
|
964
|
+
return [Score(value=m.payload.amount) for m in messages]
|
|
965
|
+
|
|
966
|
+
# after
|
|
967
|
+
def execute(self, messages: list[Message[Event]], **kwargs: object) -> list[list[Score]]:
|
|
968
|
+
return [[Score(value=m.payload.amount)] for m in messages]
|
|
969
|
+
```
|
|
912
970
|
- **streaming:** compile issues come from the code catalogue
|
|
913
971
|
(`StreamingErrorCode.X.issue(...)`), and the compiler's private issue
|
|
914
972
|
factories are removed. `loom.streaming.compiler.CompilationIssue` is a type
|
|
@@ -1367,6 +1425,14 @@
|
|
|
1367
1425
|
`Drain` default failed with `ROUTER_BRANCH_SHAPE_DIVERGENCE`, and a step
|
|
1368
1426
|
after a `Router` without a default whose branches all end their path failed
|
|
1369
1427
|
with `SHAPE_MISMATCH`; both compile now.
|
|
1428
|
+
- **streaming:** a `BatchExpandStep` expands. Every output had to pair with
|
|
1429
|
+
one input message, so a step returning more or fewer outputs than its batch
|
|
1430
|
+
raised and each message of the batch became an error envelope. Under
|
|
1431
|
+
at-least-once delivery each source offset now completes once per output,
|
|
1432
|
+
after that output's write, and a message with no output completes its
|
|
1433
|
+
offset at the step, also when the batch holds several messages of one
|
|
1434
|
+
offset that an earlier expanding node produced. The new return type is under
|
|
1435
|
+
Behaviour changes.
|
|
1370
1436
|
|
|
1371
1437
|
### prefect
|
|
1372
1438
|
|
|
@@ -15,6 +15,7 @@ from sqlalchemy import (
|
|
|
15
15
|
CheckConstraint,
|
|
16
16
|
Column,
|
|
17
17
|
Constraint,
|
|
18
|
+
Date,
|
|
18
19
|
DateTime,
|
|
19
20
|
Float,
|
|
20
21
|
ForeignKey,
|
|
@@ -27,6 +28,7 @@ from sqlalchemy import (
|
|
|
27
28
|
String,
|
|
28
29
|
Table,
|
|
29
30
|
Text,
|
|
31
|
+
Time,
|
|
30
32
|
UniqueConstraint,
|
|
31
33
|
func,
|
|
32
34
|
text,
|
|
@@ -80,7 +82,9 @@ _SA_TYPE_MAP: dict[str, type] = {
|
|
|
80
82
|
"Text": Text,
|
|
81
83
|
"JSON": JSON,
|
|
82
84
|
"Bytes": LargeBinary,
|
|
85
|
+
"Date": Date,
|
|
83
86
|
"DateTime": DateTime,
|
|
87
|
+
"Time": Time,
|
|
84
88
|
"Numeric": Numeric,
|
|
85
89
|
"Postgres.JSONB": PG_JSONB,
|
|
86
90
|
"Postgres.UUID": PG_UUID,
|
|
@@ -44,6 +44,7 @@ from loom.core.model.types import (
|
|
|
44
44
|
BigInteger,
|
|
45
45
|
Boolean,
|
|
46
46
|
Bytes,
|
|
47
|
+
Date,
|
|
47
48
|
DateTime,
|
|
48
49
|
Float,
|
|
49
50
|
Integer,
|
|
@@ -51,6 +52,7 @@ from loom.core.model.types import (
|
|
|
51
52
|
Numeric,
|
|
52
53
|
String,
|
|
53
54
|
Text,
|
|
55
|
+
Time,
|
|
54
56
|
)
|
|
55
57
|
from loom.core.model.types_postgres import Postgres
|
|
56
58
|
|
|
@@ -85,6 +87,7 @@ __all__ = [
|
|
|
85
87
|
"ColumnField",
|
|
86
88
|
"ScopedField",
|
|
87
89
|
"ColumnType",
|
|
90
|
+
"Date",
|
|
88
91
|
"DateTime",
|
|
89
92
|
"Field",
|
|
90
93
|
"Float",
|
|
@@ -105,6 +108,7 @@ __all__ = [
|
|
|
105
108
|
"ServerOnUpdate",
|
|
106
109
|
"String",
|
|
107
110
|
"Text",
|
|
111
|
+
"Time",
|
|
108
112
|
"UnsupportedBoundaryType",
|
|
109
113
|
"get_column_fields",
|
|
110
114
|
"get_id_attribute",
|
|
@@ -107,7 +107,9 @@ class BoundaryValidationError(LoomError, ValueError):
|
|
|
107
107
|
reasons drop the detail pydantic derives from the input; the msgspec
|
|
108
108
|
message is forwarded as one line, without the value msgspec echoes for an
|
|
109
109
|
invalid enum value or tag. A message raised by the type's own validator
|
|
110
|
-
keeps its text.
|
|
110
|
+
keeps its text. A repository raises it for a value its storage cannot
|
|
111
|
+
hold, such as the SQLAlchemy repository for a ``time`` whose UTC offset,
|
|
112
|
+
present or missing, its column cannot take. It is also a
|
|
111
113
|
:class:`ValueError`, so an ``except ValueError`` that used to catch
|
|
112
114
|
``msgspec.ValidationError`` or ``pydantic.ValidationError`` keeps
|
|
113
115
|
catching it.
|
|
@@ -31,11 +31,13 @@ from loom.core.model.types import (
|
|
|
31
31
|
JSON,
|
|
32
32
|
Boolean,
|
|
33
33
|
Bytes,
|
|
34
|
+
Date,
|
|
34
35
|
DateTime,
|
|
35
36
|
Float,
|
|
36
37
|
Integer,
|
|
37
38
|
Numeric,
|
|
38
39
|
String,
|
|
40
|
+
Time,
|
|
39
41
|
)
|
|
40
42
|
from loom.core.schema_names import sql_identifier
|
|
41
43
|
|
|
@@ -405,8 +407,8 @@ _SCALAR_TYPE_MAP: dict[type, ColumnType] = {
|
|
|
405
407
|
bool: Boolean,
|
|
406
408
|
bytes: Bytes,
|
|
407
409
|
datetime: DateTime(tz=True),
|
|
408
|
-
date:
|
|
409
|
-
time:
|
|
410
|
+
date: Date,
|
|
411
|
+
time: Time,
|
|
410
412
|
Decimal: Numeric(),
|
|
411
413
|
}
|
|
412
414
|
|
|
@@ -9,7 +9,7 @@ from contextlib import asynccontextmanager
|
|
|
9
9
|
from typing import ClassVar, Final, Literal
|
|
10
10
|
|
|
11
11
|
import msgspec
|
|
12
|
-
from sqlalchemy import inspect, make_url, text
|
|
12
|
+
from sqlalchemy import MetaData, Time, inspect, make_url, text
|
|
13
13
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
|
14
14
|
|
|
15
15
|
from loom.core.authz.elevation import ElevationSink
|
|
@@ -205,6 +205,31 @@ def startup_checks(
|
|
|
205
205
|
return unprotected
|
|
206
206
|
|
|
207
207
|
|
|
208
|
+
def check_time_zone_columns(dialect: str, metadata: MetaData) -> None:
|
|
209
|
+
"""Refuse a ``Time(timezone=True)`` column on a dialect that drops its offset.
|
|
210
|
+
|
|
211
|
+
Postgres stores such a column as ``time with time zone`` and keeps the
|
|
212
|
+
offset; SQLite ignores the zone and stores the time without it.
|
|
213
|
+
|
|
214
|
+
Raises:
|
|
215
|
+
ConfigError: When *metadata* holds such a column and *dialect* is not
|
|
216
|
+
Postgres, naming each ``table.column``.
|
|
217
|
+
"""
|
|
218
|
+
if dialect == POSTGRES_DIALECT:
|
|
219
|
+
return
|
|
220
|
+
columns = sorted(
|
|
221
|
+
f"{table.name}.{column.name}"
|
|
222
|
+
for table in metadata.tables.values()
|
|
223
|
+
for column in table.columns
|
|
224
|
+
if isinstance(column.type, Time) and column.type.timezone
|
|
225
|
+
)
|
|
226
|
+
if columns:
|
|
227
|
+
raise ConfigError(
|
|
228
|
+
f"dialect {dialect!r} would drop the UTC offset of the Time(timezone=True) "
|
|
229
|
+
f"columns {', '.join(columns)}; declare a JSON column to keep the offset"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
|
|
208
233
|
@asynccontextmanager
|
|
209
234
|
async def _lifespan(
|
|
210
235
|
session_manager: SessionManager,
|
|
@@ -223,6 +248,7 @@ async def _lifespan(
|
|
|
223
248
|
scoped,
|
|
224
249
|
has_session_settings=session_manager.has_session_settings,
|
|
225
250
|
)
|
|
251
|
+
check_time_zone_columns(session_manager.engine.dialect.name, get_metadata())
|
|
226
252
|
if unprotected:
|
|
227
253
|
_logger.warning(
|
|
228
254
|
"scoped tables left unprotected on this dialect: %s", ", ".join(unprotected)
|
|
@@ -11,6 +11,7 @@ from sqlalchemy import update as sa_update
|
|
|
11
11
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
12
12
|
|
|
13
13
|
from loom.core.backend.sqlalchemy import get_compiled_core
|
|
14
|
+
from loom.core.errors.codes import ErrorCode
|
|
14
15
|
from loom.core.model.convert import to_struct
|
|
15
16
|
from loom.core.model.introspection import (
|
|
16
17
|
get_column_fields,
|
|
@@ -33,7 +34,12 @@ from loom.core.repository.mutation import MutationEvent
|
|
|
33
34
|
from loom.core.repository.sqlalchemy.integrity import handle_integrity_errors
|
|
34
35
|
from loom.core.repository.sqlalchemy.query_compiler.compiler import QuerySpecCompiler
|
|
35
36
|
from loom.core.repository.sqlalchemy.transactional import record_mutation
|
|
36
|
-
from loom.core.repository.sqlalchemy.values import
|
|
37
|
+
from loom.core.repository.sqlalchemy.values import (
|
|
38
|
+
check_time_offsets,
|
|
39
|
+
is_json_column,
|
|
40
|
+
to_column_value,
|
|
41
|
+
to_comparison_value,
|
|
42
|
+
)
|
|
37
43
|
|
|
38
44
|
_SENTINEL = object()
|
|
39
45
|
_TOTAL_COUNT_ALIAS = "__loom_total_count"
|
|
@@ -161,7 +167,14 @@ class SQLAlchemyContextMixin(Generic[OutputT, IdT]):
|
|
|
161
167
|
builtins = to_column_value(data)
|
|
162
168
|
if not isinstance(builtins, dict):
|
|
163
169
|
raise TypeError("Struct payload must serialize to dict")
|
|
164
|
-
|
|
170
|
+
values = self._encode_json_columns(_to_internal_field_names(type(data), builtins))
|
|
171
|
+
sa_model = self._effective_sa_model
|
|
172
|
+
names = (self._column_field_names or frozenset()).intersection(values)
|
|
173
|
+
check_time_offsets(
|
|
174
|
+
((getattr(sa_model, name), values[name]) for name in names),
|
|
175
|
+
code=ErrorCode.BOUNDARY_VALIDATION,
|
|
176
|
+
)
|
|
177
|
+
return values
|
|
165
178
|
return data
|
|
166
179
|
|
|
167
180
|
def _encode_json_columns(self, values: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -174,10 +187,11 @@ class SQLAlchemyContextMixin(Generic[OutputT, IdT]):
|
|
|
174
187
|
"""Resolve a model column attribute by field name.
|
|
175
188
|
|
|
176
189
|
Raises:
|
|
177
|
-
ValueError: If ``field``
|
|
190
|
+
ValueError: If ``field`` is not a mapped column of the SQLAlchemy
|
|
191
|
+
model.
|
|
178
192
|
"""
|
|
179
193
|
sa_model = self._effective_sa_model
|
|
180
|
-
if not
|
|
194
|
+
if field not in inspect(sa_model).column_attrs:
|
|
181
195
|
raise ValueError(f"Unknown field '{field}' for model '{self.model.__name__}'")
|
|
182
196
|
return getattr(sa_model, field)
|
|
183
197
|
|
|
@@ -189,7 +203,12 @@ class SQLAlchemyContextMixin(Generic[OutputT, IdT]):
|
|
|
189
203
|
"""Apply page-mode filters to an offset items statement."""
|
|
190
204
|
if not filter_params or not filter_params.filters:
|
|
191
205
|
return items_stmt
|
|
192
|
-
return items_stmt.filter_by(
|
|
206
|
+
return items_stmt.filter_by(
|
|
207
|
+
**{
|
|
208
|
+
name: to_comparison_value(self._column_for_field(name), value)
|
|
209
|
+
for name, value in filter_params.filters.items()
|
|
210
|
+
}
|
|
211
|
+
)
|
|
193
212
|
|
|
194
213
|
def _to_output(
|
|
195
214
|
self,
|
|
@@ -441,7 +460,9 @@ class SQLAlchemyReadMixin(SQLAlchemyContextMixin[OutputT, IdT], Generic[OutputT,
|
|
|
441
460
|
"""Fetch one entity by equality over an arbitrary column field."""
|
|
442
461
|
async with self._session_scope() as scoped_session:
|
|
443
462
|
core_model = self._effective_core_model
|
|
444
|
-
|
|
463
|
+
column = self._column_for_field(field)
|
|
464
|
+
stmt = core_model.select(profile).where(column == to_comparison_value(column, value))
|
|
465
|
+
stmt = stmt.limit(1)
|
|
445
466
|
loaded = await core_model.fetch_one(scoped_session, stmt, profile=profile)
|
|
446
467
|
return cast(OutputT | None, loaded)
|
|
447
468
|
|
|
@@ -575,7 +596,8 @@ class SQLAlchemyReadMixin(SQLAlchemyContextMixin[OutputT, IdT], Generic[OutputT,
|
|
|
575
596
|
|
|
576
597
|
async def exists_by(self, field: str, value: Any) -> bool:
|
|
577
598
|
"""Check whether an entity exists by an arbitrary column field."""
|
|
578
|
-
|
|
599
|
+
column = self._column_for_field(field)
|
|
600
|
+
return await self._exists_where(column == to_comparison_value(column, value))
|
|
579
601
|
|
|
580
602
|
async def _exists_where(self, clause: Any) -> bool:
|
|
581
603
|
async with self._session_scope() as scoped_session:
|
|
@@ -15,7 +15,7 @@ from loom.core.repository.sqlalchemy.query_compiler.subquery import (
|
|
|
15
15
|
compile_exists,
|
|
16
16
|
compile_not_exists,
|
|
17
17
|
)
|
|
18
|
-
from loom.core.repository.sqlalchemy.values import
|
|
18
|
+
from loom.core.repository.sqlalchemy.values import to_comparison_value
|
|
19
19
|
|
|
20
20
|
_RELATION_OPS = frozenset([FilterOp.EXISTS, FilterOp.NOT_EXISTS])
|
|
21
21
|
_SIMPLE_OPS: dict[FilterOp, Callable[[Any, Any], Any]] = {
|
|
@@ -50,6 +50,8 @@ def compile_filter_group(
|
|
|
50
50
|
Raises:
|
|
51
51
|
UnsafeFilterError: If a field is not in ``allowed_fields``.
|
|
52
52
|
FilterPathError: If a field path cannot be resolved.
|
|
53
|
+
BoundaryValidationError: ``query_validation``, for a ``time`` whose
|
|
54
|
+
offset the compared column cannot take.
|
|
53
55
|
"""
|
|
54
56
|
clauses = [_compile_spec(sa_model, spec, allowed_fields) for spec in group.filters]
|
|
55
57
|
if group.op == "OR":
|
|
@@ -78,17 +80,22 @@ def _compile_spec(
|
|
|
78
80
|
def _apply_op(col: Any, op: FilterOp, value: Any) -> Any:
|
|
79
81
|
"""Apply *op*, converting *value* as the repository converts a value it writes.
|
|
80
82
|
|
|
81
|
-
A
|
|
82
|
-
|
|
83
|
+
A ``time`` whose offset the column cannot take is refused, as
|
|
84
|
+
:func:`to_comparison_value` refuses it. A SQLAlchemy expression, and an
|
|
85
|
+
``IN`` value that is a string or not iterable, reach SQLAlchemy as they
|
|
86
|
+
are.
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
ValueError: If *op* is not a supported operator.
|
|
90
|
+
BoundaryValidationError: ``query_validation``, for a refused ``time``.
|
|
83
91
|
"""
|
|
84
92
|
handler = _SIMPLE_OPS.get(op)
|
|
85
93
|
if handler is None:
|
|
86
94
|
raise ValueError(f"Unsupported FilterOp: {op!r}")
|
|
87
95
|
if isinstance(value, ClauseElement):
|
|
88
96
|
return handler(col, value)
|
|
89
|
-
json = is_json_column(col)
|
|
90
97
|
if op is not FilterOp.IN:
|
|
91
|
-
return handler(col,
|
|
98
|
+
return handler(col, to_comparison_value(col, value))
|
|
92
99
|
if isinstance(value, str | bytes) or not isinstance(value, Iterable):
|
|
93
100
|
return handler(col, value)
|
|
94
|
-
return handler(col, [
|
|
101
|
+
return handler(col, [to_comparison_value(col, item) for item in value])
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Column form of model values in SQLAlchemy rows.
|
|
2
|
+
|
|
3
|
+
SQLAlchemy binds ``bytes``, ``datetime``, ``date``, ``time``, ``Decimal`` and
|
|
4
|
+
``UUID`` natively; every other value is reduced to msgspec builtins (an
|
|
5
|
+
``Enum`` to its value, a struct to a dict). A JSON column holds builtins only,
|
|
6
|
+
so its values are reduced completely.
|
|
7
|
+
|
|
8
|
+
:func:`to_column_value` is the conversion the repository applies to a value it
|
|
9
|
+
writes, and :func:`to_comparison_value` the one it applies to a value compared
|
|
10
|
+
with a column (a filter, ``get_by``, ``exists_by``), so a comparison matches
|
|
11
|
+
exactly what the row holds.
|
|
12
|
+
|
|
13
|
+
A ``time`` with a UTC offset is refused for a column that cannot hold the
|
|
14
|
+
offset: SQL ``TIME`` without time zone (Postgres ``time``, SQLite text) stores
|
|
15
|
+
``08:30+02:00`` as ``08:30``, and an aware value compared with it matches the
|
|
16
|
+
row holding ``08:30``. A JSON column, which keeps the ISO text, takes any
|
|
17
|
+
``time``. A ``Time`` column with ``timezone=True`` (Postgres ``timetz``) takes
|
|
18
|
+
only a ``time`` with an offset: asyncpg cannot encode a naive one for it. The
|
|
19
|
+
SQLAlchemy backend refuses such a column at startup on any dialect other than
|
|
20
|
+
Postgres.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from collections.abc import Iterable
|
|
26
|
+
from datetime import date, datetime, time
|
|
27
|
+
from decimal import Decimal
|
|
28
|
+
from typing import Any
|
|
29
|
+
from uuid import UUID
|
|
30
|
+
|
|
31
|
+
import msgspec
|
|
32
|
+
from sqlalchemy import JSON, Time
|
|
33
|
+
|
|
34
|
+
from loom.core.errors.codes import ErrorCode
|
|
35
|
+
from loom.core.model import BoundaryValidationError
|
|
36
|
+
|
|
37
|
+
# Values SQLAlchemy binds natively; encoding them to strings breaks typed columns.
|
|
38
|
+
_NATIVE_COLUMN_TYPES = (bytes, datetime, date, time, Decimal, UUID)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def to_column_value(value: object, *, json: bool = False) -> Any:
|
|
42
|
+
"""Return the form ``value`` takes in a column.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
value: A model value or a filter value.
|
|
46
|
+
json: ``True`` when the column is a JSON column.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
``value`` reduced to msgspec builtins, keeping the natively bound
|
|
50
|
+
types unless the column is a JSON column.
|
|
51
|
+
"""
|
|
52
|
+
if json:
|
|
53
|
+
return msgspec.to_builtins(value)
|
|
54
|
+
return msgspec.to_builtins(value, builtin_types=_NATIVE_COLUMN_TYPES)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
_OFFSET_REFUSED = "time must not carry a UTC offset"
|
|
58
|
+
_OFFSET_REQUIRED = "time must carry a UTC offset"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def check_time_offsets(bindings: Iterable[tuple[Any, object]], *, code: str) -> None:
|
|
62
|
+
"""Raise when a time's offset, present or missing, does not fit the column it is bound to.
|
|
63
|
+
|
|
64
|
+
A JSON column takes any ``time``. A ``Time(timezone=True)`` column keeps the
|
|
65
|
+
offset and takes only a ``time`` that has one (``utcoffset()`` is not
|
|
66
|
+
``None``); every other column drops the offset and takes only a ``time``
|
|
67
|
+
without one. A model that needs the offset declares a JSON column or
|
|
68
|
+
``ColumnType("Time", kwargs={"timezone": True})`` (Postgres only); on
|
|
69
|
+
Postgres a ``datetime`` field keeps the instant instead. The error names
|
|
70
|
+
the columns, not the values.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
bindings: ``(column, value)`` pairs, each a SQLAlchemy column or mapped
|
|
74
|
+
attribute and a value about to be written to or compared with it.
|
|
75
|
+
code: ``boundary_validation`` for written values, ``query_validation``
|
|
76
|
+
for compared values.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
BoundaryValidationError: With one violation per refused column, in
|
|
80
|
+
column name order.
|
|
81
|
+
"""
|
|
82
|
+
violations = sorted(
|
|
83
|
+
(column.key, reason)
|
|
84
|
+
for column, value in bindings
|
|
85
|
+
if (reason := _time_offset_refusal(column, value)) is not None
|
|
86
|
+
)
|
|
87
|
+
if violations:
|
|
88
|
+
message = "; ".join(f"{name}: {reason}" for name, reason in violations)
|
|
89
|
+
raise BoundaryValidationError(message, tuple(violations), code=code)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _time_offset_refusal(column: Any, value: object) -> str | None:
|
|
93
|
+
if not isinstance(value, time) or is_json_column(column):
|
|
94
|
+
return None
|
|
95
|
+
column_type = getattr(column, "type", None)
|
|
96
|
+
keeps_offset = isinstance(column_type, Time) and bool(column_type.timezone)
|
|
97
|
+
if (value.utcoffset() is not None) == keeps_offset:
|
|
98
|
+
return None
|
|
99
|
+
return _OFFSET_REQUIRED if keeps_offset else _OFFSET_REFUSED
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def to_comparison_value(column: Any, value: object) -> Any:
|
|
103
|
+
"""Return *value* in the form it is compared with *column*.
|
|
104
|
+
|
|
105
|
+
Refused as :func:`check_time_offsets` refuses it, and converted as
|
|
106
|
+
:func:`to_column_value` converts a written value. A refusal is raised under
|
|
107
|
+
``query_validation`` whatever the value's source, so ``get_by`` and
|
|
108
|
+
``exists_by`` called with a value from a command body raise it too.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
column: A SQLAlchemy column or mapped attribute.
|
|
112
|
+
value: A filter or lookup value.
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
BoundaryValidationError: ``query_validation``, for a ``time`` whose
|
|
116
|
+
offset *column* cannot take, as :func:`check_time_offsets` decides.
|
|
117
|
+
"""
|
|
118
|
+
check_time_offsets(((column, value),), code=ErrorCode.QUERY_VALIDATION)
|
|
119
|
+
return to_column_value(value, json=is_json_column(column))
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def is_json_column(column: object) -> bool:
|
|
123
|
+
"""Whether *column*, a SQLAlchemy column or mapped attribute, holds JSON.
|
|
124
|
+
|
|
125
|
+
``JSON`` and the dialect types derived from it (Postgres ``JSONB``) count.
|
|
126
|
+
"""
|
|
127
|
+
return isinstance(getattr(column, "type", None), JSON)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
__all__ = ["check_time_offsets", "is_json_column", "to_column_value", "to_comparison_value"]
|
|
@@ -36,6 +36,7 @@ if TYPE_CHECKING:
|
|
|
36
36
|
|
|
37
37
|
Stream: TypeAlias = Any
|
|
38
38
|
AwaitT = TypeVar("AwaitT")
|
|
39
|
+
ExpandT = TypeVar("ExpandT", bound=Iterable[Any])
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
@runtime_checkable
|
|
@@ -91,11 +92,8 @@ class _ExecutableBatchExpandStep(Protocol):
|
|
|
91
92
|
self,
|
|
92
93
|
messages: list[Message[StreamPayload]],
|
|
93
94
|
**kwargs: object,
|
|
94
|
-
) ->
|
|
95
|
-
|
|
96
|
-
| Awaitable[Iterable[StreamPayload | Message[StreamPayload]]]
|
|
97
|
-
):
|
|
98
|
-
"""Expand one batch into many payloads or replacement messages."""
|
|
95
|
+
) -> Iterable[Iterable[StreamPayload]] | Awaitable[Iterable[Iterable[StreamPayload]]]:
|
|
96
|
+
"""Expand each message of one batch into its own list of payloads."""
|
|
99
97
|
...
|
|
100
98
|
|
|
101
99
|
|
|
@@ -259,10 +257,9 @@ def _resolve_batch_result(
|
|
|
259
257
|
|
|
260
258
|
|
|
261
259
|
def _resolve_expand_result(
|
|
262
|
-
result:
|
|
263
|
-
| Awaitable[Iterable[StreamPayload | Message[StreamPayload]]],
|
|
260
|
+
result: ExpandT | Awaitable[ExpandT],
|
|
264
261
|
node_type: str,
|
|
265
|
-
) ->
|
|
262
|
+
) -> ExpandT:
|
|
266
263
|
"""Resolve a synchronous expanding result and reject awaitables."""
|
|
267
264
|
if isinstance(result, Awaitable):
|
|
268
265
|
raise TypeError(f"{node_type} returned an awaitable outside WithAsync.")
|
|
@@ -353,9 +350,11 @@ def _reconcile_fanout(
|
|
|
353
350
|
|
|
354
351
|
An expanding node turns one input record into N outputs that all carry the
|
|
355
352
|
same source offset, and every one of them completes that offset when it
|
|
356
|
-
reaches a terminal.
|
|
357
|
-
|
|
358
|
-
|
|
353
|
+
reaches a terminal. Each input already owes one completion, and a batch can
|
|
354
|
+
hold several inputs of one offset when an earlier node expanded it, so per
|
|
355
|
+
offset the outputs are compared with the inputs: extra outputs fork the
|
|
356
|
+
difference, and missing ones complete it here — while the outputs are still
|
|
357
|
+
a plain list and none of them can have reached a terminal yet.
|
|
359
358
|
|
|
360
359
|
Two failures this prevents, both silent:
|
|
361
360
|
|
|
@@ -372,20 +371,21 @@ def _reconcile_fanout(
|
|
|
372
371
|
"""
|
|
373
372
|
if tracker is None:
|
|
374
373
|
return
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
tracker.fork(key[0], key[1], key[2], count - 1)
|
|
383
|
-
for original in originals:
|
|
384
|
-
key = _commit_key(original)
|
|
385
|
-
if key is not None and key not in produced:
|
|
374
|
+
expected = _commit_key_counts(originals)
|
|
375
|
+
produced = _commit_key_counts(results)
|
|
376
|
+
for key in expected | produced:
|
|
377
|
+
delta = produced[key] - expected[key]
|
|
378
|
+
if delta > 0:
|
|
379
|
+
tracker.fork(key[0], key[1], key[2], delta)
|
|
380
|
+
for _ in range(-delta):
|
|
386
381
|
tracker.complete(key[0], key[1], key[2])
|
|
387
382
|
|
|
388
383
|
|
|
384
|
+
def _commit_key_counts(items: Sequence[Any]) -> Counter[tuple[str, int, int]]:
|
|
385
|
+
"""Count the items accountable for each source offset."""
|
|
386
|
+
return Counter(key for item in items if (key := _commit_key(item)) is not None)
|
|
387
|
+
|
|
388
|
+
|
|
389
389
|
def _drop_and_commit(item: Any, tracker: CommitCompletionPort) -> tuple[()]:
|
|
390
390
|
"""Drop one item and mark it complete for commit tracking.
|
|
391
391
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from collections.abc import Iterable
|
|
5
|
+
from collections.abc import Iterable, Mapping
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
from bytewax.operators import flat_map
|
|
@@ -134,8 +134,6 @@ def _apply_expand_step(
|
|
|
134
134
|
|
|
135
135
|
sid = _step_id(f"expand_{idx}_{name}", ctx)
|
|
136
136
|
mapped = bw_map(sid, stream, step_fn)
|
|
137
|
-
from bytewax.operators import flat_map
|
|
138
|
-
|
|
139
137
|
flattened_stream = flat_map(_step_id(f"flatten_expand_{idx}", ctx), mapped, _identity)
|
|
140
138
|
return _split_node_result(flattened_stream, sid, ctx, ErrorKind.TASK)
|
|
141
139
|
|
|
@@ -296,9 +294,44 @@ def _execute_batch_expand_step(
|
|
|
296
294
|
correlation_id=messages[0].meta.correlation_id if messages else None,
|
|
297
295
|
):
|
|
298
296
|
result = _resolve_expand_result(batch_expand_step.execute(messages), name)
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
297
|
+
return _outputs_per_message(messages, _result_list(result, name), name)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _outputs_per_message(
|
|
301
|
+
messages: list[Message[StreamPayload]],
|
|
302
|
+
groups: list[Any],
|
|
303
|
+
name: str,
|
|
304
|
+
) -> list[Message[StreamPayload]]:
|
|
305
|
+
"""Give each output the metadata of the message whose list it is in.
|
|
306
|
+
|
|
307
|
+
``groups[i]`` holds the outputs of ``messages[i]``; an empty list filters
|
|
308
|
+
that message out.
|
|
309
|
+
"""
|
|
310
|
+
if len(groups) != len(messages):
|
|
311
|
+
raise TypeError(
|
|
312
|
+
f"{name} returned {len(groups)} output lists for {len(messages)} messages; "
|
|
313
|
+
"return one list of payloads per message, in batch order."
|
|
314
|
+
)
|
|
315
|
+
outputs: list[Message[StreamPayload]] = []
|
|
316
|
+
for message, payloads in zip(messages, groups, strict=True):
|
|
317
|
+
for payload in _result_list(payloads, name):
|
|
318
|
+
if isinstance(payload, Message):
|
|
319
|
+
raise TypeError(
|
|
320
|
+
f"{name} must return payloads, not messages: each output "
|
|
321
|
+
"takes the metadata of the message it came from."
|
|
322
|
+
)
|
|
323
|
+
outputs.append(_replace_payload(message, payload))
|
|
324
|
+
return outputs
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _result_list(value: object, name: str) -> list[Any]:
|
|
328
|
+
"""Materialize one list of a batch-expanding result, iterating it once.
|
|
329
|
+
|
|
330
|
+
``str``, ``bytes`` and mappings are iterable but are not lists of results.
|
|
331
|
+
"""
|
|
332
|
+
if not isinstance(value, Iterable) or isinstance(value, (str, bytes, bytearray, Mapping)):
|
|
333
|
+
raise TypeError(f"{name} must return one list of payloads per message.")
|
|
334
|
+
return list(value)
|
|
302
335
|
|
|
303
336
|
|
|
304
337
|
def _execute_explode_step(
|