matrx-orm 3.1.201__tar.gz → 3.1.203__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.
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/PKG-INFO +2 -2
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/session_context.py +78 -3
- matrx_orm-3.1.203/matrx_orm/pytest_production_door.py +353 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/diff_preview.py +7 -0
- matrx_orm-3.1.203/matrx_orm/schema_builder/excluded_targets.py +93 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/runner.py +7 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/schema_manager.py +26 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/pyproject.toml +3 -2
- matrx_orm-3.1.203/tests/schema/test_excluded_fk_targets.py +128 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/.gitignore +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/AGENTS.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/BASE_CLASS_METHODS.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/CHANGELOG.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/CLAUDE.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/MODEL_API.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/database/orm/extended/managers/ai_model_base.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/docs/migrations.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/FEATURE.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/adapters/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/adapters/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/adapters/async_postgresql.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/adapters/base_adapter.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/adapters/supabase_adapter.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/admin/FEATURE.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/admin/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/admin/router.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/api/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/api/auth.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/api/config.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/api/handlers.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/api/protocol.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/api/server.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/associations.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/cache_debug.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/catalog.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/catalog_sql.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/client/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/client/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/client/postgres_connection.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/client/postgrest.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/client/supabase_auth.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/client/supabase_config.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/client/supabase_manager.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/EXTENDED-TASK.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/FEATURE.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/TASKS.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/admin_lane.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/async_db_manager.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/base.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/config.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/connections.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/db_function.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/diagnostics.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/expressions.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/extended.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/fields.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/introspection.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/listen.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/loop_filters.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/model_dto.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/model_view.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/one_database.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/paginator.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/pool_maintenance.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/pool_watch.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/pooler_role.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/pydantic_bridge.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/read_write.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/registry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/relations.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/resilience.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/rls_session.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/signals.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/statement_ceiling.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/tls.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/transaction.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/types.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/write_queue.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/core/write_retry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/entity.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/error_handling.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/exceptions.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/extended/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/extended/app_error_handler.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/identity_rule.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/local_sqlite.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/middleware/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/middleware/base.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/cli.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/ddl.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/diff.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/executor.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/integration.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/loader.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/operations.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/state.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/migrations/table_filter.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/no_org_assignment.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/FEATURE.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/bulk_update_values.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/catalog_select.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/conflict.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/conflict_writes.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/create.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/db_functions.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/delete.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/dynamic_admin.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/dynamic_crud.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/graph_walk.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/latest_rows.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/queue_claim.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/read.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/relational_backfill.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/staging_load.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/operations/update.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/platform_access.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/platform_db.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/py.typed +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/pytest_live_db_guard.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/pytest_lock_guard.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/pytest_plugin.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/python_sql/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/python_sql/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/python_sql/db_objects.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/query/FEATURE.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/query/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/query/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/query/builder.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/query/executor.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/resources/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/FEATURE.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/code_handler.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/codegen_writer.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/columns.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/common.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/generator.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/package_wiring.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/relationships.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/schema.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/tables.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/schema_builder/views.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/FEATURE.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/attachments.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/backup_restore.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/crypto.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/host_authorization.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/items.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/model.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/native_enable.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/native_source.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/org_service.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/service.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/secrets_battery/vault_history.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/coalesce.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/dag.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/errors.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/fallback.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/flush.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/lifecycle.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/managed.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/op.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/reads.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/session.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/session/telemetry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/sql_executor/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/sql_executor/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/sql_executor/executor.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/sql_executor/queries.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/sql_executor/registry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/sql_executor/types.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/sql_executor/utils.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/state.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/utils/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/utils/sql_utils.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/utils/type_converters.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/matrx_orm/write_actor.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/scripts/git-branches.sh +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/scripts/publish.sh +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/scripts/release.sh +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/conftest.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_adapter_registry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_admin_db_columns.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_admin_response_rendering.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_admin_search_negation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_admin_search_sentinels.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_advisory_lock.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_agent_message.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_api_auth.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_api_config.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_api_handlers.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_api_protocol.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_array_agg_order_by.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_association_trigger_actor_naming.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_associations.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_associations_wiring.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_bulk_hydration_offload.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_bulk_update_by_pk.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_cache_debug.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_call_function.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_case_when.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_catalog.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_column_scoped_writes.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_committed_row_guard.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_composite_pk_filter.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_composite_pk_write_paths.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_config.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_conflict_target.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_conflict_writes.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_connection_codecs.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_connection_poison_guard.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_connection_primitives.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_count_composite_distinct.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_count_limit_param_leak.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_db_function_field.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_ddl_generator.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_deadlock_retry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_derived_table.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_dirty_tracking.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_dynamic_crud.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_exceptions.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_expression_primitives.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_fields.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_fk_cycle_resolution.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_from_alias.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_fts.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_func_expression_args.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_graph_walk.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_having_annotate_alias.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_introspect_rls_policies.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_join_and_aggregate.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_latest_rows.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_listen_notify.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_local_sqlite.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_lock_contention_retry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_managed_write_guard.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_matrx_entity.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_migration_diff_types.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_migration_loader.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_model_instance.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_model_meta.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_optimistic_concurrency.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_order_by_expression.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_org_assignment_inventory.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_parameter_name_hydration.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_patch_jsonb_path.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_percentile_cont.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_persisted_count.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_pool_create_never_wedges.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_pool_holder_census.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_pool_loop_recreation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_pool_maintenance.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_postgrest_filters.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_pydantic_bridge.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_query_builder.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_query_error_detail.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_query_executor_sql.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_query_timeout.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_queue_claim.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_read_connection_retry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_read_write_declared.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_registry.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_registry_multi_database.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_registry_multi_schema.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_relational_backfill.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_relations.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_resilience.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_rls_session_scope.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_schema_exists.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_session_advisory_lock.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_standalone_write_session_context.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_state_cache.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_subquery_filter_raw.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_subquery_in_filter.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_subquery_nested_expressions.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_supabase_auth.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_supabase_config.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_tls.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_transaction_database_identity.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_transaction_gucs_one_round_trip.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_typed_join_projection.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_typed_predicates.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_update_case_expression.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_update_subquery.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_update_with_rebase.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_upsert_default_leak.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_upsert_with_conflict.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_values_jsonb_decode.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_watched_lifecycle.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_write_queue_deadline.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level1/test_write_retry_semantics.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/MODULE_README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/conftest.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_bulk_ops.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_cache_integration.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_crud.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_foreign_keys.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_m2m.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_manager.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_migrations_live.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_query_execution.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/test_schema_diff.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/live_pooler_role.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/native_source_cases.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/native_source_oracle.rs +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project/.env.example +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project/README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project/generate.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project/generated/.gitkeep +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project/matrx_orm.yaml +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project/test_schema_generation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project_desktop/.env.example +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project_desktop/README.md +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project_desktop/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project_desktop/client_example.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project_desktop/client_example.ts +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project_desktop/client_supabase_example.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/sample_project_desktop/server.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/entity_tests.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_base_generation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_composite_pk_fk_generation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_composite_unique_generation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_dto_identity_generation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_entity_capability_generation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_enum_ordering.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_generate_schema.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_junction_analysis.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_multi_schema_output.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_schema_analysis.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_sql_expression_defaults.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_table_relationships_query.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema/test_view_generation.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema_builder/test_array_default_parsing.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema_builder/test_focused_generation_plan.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema_builder/test_host_models_aggregator.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/schema_builder/test_never_filter_columns.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/__init__.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/conftest.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_cache_no_downgrade.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_capture_poison_proof.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_coalesce.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_dag.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_disk_spill_fallback.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_flush_individual_fallback.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_governed_write.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_live_db_guard_plugin.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_managed.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_op_enqueue_site.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_reads.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_record_error_bounded_insert.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_record_error_storm.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_session.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/session/test_spill_guard_plugin.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_a_read_only_backend_never_refuses_our_writes.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_array_arg_element_type.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_attachment_mutation_serialization.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_backup_alias_conflict.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_backup_history_restore.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_backup_restore_live.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_call_function_as.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_call_function_none_mode.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_database_name_alias.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_db_functions.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_dsn_password_masking.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_dynamic_select_unregistered.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_immutable_insert_or_exact_verify.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_keyed_digest.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_model_cls_refactor.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_native_enable.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_native_lifecycle.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_native_lifecycle_fences.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_native_passkey_receipts.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_native_source.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_no_blocking_asyncpg_tls.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_one_database.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_order_by_desc_nulls_last.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_org_vault_gate.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_pooler_role_guard.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_secret_audit_names_its_organization.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_secrets_battery.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_secrets_minting_keys.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_shared_lock_guard.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_sql_param_casts.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_statement_ceiling_warning.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_sync_twins_guard.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_update_result_truthiness.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_user_visible_lookup.py +0 -0
- {matrx_orm-3.1.201 → matrx_orm-3.1.203}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: matrx-orm
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.203
|
|
4
4
|
Summary: Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching
|
|
5
5
|
Project-URL: Homepage, https://github.com/AI-Matrix-Engine/aidream-current
|
|
6
6
|
Project-URL: Repository, https://github.com/AI-Matrix-Engine/aidream-current
|
|
@@ -26,7 +26,7 @@ Requires-Dist: asyncpg>=0.31.0
|
|
|
26
26
|
Requires-Dist: cbor2<7,>=6.1.3
|
|
27
27
|
Requires-Dist: cryptography>=43.0
|
|
28
28
|
Requires-Dist: gitpython>=3.1.40
|
|
29
|
-
Requires-Dist: matrx-utils>=2.0.
|
|
29
|
+
Requires-Dist: matrx-utils>=2.0.59
|
|
30
30
|
Requires-Dist: psycopg-pool>=3.2.5
|
|
31
31
|
Requires-Dist: psycopg[binary]>=3.2.5
|
|
32
32
|
Requires-Dist: python-dotenv>=1.0
|
|
@@ -200,11 +200,81 @@ def declared_actor_gucs() -> dict[str, str]:
|
|
|
200
200
|
Empty when nothing declared an actor: the DB resolver then applies its
|
|
201
201
|
documented default (``human`` with an identity present, ``code`` without)
|
|
202
202
|
and logs that it did.
|
|
203
|
+
|
|
204
|
+
The WORKFLOW CHAIN rides the same provider (it is part of "who is writing":
|
|
205
|
+
the store copies it onto every record-changed event's ``actor.chain``), so a
|
|
206
|
+
host that wired this provider stamps run writes with no second wiring.
|
|
203
207
|
"""
|
|
204
208
|
actor = _current_actor.get()
|
|
205
|
-
if actor is None
|
|
206
|
-
|
|
207
|
-
|
|
209
|
+
out = actor.as_gucs() if actor is not None else {}
|
|
210
|
+
chain = _current_chain.get()
|
|
211
|
+
if chain is not None:
|
|
212
|
+
out[WORKFLOW_CHAIN_GUC] = chain.as_json()
|
|
213
|
+
return out
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# ---------------------------------------------------------------------------
|
|
217
|
+
# THE WORKFLOW CHAIN — which workflow run is writing (lane CHAIR-RECORD-CHANGED).
|
|
218
|
+
#
|
|
219
|
+
# A record write made by a workflow run's step carries ``{run_id, root_run, depth}``
|
|
220
|
+
# in the transaction-local GUC ``custom.workflow_chain``; the store's record-changed
|
|
221
|
+
# emitter copies it onto the event (``actor.chain``). A run started BY such an event
|
|
222
|
+
# declares the event's chain one level deeper, so a consumer can cap a chain's depth
|
|
223
|
+
# and see a loop (the same root_run coming back) without reading run history.
|
|
224
|
+
# ---------------------------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
WORKFLOW_CHAIN_GUC = "custom.workflow_chain"
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@dataclass(frozen=True, slots=True)
|
|
230
|
+
class WorkflowChain:
|
|
231
|
+
"""The workflow run writing now, the run that started the chain, and how deep it is."""
|
|
232
|
+
|
|
233
|
+
run_id: str
|
|
234
|
+
root_run: str
|
|
235
|
+
depth: int = 1
|
|
236
|
+
|
|
237
|
+
def as_json(self) -> str:
|
|
238
|
+
import json
|
|
239
|
+
|
|
240
|
+
return json.dumps(
|
|
241
|
+
{"run_id": self.run_id, "root_run": self.root_run, "depth": self.depth},
|
|
242
|
+
separators=(",", ":"),
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def workflow_chain_for_run(run_id: str, caused_by: Mapping[str, Any] | None = None) -> WorkflowChain:
|
|
247
|
+
"""The chain a run declares: one level below the change that started it, else a new root."""
|
|
248
|
+
if caused_by:
|
|
249
|
+
root = str(caused_by.get("root_run") or caused_by.get("run_id") or run_id)
|
|
250
|
+
try:
|
|
251
|
+
depth = int(caused_by.get("depth") or 0) + 1
|
|
252
|
+
except (TypeError, ValueError):
|
|
253
|
+
depth = 1
|
|
254
|
+
return WorkflowChain(run_id=str(run_id), root_run=root, depth=depth)
|
|
255
|
+
return WorkflowChain(run_id=str(run_id), root_run=str(run_id), depth=1)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
_current_chain: ContextVar[WorkflowChain | None] = ContextVar("_workflow_chain", default=None)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def current_workflow_chain() -> WorkflowChain | None:
|
|
262
|
+
"""The workflow chain declared by the innermost open declaration, if any."""
|
|
263
|
+
return _current_chain.get()
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@contextmanager
|
|
267
|
+
def declaring_workflow_chain(chain: WorkflowChain | None) -> Iterator[WorkflowChain | None]:
|
|
268
|
+
"""Every transaction opened inside this block stamps its writes with ``chain``.
|
|
269
|
+
|
|
270
|
+
A ContextVar, like the actor: tasks spawned inside the block inherit it, work
|
|
271
|
+
running beside it does not. ``None`` clears an outer declaration for the block.
|
|
272
|
+
"""
|
|
273
|
+
token = _current_chain.set(chain)
|
|
274
|
+
try:
|
|
275
|
+
yield chain
|
|
276
|
+
finally:
|
|
277
|
+
_current_chain.reset(token)
|
|
208
278
|
|
|
209
279
|
|
|
210
280
|
def _validated_actor(tier: str, system: str, agent: str | None, *, caller: str) -> ActorRef:
|
|
@@ -279,6 +349,11 @@ async def declared_actor(
|
|
|
279
349
|
|
|
280
350
|
|
|
281
351
|
__all__ = [
|
|
352
|
+
"WORKFLOW_CHAIN_GUC",
|
|
353
|
+
"WorkflowChain",
|
|
354
|
+
"current_workflow_chain",
|
|
355
|
+
"declaring_workflow_chain",
|
|
356
|
+
"workflow_chain_for_run",
|
|
282
357
|
"ACTOR_AGENT_GUC",
|
|
283
358
|
"ACTOR_SYSTEM_GUC",
|
|
284
359
|
"ACTOR_TIER_GUC",
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"""Session-wide door: a pytest process never opens a connection to PRODUCTION (lane ONE-HOME, 2026-10-02).
|
|
2
|
+
|
|
3
|
+
Registered as a ``pytest11`` entry point (``matrx_production_door``), so pytest loads it in every suite
|
|
4
|
+
regardless of rootdir — the same mechanism as this package's spill, lock and live-db guards; the aidream
|
|
5
|
+
root ``conftest.py`` also registers it when the entry point is missing (stale install metadata). This is the
|
|
6
|
+
NINTH cross-suite hazard; the others are catalogued in the aidream repo-root ``conftest.py``.
|
|
7
|
+
|
|
8
|
+
WHY A DRIVER-LEVEL DOOR. A static census of test sources cannot win: a production ref split in two and
|
|
9
|
+
concatenated, a DSN read from JSON or a dotenv file, libpq's own ``PG*`` environment behind a no-argument
|
|
10
|
+
``connect()``, asyncpg keyword arguments, sqlalchemy URLs, SQL read from a file, writing functions called
|
|
11
|
+
through ``select``, aliased imports and ``psql`` in a subprocess all slip past every pattern. Every one of them
|
|
12
|
+
reaches a driver. So the driver is the door: at CONNECT time the effective host, user and database — the DSN
|
|
13
|
+
text, the keyword arguments and libpq's environment defaults merged the way libpq merges them — are compared
|
|
14
|
+
with production's identity (ref ``brsgrqvjdzwihsvnfqkf`` in the pooler user or host, or
|
|
15
|
+
``db.matrxserver.com``), and a production connection is refused by name.
|
|
16
|
+
|
|
17
|
+
WHAT IS WRAPPED: ``psycopg.Connection.connect`` / ``psycopg.AsyncConnection.connect`` (so ``psycopg.connect``
|
|
18
|
+
and every ``psycopg_pool`` pool), ``psycopg2.connect``, ``asyncpg.connect`` / ``create_pool`` (and the
|
|
19
|
+
``asyncpg.connection.connect`` a pool dials), sqlalchemy ``create_engine`` / ``create_async_engine``,
|
|
20
|
+
``matrx_orm``'s database registration, and ``subprocess.Popen`` of ``psql``. A module imported after this
|
|
21
|
+
plugin loads is patched on import.
|
|
22
|
+
|
|
23
|
+
THE ONE EXCEPTION: ``db.pooled_read.read_only("production")`` opens its connection inside
|
|
24
|
+
:func:`production_read_only` and then runs ``begin read only`` before handing out a cursor, so a production
|
|
25
|
+
read in a test is a transaction that cannot write. Nothing else — no flag, no environment variable — opens
|
|
26
|
+
this door. Not covered: a libpq service file or ``~/.pgpass`` host that the environment does not name.
|
|
27
|
+
|
|
28
|
+
Guard: ``aidream/tests/test_tests_never_write_production.py`` (plants per bypass class).
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import contextvars
|
|
34
|
+
import importlib.abc
|
|
35
|
+
import importlib.util
|
|
36
|
+
import os
|
|
37
|
+
import subprocess
|
|
38
|
+
import sys
|
|
39
|
+
from collections.abc import Iterator
|
|
40
|
+
from contextlib import contextmanager
|
|
41
|
+
from typing import Any
|
|
42
|
+
from urllib.parse import parse_qs, unquote, urlsplit
|
|
43
|
+
|
|
44
|
+
PRODUCTION_REF = "brsgrqvjdzwihsvnfqkf"
|
|
45
|
+
PRODUCTION_MARKERS = (PRODUCTION_REF, "db.matrxserver.com")
|
|
46
|
+
#: libpq's environment defaults, by the connection parameter each one supplies.
|
|
47
|
+
LIBPQ_ENV = {"host": "PGHOST", "hostaddr": "PGHOSTADDR", "user": "PGUSER", "dbname": "PGDATABASE", "service": "PGSERVICE"}
|
|
48
|
+
|
|
49
|
+
_READ_ONLY_PRODUCTION: contextvars.ContextVar[bool] = contextvars.ContextVar("production_read_only", default=False)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ProductionDoorRefusal(RuntimeError):
|
|
53
|
+
"""A connection opened under pytest named the production database."""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@contextmanager
|
|
57
|
+
def production_read_only() -> Iterator[None]:
|
|
58
|
+
"""Open ONE production connection that the caller turns into ``begin read only`` before any statement."""
|
|
59
|
+
token = _READ_ONLY_PRODUCTION.set(True)
|
|
60
|
+
try:
|
|
61
|
+
yield
|
|
62
|
+
finally:
|
|
63
|
+
_READ_ONLY_PRODUCTION.reset(token)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _parse_dsn(text: str) -> dict[str, str]:
|
|
67
|
+
"""Connection parameters from a URL (any ``scheme://``) or a libpq ``key=value`` string."""
|
|
68
|
+
text = (text or "").strip()
|
|
69
|
+
if not text:
|
|
70
|
+
return {}
|
|
71
|
+
if "://" in text:
|
|
72
|
+
try:
|
|
73
|
+
u = urlsplit(text)
|
|
74
|
+
out = {"host": u.hostname or "", "user": unquote(u.username or ""), "dbname": (u.path or "").lstrip("/")}
|
|
75
|
+
for k, v in parse_qs(u.query).items():
|
|
76
|
+
out[k] = v[0]
|
|
77
|
+
return {k: v for k, v in out.items() if v}
|
|
78
|
+
except ValueError:
|
|
79
|
+
return {}
|
|
80
|
+
out: dict[str, str] = {}
|
|
81
|
+
for part in text.split():
|
|
82
|
+
k, sep, v = part.partition("=")
|
|
83
|
+
if sep:
|
|
84
|
+
out[k.strip()] = v.strip().strip("'\"")
|
|
85
|
+
return out
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def effective_identity(dsn: Any = None, **kwargs: Any) -> dict[str, str]:
|
|
89
|
+
"""What libpq would connect to: environment defaults, overlaid by the DSN, overlaid by keyword arguments."""
|
|
90
|
+
params = {k: os.environ[v] for k, v in LIBPQ_ENV.items() if os.environ.get(v)}
|
|
91
|
+
params.update(_parse_dsn(str(dsn)) if dsn else {})
|
|
92
|
+
for k in ("host", "hostaddr", "user", "dbname", "database", "service"):
|
|
93
|
+
if kwargs.get(k):
|
|
94
|
+
params["dbname" if k == "database" else k] = str(kwargs[k])
|
|
95
|
+
return params
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def names_production(dsn: Any = None, **kwargs: Any) -> str | None:
|
|
99
|
+
"""The production marker this connection carries (in the DSN text or its effective identity), else None."""
|
|
100
|
+
texts = [str(dsn or "")] + list(effective_identity(dsn, **kwargs).values())
|
|
101
|
+
blob = " ".join(texts).lower()
|
|
102
|
+
return next((m for m in PRODUCTION_MARKERS if m in blob), None)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def check(what: str, dsn: Any = None, **kwargs: Any) -> None:
|
|
106
|
+
"""Refuse a production connection unless it is the read-only one :func:`production_read_only` opens."""
|
|
107
|
+
if _READ_ONLY_PRODUCTION.get():
|
|
108
|
+
return
|
|
109
|
+
marker = names_production(dsn, **kwargs)
|
|
110
|
+
if marker:
|
|
111
|
+
raise ProductionDoorRefusal(
|
|
112
|
+
f"refused under pytest: {what} reaches the PRODUCTION database ({marker}). Tests never write "
|
|
113
|
+
"production — open the nightly clone (db.pooled_read.clone_writer_dsn()); a read-only production "
|
|
114
|
+
"check goes through db.pooled_read.read_only('production')."
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# ── the wrappers ─────────────────────────────────────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _patch_psycopg(mod: Any) -> None:
|
|
122
|
+
for cls_name in ("Connection", "AsyncConnection"):
|
|
123
|
+
cls = getattr(mod, cls_name, None)
|
|
124
|
+
if cls is None or getattr(cls.connect, "_production_door", False):
|
|
125
|
+
continue
|
|
126
|
+
original = cls.__dict__["connect"].__func__
|
|
127
|
+
if cls_name == "Connection":
|
|
128
|
+
|
|
129
|
+
def connect(cls: Any, conninfo: str = "", _o: Any = original, **kw: Any) -> Any:
|
|
130
|
+
check("psycopg.connect", conninfo, **kw)
|
|
131
|
+
return _o(cls, conninfo, **kw)
|
|
132
|
+
else:
|
|
133
|
+
|
|
134
|
+
async def connect(cls: Any, conninfo: str = "", _o: Any = original, **kw: Any) -> Any: # type: ignore[misc]
|
|
135
|
+
check("psycopg.AsyncConnection.connect", conninfo, **kw)
|
|
136
|
+
return await _o(cls, conninfo, **kw)
|
|
137
|
+
|
|
138
|
+
connect._production_door = True # type: ignore[attr-defined]
|
|
139
|
+
cls.connect = classmethod(connect)
|
|
140
|
+
mod.connect = mod.Connection.connect
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _patch_psycopg2(mod: Any) -> None:
|
|
144
|
+
original = mod.connect
|
|
145
|
+
if getattr(original, "_production_door", False):
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
def connect(dsn: Any = None, connection_factory: Any = None, cursor_factory: Any = None, **kw: Any) -> Any:
|
|
149
|
+
check("psycopg2.connect", dsn, **kw)
|
|
150
|
+
return original(dsn, connection_factory, cursor_factory, **kw)
|
|
151
|
+
|
|
152
|
+
connect._production_door = True # type: ignore[attr-defined]
|
|
153
|
+
mod.connect = connect
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _patch_asyncpg(mod: Any) -> None:
|
|
157
|
+
import asyncpg.connection as connection_mod
|
|
158
|
+
import asyncpg.pool as pool_mod
|
|
159
|
+
|
|
160
|
+
original = connection_mod.connect
|
|
161
|
+
if getattr(original, "_production_door", False):
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
async def connect(dsn: Any = None, *args: Any, **kw: Any) -> Any:
|
|
165
|
+
check("asyncpg.connect", dsn, **kw)
|
|
166
|
+
return await original(dsn, *args, **kw)
|
|
167
|
+
|
|
168
|
+
original_pool = pool_mod.create_pool
|
|
169
|
+
|
|
170
|
+
def create_pool(dsn: Any = None, *args: Any, **kw: Any) -> Any:
|
|
171
|
+
check("asyncpg.create_pool", dsn, **kw)
|
|
172
|
+
return original_pool(dsn, *args, **kw)
|
|
173
|
+
|
|
174
|
+
connect._production_door = True # type: ignore[attr-defined]
|
|
175
|
+
create_pool._production_door = True # type: ignore[attr-defined]
|
|
176
|
+
connection_mod.connect = connect
|
|
177
|
+
mod.connect = connect
|
|
178
|
+
pool_mod.create_pool = create_pool
|
|
179
|
+
mod.create_pool = create_pool
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _patch_sqlalchemy(mod: Any) -> None:
|
|
183
|
+
import sqlalchemy.engine as engine_mod
|
|
184
|
+
|
|
185
|
+
original = engine_mod.create_engine
|
|
186
|
+
if getattr(original, "_production_door", False):
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
def create_engine(url: Any, *args: Any, **kw: Any) -> Any:
|
|
190
|
+
check("sqlalchemy.create_engine", _render_url(url))
|
|
191
|
+
return original(url, *args, **kw)
|
|
192
|
+
|
|
193
|
+
create_engine._production_door = True # type: ignore[attr-defined]
|
|
194
|
+
engine_mod.create_engine = create_engine
|
|
195
|
+
mod.create_engine = create_engine
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _patch_sqlalchemy_asyncio(mod: Any) -> None:
|
|
199
|
+
original = mod.create_async_engine
|
|
200
|
+
if getattr(original, "_production_door", False):
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
def create_async_engine(url: Any, *args: Any, **kw: Any) -> Any:
|
|
204
|
+
check("sqlalchemy.create_async_engine", _render_url(url))
|
|
205
|
+
return original(url, *args, **kw)
|
|
206
|
+
|
|
207
|
+
create_async_engine._production_door = True # type: ignore[attr-defined]
|
|
208
|
+
mod.create_async_engine = create_async_engine
|
|
209
|
+
engine = sys.modules.get("sqlalchemy.ext.asyncio.engine")
|
|
210
|
+
if engine is not None:
|
|
211
|
+
engine.create_async_engine = create_async_engine
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _patch_psycopg_pool(mod: Any) -> None:
|
|
215
|
+
# A pool's worker swallows a connect error into retries; refuse at construction so the refusal is said.
|
|
216
|
+
for cls_name in ("ConnectionPool", "AsyncConnectionPool", "NullConnectionPool", "AsyncNullConnectionPool"):
|
|
217
|
+
cls = getattr(mod, cls_name, None)
|
|
218
|
+
if cls is None or getattr(cls.__init__, "_production_door", False):
|
|
219
|
+
continue
|
|
220
|
+
original = cls.__init__
|
|
221
|
+
|
|
222
|
+
def __init__(self: Any, conninfo: str = "", *a: Any, _o: Any = original, _n: str = cls_name, **kw: Any) -> None:
|
|
223
|
+
check(f"psycopg_pool.{_n}", conninfo, **(kw.get("kwargs") or {}))
|
|
224
|
+
_o(self, conninfo, *a, **kw)
|
|
225
|
+
|
|
226
|
+
__init__._production_door = True # type: ignore[attr-defined]
|
|
227
|
+
cls.__init__ = __init__
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _render_url(url: Any) -> str:
|
|
231
|
+
render = getattr(url, "render_as_string", None)
|
|
232
|
+
return render(hide_password=True) if callable(render) else str(url)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _patch_orm_registry(mod: Any) -> None:
|
|
236
|
+
registry_cls = getattr(mod, "DatabaseRegistry", None) or type(getattr(mod, "_registry", None) or object())
|
|
237
|
+
original = getattr(registry_cls, "register", None)
|
|
238
|
+
if original is None or getattr(original, "_production_door", False):
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
def register(self: Any, config: Any) -> None:
|
|
242
|
+
check(
|
|
243
|
+
f"matrx_orm database registration {getattr(config, 'name', '?')!r}",
|
|
244
|
+
None,
|
|
245
|
+
host=getattr(config, "host", None),
|
|
246
|
+
user=getattr(config, "user", None),
|
|
247
|
+
dbname=getattr(config, "database_name", None),
|
|
248
|
+
)
|
|
249
|
+
return original(self, config)
|
|
250
|
+
|
|
251
|
+
register._production_door = True # type: ignore[attr-defined]
|
|
252
|
+
registry_cls.register = register
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _psql_argv(args: Any, shell: bool) -> list[str] | None:
|
|
256
|
+
"""The command line as words when it runs ``psql`` (directly or inside a shell string), else None."""
|
|
257
|
+
words = args.split() if isinstance(args, str | bytes) else [str(a) for a in args] if args else []
|
|
258
|
+
words = [w.decode() if isinstance(w, bytes) else w for w in words]
|
|
259
|
+
if any(os.path.basename(w) == "psql" for w in words):
|
|
260
|
+
return words
|
|
261
|
+
return None
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _patch_subprocess() -> None:
|
|
265
|
+
original = subprocess.Popen.__init__
|
|
266
|
+
if getattr(original, "_production_door", False):
|
|
267
|
+
return
|
|
268
|
+
|
|
269
|
+
def __init__(self: Any, args: Any, *a: Any, **kw: Any) -> None:
|
|
270
|
+
words = _psql_argv(args, bool(kw.get("shell")))
|
|
271
|
+
if words is not None:
|
|
272
|
+
env = kw.get("env")
|
|
273
|
+
saved = dict(os.environ)
|
|
274
|
+
try:
|
|
275
|
+
if env is not None: # psql sees the child's environment, not ours
|
|
276
|
+
os.environ.clear()
|
|
277
|
+
os.environ.update({str(k): str(v) for k, v in env.items()})
|
|
278
|
+
flags = {"-h": "host", "--host": "host", "-U": "user", "--username": "user", "-d": "dbname", "--dbname": "dbname"}
|
|
279
|
+
kwargs = {flags[w]: words[i + 1] for i, w in enumerate(words[:-1]) if w in flags}
|
|
280
|
+
check("psql (subprocess)", " ".join(words), **kwargs)
|
|
281
|
+
finally:
|
|
282
|
+
if env is not None:
|
|
283
|
+
os.environ.clear()
|
|
284
|
+
os.environ.update(saved)
|
|
285
|
+
original(self, args, *a, **kw)
|
|
286
|
+
|
|
287
|
+
__init__._production_door = True # type: ignore[attr-defined]
|
|
288
|
+
subprocess.Popen.__init__ = __init__ # type: ignore[method-assign]
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
_PATCHERS = {
|
|
292
|
+
"psycopg": _patch_psycopg,
|
|
293
|
+
"psycopg_pool": _patch_psycopg_pool,
|
|
294
|
+
"psycopg2": _patch_psycopg2,
|
|
295
|
+
"asyncpg": _patch_asyncpg,
|
|
296
|
+
"sqlalchemy": _patch_sqlalchemy,
|
|
297
|
+
"sqlalchemy.ext.asyncio": _patch_sqlalchemy_asyncio,
|
|
298
|
+
"matrx_orm.core.config": _patch_orm_registry,
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
class _PatchOnImport(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
|
303
|
+
"""Patch a driver the moment it is first imported (for drivers this plugin did not import itself)."""
|
|
304
|
+
|
|
305
|
+
def find_spec(self, fullname: str, path: Any, target: Any = None) -> Any:
|
|
306
|
+
if fullname not in _PATCHERS or fullname in sys.modules:
|
|
307
|
+
return None
|
|
308
|
+
sys.meta_path.remove(self)
|
|
309
|
+
try:
|
|
310
|
+
spec = importlib.util.find_spec(fullname)
|
|
311
|
+
finally:
|
|
312
|
+
sys.meta_path.insert(0, self)
|
|
313
|
+
if spec is None or spec.loader is None:
|
|
314
|
+
return None
|
|
315
|
+
loader = spec.loader
|
|
316
|
+
|
|
317
|
+
class _Loader(importlib.abc.Loader):
|
|
318
|
+
def create_module(self, s: Any) -> Any:
|
|
319
|
+
return loader.create_module(s)
|
|
320
|
+
|
|
321
|
+
def exec_module(self, module: Any) -> None:
|
|
322
|
+
loader.exec_module(module)
|
|
323
|
+
_PATCHERS[fullname](module)
|
|
324
|
+
|
|
325
|
+
spec.loader = _Loader()
|
|
326
|
+
return spec
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def install() -> None:
|
|
330
|
+
"""Wrap every driver already imported, and every one imported later. Idempotent."""
|
|
331
|
+
_patch_subprocess()
|
|
332
|
+
for name, patch in _PATCHERS.items():
|
|
333
|
+
if name in sys.modules:
|
|
334
|
+
patch(sys.modules[name])
|
|
335
|
+
if not any(isinstance(f, _PatchOnImport) for f in sys.meta_path):
|
|
336
|
+
sys.meta_path.insert(0, _PatchOnImport())
|
|
337
|
+
for name in ("psycopg", "asyncpg"): # the two drivers every suite has: patch them now
|
|
338
|
+
try:
|
|
339
|
+
importlib.import_module(name)
|
|
340
|
+
except ImportError:
|
|
341
|
+
pass
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
# ── pytest hooks: install before any conftest or test module is imported ─────────────────────────────
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def pytest_load_initial_conftests(early_config: Any, parser: Any, args: Any) -> None:
|
|
349
|
+
install()
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def pytest_configure(config: Any) -> None:
|
|
353
|
+
install() # idempotent: covers a registration through the root conftest's fallback
|
|
@@ -725,6 +725,7 @@ def preview_schema_changes(
|
|
|
725
725
|
from matrx_orm.core.config import register_database_from_env
|
|
726
726
|
from matrx_orm.schema_builder.common import DEBUG_CONFIG, OutputConfig
|
|
727
727
|
from matrx_orm.schema_builder.schema import entry_manager_flags
|
|
728
|
+
from matrx_orm.schema_builder.excluded_targets import excluded_targets, modeled_schemas
|
|
728
729
|
from matrx_orm.schema_builder.schema_manager import SchemaManager
|
|
729
730
|
|
|
730
731
|
caller_dir = Path(sys.argv[0]).parent.resolve()
|
|
@@ -804,6 +805,12 @@ def preview_schema_changes(
|
|
|
804
805
|
include_tables=include_tables,
|
|
805
806
|
exclude_tables=exclude_tables,
|
|
806
807
|
manager_flags=manager_flags,
|
|
808
|
+
excluded_fk_targets=excluded_targets(cfg.get("generate", []), db_name),
|
|
809
|
+
modeled_schemas=modeled_schemas(
|
|
810
|
+
cfg.get("generate", []),
|
|
811
|
+
db_name,
|
|
812
|
+
next((d.get("additional_schemas") or [] for d in cfg.get("databases", []) if d.get("name") == db_name), []),
|
|
813
|
+
),
|
|
807
814
|
)
|
|
808
815
|
manager.initialize()
|
|
809
816
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""A table excluded from generation is excluded as a REFERENCE target too.
|
|
2
|
+
|
|
3
|
+
``exclude_tables`` under a schema's ``generate[]`` entry keeps that table's model out of the
|
|
4
|
+
schema's file. A table in ANOTHER schema (or the same one) whose foreign key points at it would
|
|
5
|
+
still emit ``ForeignKey(to_model='<Excluded>')`` and a ``get_*_with_related('<schema>.<table>')``
|
|
6
|
+
manager method — a lazy reference that resolves to nothing at runtime and a relation that reads a
|
|
7
|
+
table the host chose not to model. So every reference to an excluded table is dropped at load:
|
|
8
|
+
the column generates as its plain type, and the relation (both directions) is not emitted.
|
|
9
|
+
|
|
10
|
+
The excluded set is qualified (``schema.table``) and spans every ``generate[]`` entry of the same
|
|
11
|
+
database, because the referencing table usually lives in another schema's run.
|
|
12
|
+
|
|
13
|
+
The same holds for a table in a schema the host never models: a foreign key follows its table's
|
|
14
|
+
oid, so once a retired table moves to ``graveyard`` every reference to it reads
|
|
15
|
+
``to_schema='graveyard'`` — a class the registry can never hold. A reference whose target schema
|
|
16
|
+
is neither generated nor one of the database's ``additional_schemas`` is dropped the same way.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from collections.abc import Iterable
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def excluded_targets(generate_list: Iterable[dict[str, Any]], database: str) -> frozenset[str]:
|
|
26
|
+
"""Every ``schema.table`` an ``exclude_tables`` list names for ``database``."""
|
|
27
|
+
out: set[str] = set()
|
|
28
|
+
for entry in generate_list:
|
|
29
|
+
if entry.get("database") != database:
|
|
30
|
+
continue
|
|
31
|
+
schema = entry.get("schema") or "public"
|
|
32
|
+
for table in entry.get("exclude_tables") or ():
|
|
33
|
+
out.add(f"{schema}.{table}")
|
|
34
|
+
return frozenset(out)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def modeled_schemas(
|
|
38
|
+
generate_list: Iterable[dict[str, Any]], database: str, additional_schemas: Iterable[str] = ()
|
|
39
|
+
) -> frozenset[str]:
|
|
40
|
+
"""Every schema the host models for ``database``: the generated ones and its additional schemas."""
|
|
41
|
+
out = {"public", *additional_schemas}
|
|
42
|
+
out.update(e.get("schema") or "public" for e in generate_list if e.get("database") == database)
|
|
43
|
+
return frozenset(out)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def drop_references_to(
|
|
47
|
+
excluded: frozenset[str] | set[str],
|
|
48
|
+
*,
|
|
49
|
+
schema: str,
|
|
50
|
+
processed_objects: list[dict[str, Any]],
|
|
51
|
+
full_relationships: list[dict[str, Any]],
|
|
52
|
+
modeled: frozenset[str] | set[str] | None = None,
|
|
53
|
+
) -> list[str]:
|
|
54
|
+
"""Remove every reference to an excluded table, or into a schema outside ``modeled``, in place.
|
|
55
|
+
|
|
56
|
+
Returns what was dropped, for the log. ``modeled=None`` keeps every schema.
|
|
57
|
+
"""
|
|
58
|
+
if not excluded and modeled is None:
|
|
59
|
+
return []
|
|
60
|
+
|
|
61
|
+
def gone(target_schema: str, table: str) -> bool:
|
|
62
|
+
return f"{target_schema}.{table}" in excluded or (modeled is not None and target_schema not in modeled)
|
|
63
|
+
|
|
64
|
+
dropped: list[str] = []
|
|
65
|
+
for obj in processed_objects:
|
|
66
|
+
for column in obj.get("table_columns") or ():
|
|
67
|
+
fk = column.get("foreign_key_reference")
|
|
68
|
+
if not isinstance(fk, dict) or not fk.get("table"):
|
|
69
|
+
continue
|
|
70
|
+
target_schema = fk.get("schema") or "public"
|
|
71
|
+
if gone(target_schema, fk["table"]):
|
|
72
|
+
column["foreign_key_reference"] = None
|
|
73
|
+
dropped.append(
|
|
74
|
+
f"{obj.get('schema')}.{obj.get('name')}.{column.get('name')} -> {target_schema}.{fk['table']}"
|
|
75
|
+
)
|
|
76
|
+
for rel in full_relationships:
|
|
77
|
+
fks = rel.get("foreign_keys")
|
|
78
|
+
if isinstance(fks, dict):
|
|
79
|
+
for key in [
|
|
80
|
+
k
|
|
81
|
+
for k, v in fks.items()
|
|
82
|
+
if isinstance(v, dict) and gone(v.get("foreign_schema") or schema, v.get("foreign_table") or k)
|
|
83
|
+
]:
|
|
84
|
+
fks.pop(key)
|
|
85
|
+
refs = rel.get("referenced_by")
|
|
86
|
+
if isinstance(refs, dict):
|
|
87
|
+
# Keys of referenced_by are always tables of THIS schema (bare names).
|
|
88
|
+
for key in [k for k in refs if f"{schema}.{k}" in excluded]:
|
|
89
|
+
refs.pop(key)
|
|
90
|
+
return dropped
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
__all__ = ["drop_references_to", "excluded_targets", "modeled_schemas"]
|
|
@@ -19,6 +19,7 @@ from dotenv import load_dotenv
|
|
|
19
19
|
from matrx_utils import vcprint
|
|
20
20
|
|
|
21
21
|
from matrx_orm.core.config import DatabaseConfigError, register_database_from_env
|
|
22
|
+
from matrx_orm.schema_builder.excluded_targets import excluded_targets, modeled_schemas
|
|
22
23
|
from matrx_orm.schema_builder.common import (
|
|
23
24
|
DEBUG_CONFIG,
|
|
24
25
|
GenerationOutputOverrides,
|
|
@@ -386,6 +387,12 @@ def run_schema_generation(
|
|
|
386
387
|
output_config=output_config,
|
|
387
388
|
include_tables=include_tables,
|
|
388
389
|
exclude_tables=exclude_tables,
|
|
390
|
+
excluded_fk_targets=excluded_targets(cfg.get("generate", []), db_name),
|
|
391
|
+
modeled_schemas=modeled_schemas(
|
|
392
|
+
cfg.get("generate", []),
|
|
393
|
+
db_name,
|
|
394
|
+
next((d.get("additional_schemas") or [] for d in cfg.get("databases", []) if d.get("name") == db_name), []),
|
|
395
|
+
),
|
|
389
396
|
manager_flags=manager_flags,
|
|
390
397
|
skip_unchanged_managers=skip_unchanged_managers,
|
|
391
398
|
output_overrides=output_overrides,
|
|
@@ -39,6 +39,8 @@ class SchemaManager:
|
|
|
39
39
|
manager_flags: dict | None = None,
|
|
40
40
|
skip_unchanged_managers: bool = False,
|
|
41
41
|
output_overrides: GenerationOutputOverrides | None = None,
|
|
42
|
+
excluded_fk_targets: frozenset[str] | set[str] | None = None,
|
|
43
|
+
modeled_schemas: frozenset[str] | set[str] | None = None,
|
|
42
44
|
):
|
|
43
45
|
if additional_schemas is None:
|
|
44
46
|
# Read from the registered database config if a project name is provided;
|
|
@@ -93,6 +95,13 @@ class SchemaManager:
|
|
|
93
95
|
self._exclude_tables: set[str] | None = (
|
|
94
96
|
set(exclude_tables) if exclude_tables is not None else None
|
|
95
97
|
)
|
|
98
|
+
#: ``schema.table`` names excluded from generation in ANY generate[] entry of this database:
|
|
99
|
+
#: a reference to one is dropped at load (``excluded_targets.drop_references_to``).
|
|
100
|
+
self._excluded_fk_targets: frozenset[str] = frozenset(excluded_fk_targets or ())
|
|
101
|
+
#: Schemas the host models; a reference into any other (``graveyard``) is dropped the same way.
|
|
102
|
+
self._modeled_schemas: frozenset[str] | None = (
|
|
103
|
+
frozenset(modeled_schemas) if modeled_schemas is not None else None
|
|
104
|
+
)
|
|
96
105
|
|
|
97
106
|
vcprint(
|
|
98
107
|
self.schema, title="SCHEMA MANAGER] with schema", verbose=self.verbose, color="blue"
|
|
@@ -160,6 +169,23 @@ class SchemaManager:
|
|
|
160
169
|
self.overview_analysis,
|
|
161
170
|
) = get_db_objects(self.schema.name, self.database_project)
|
|
162
171
|
|
|
172
|
+
if self._excluded_fk_targets or self._modeled_schemas is not None:
|
|
173
|
+
from matrx_orm.schema_builder.excluded_targets import drop_references_to
|
|
174
|
+
|
|
175
|
+
dropped = drop_references_to(
|
|
176
|
+
self._excluded_fk_targets,
|
|
177
|
+
schema=self.schema.name or "public",
|
|
178
|
+
processed_objects=self.processed_objects,
|
|
179
|
+
full_relationships=self.full_relationships,
|
|
180
|
+
modeled=self._modeled_schemas,
|
|
181
|
+
)
|
|
182
|
+
if dropped:
|
|
183
|
+
vcprint(
|
|
184
|
+
f"[MATRX ORM] {len(dropped)} reference(s) to an excluded or unmodeled table generate as plain "
|
|
185
|
+
f"columns: {', '.join(dropped)}",
|
|
186
|
+
color="yellow",
|
|
187
|
+
)
|
|
188
|
+
|
|
163
189
|
# NOTE: no filtering here — all relationship/overview data loads in full so
|
|
164
190
|
# that topological sort, FK resolution, and relationship analysis are always
|
|
165
191
|
# correct. The filter is applied in Schema.generate_models() just before
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "matrx-orm"
|
|
3
|
-
version = "3.1.
|
|
3
|
+
version = "3.1.203"
|
|
4
4
|
description = "Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -41,7 +41,7 @@ dependencies = [
|
|
|
41
41
|
"gitpython>=3.1.40",
|
|
42
42
|
"psycopg[binary]>=3.2.5",
|
|
43
43
|
"psycopg-pool>=3.2.5",
|
|
44
|
-
"matrx-utils>=2.0.
|
|
44
|
+
"matrx-utils>=2.0.59",
|
|
45
45
|
"pyyaml>=6.0.3",
|
|
46
46
|
"python-dotenv>=1.0",
|
|
47
47
|
"cryptography>=43.0",
|
|
@@ -52,6 +52,7 @@ dependencies = [
|
|
|
52
52
|
matrx_write_spill_guard = "matrx_orm.pytest_plugin"
|
|
53
53
|
matrx_shared_lock_guard = "matrx_orm.pytest_lock_guard"
|
|
54
54
|
matrx_live_db_guard = "matrx_orm.pytest_live_db_guard"
|
|
55
|
+
matrx_production_door = "matrx_orm.pytest_production_door"
|
|
55
56
|
|
|
56
57
|
[project.urls]
|
|
57
58
|
Homepage = "https://github.com/AI-Matrix-Engine/aidream-current"
|