python-ddd-framework 0.3.1__py3-none-any.whl
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.
- python_ddd_framework/__init__.py +449 -0
- python_ddd_framework/application/__init__.py +6 -0
- python_ddd_framework/application/build_spec.py +37 -0
- python_ddd_framework/application/builder.py +260 -0
- python_ddd_framework/application/composition.py +219 -0
- python_ddd_framework/application/runtime.py +549 -0
- python_ddd_framework/application/runtime_hooks.py +327 -0
- python_ddd_framework/application/state.py +216 -0
- python_ddd_framework/application_services/__init__.py +54 -0
- python_ddd_framework/application_services/catalog.py +500 -0
- python_ddd_framework/application_services/contracts.py +190 -0
- python_ddd_framework/application_services/dispatcher.py +423 -0
- python_ddd_framework/application_services/errors.py +89 -0
- python_ddd_framework/application_services/execution.py +199 -0
- python_ddd_framework/application_services/interceptors.py +44 -0
- python_ddd_framework/application_services/invocation.py +431 -0
- python_ddd_framework/application_services/policies.py +46 -0
- python_ddd_framework/application_services/seeding.py +72 -0
- python_ddd_framework/application_services/signature.py +49 -0
- python_ddd_framework/application_services/validation.py +84 -0
- python_ddd_framework/auditing/__init__.py +12 -0
- python_ddd_framework/auditing/contracts.py +39 -0
- python_ddd_framework/auditing/control.py +48 -0
- python_ddd_framework/auditing/sqlalchemy/__init__.py +6 -0
- python_ddd_framework/auditing/sqlalchemy/migrations/0001_auditing.py +45 -0
- python_ddd_framework/auditing/sqlalchemy/migrations/__init__.py +1 -0
- python_ddd_framework/auditing/sqlalchemy/models.py +31 -0
- python_ddd_framework/auditing/sqlalchemy/module.py +32 -0
- python_ddd_framework/auditing/sqlalchemy/store.py +63 -0
- python_ddd_framework/authorization/__init__.py +38 -0
- python_ddd_framework/authorization/catalog.py +63 -0
- python_ddd_framework/authorization/contracts.py +241 -0
- python_ddd_framework/authorization/definition_discovery.py +81 -0
- python_ddd_framework/authorization/definitions.py +43 -0
- python_ddd_framework/authorization/errors.py +40 -0
- python_ddd_framework/background_execution/__init__.py +17 -0
- python_ddd_framework/background_execution/application.py +41 -0
- python_ddd_framework/background_execution/child.py +123 -0
- python_ddd_framework/background_execution/contracts.py +48 -0
- python_ddd_framework/background_execution/lifecycle.py +22 -0
- python_ddd_framework/background_execution/local.py +127 -0
- python_ddd_framework/background_execution/locks.py +33 -0
- python_ddd_framework/background_execution/management.py +17 -0
- python_ddd_framework/background_execution/module.py +10 -0
- python_ddd_framework/background_execution/permissions.py +14 -0
- python_ddd_framework/background_execution/processes.py +331 -0
- python_ddd_framework/background_jobs/__init__.py +31 -0
- python_ddd_framework/background_jobs/catalog.py +340 -0
- python_ddd_framework/background_jobs/contracts.py +208 -0
- python_ddd_framework/background_jobs/declaration.py +67 -0
- python_ddd_framework/background_jobs/errors.py +28 -0
- python_ddd_framework/background_jobs/execution.py +203 -0
- python_ddd_framework/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt +21 -0
- python_ddd_framework/background_jobs/pgqueuer/__init__.py +6 -0
- python_ddd_framework/background_jobs/pgqueuer/enqueue.py +86 -0
- python_ddd_framework/background_jobs/pgqueuer/migrations/0001_pgqueuer_1_3_2.py +95 -0
- python_ddd_framework/background_jobs/pgqueuer/migrations/__init__.py +1 -0
- python_ddd_framework/background_jobs/pgqueuer/module.py +106 -0
- python_ddd_framework/background_jobs/pgqueuer/options.py +82 -0
- python_ddd_framework/background_jobs/pgqueuer/runtime.py +479 -0
- python_ddd_framework/background_jobs/pgqueuer/sql/pgqueuer_1_3_2_install.sql +118 -0
- python_ddd_framework/background_jobs/pgqueuer/supervision.py +201 -0
- python_ddd_framework/background_workers/__init__.py +22 -0
- python_ddd_framework/background_workers/catalog.py +118 -0
- python_ddd_framework/background_workers/contracts.py +152 -0
- python_ddd_framework/background_workers/errors.py +20 -0
- python_ddd_framework/background_workers/execution.py +133 -0
- python_ddd_framework/background_workers/runtime.py +219 -0
- python_ddd_framework/caching/__init__.py +11 -0
- python_ddd_framework/caching/catalog.py +73 -0
- python_ddd_framework/caching/contracts.py +73 -0
- python_ddd_framework/caching/errors.py +20 -0
- python_ddd_framework/cli/__init__.py +105 -0
- python_ddd_framework/cli/development.py +85 -0
- python_ddd_framework/cli/errors.py +5 -0
- python_ddd_framework/cli/inspection.py +96 -0
- python_ddd_framework/cli/project.py +69 -0
- python_ddd_framework/cli/runtime.py +56 -0
- python_ddd_framework/configuration/__init__.py +21 -0
- python_ddd_framework/configuration/composition.py +65 -0
- python_ddd_framework/configuration/contracts.py +68 -0
- python_ddd_framework/configuration/dotenv_source.py +51 -0
- python_ddd_framework/configuration/environment_source.py +38 -0
- python_ddd_framework/configuration/immutability.py +124 -0
- python_ddd_framework/configuration/input_shape.py +58 -0
- python_ddd_framework/configuration/merge.py +103 -0
- python_ddd_framework/configuration/root.py +215 -0
- python_ddd_framework/configuration/sources.py +519 -0
- python_ddd_framework/configuration/values.py +427 -0
- python_ddd_framework/configuration/yaml_source.py +51 -0
- python_ddd_framework/developer_kit/__init__.py +1 -0
- python_ddd_framework/developer_kit/generation.py +182 -0
- python_ddd_framework/developer_kit/project_metadata.py +45 -0
- python_ddd_framework/developer_kit/source.py +53 -0
- python_ddd_framework/developer_kit/templates/module/cookiecutter.json +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/README.md +70 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/cache.py.jinja +10 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/events.py.jinja +24 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/integration.py.jinja +41 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/module.py.jinja +20 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/options.py.jinja +7 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/orders.py.jinja +83 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/tasks.py.jinja +84 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/module.py.jinja +10 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/orders.py.jinja +35 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/module.py.jinja +10 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/orders.py.jinja +56 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/repository.py.jinja +14 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/seeding.py.jinja +19 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/settings.py.jinja +16 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/definitions.py.jinja +24 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/module.py.jinja +7 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/permissions.py.jinja +15 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/files.py.jinja +73 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/module.py.jinja +25 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/realtime.py.jinja +36 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/migrations/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/models/__init__.py.jinja +7 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/models/orders.py.jinja +25 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/module.py.jinja +26 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/repositories/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/repositories/orders.py.jinja +49 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/tests/test_domain.py.jinja +18 -0
- python_ddd_framework/developer_kit/templates/project/cookiecutter.json +6 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/.dockerignore +9 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/.gitignore +6 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/.python-version +1 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/AGENTS.md +38 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/Dockerfile +22 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/README.md +130 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/app.development.yaml.jinja +30 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/compose.dev.yaml.jinja +24 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/compose.production.yaml.jinja +20 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/docs/architecture.md +84 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/docs/development.md +185 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/pyproject.toml.jinja +28 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/main.py.jinja +47 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/module.py.jinja +37 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/tests/conftest.py.jinja +8 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/tests/host/test_http.py.jinja +57 -0
- python_ddd_framework/developer_kit/wiring.py +162 -0
- python_ddd_framework/diagnostics/__init__.py +23 -0
- python_ddd_framework/diagnostics/journal.py +174 -0
- python_ddd_framework/diagnostics/model.py +83 -0
- python_ddd_framework/diagnostics/source.py +25 -0
- python_ddd_framework/distributed_lock/__init__.py +6 -0
- python_ddd_framework/distributed_lock/contracts.py +20 -0
- python_ddd_framework/distributed_lock/options.py +19 -0
- python_ddd_framework/domain/__init__.py +13 -0
- python_ddd_framework/domain/aggregates.py +64 -0
- python_ddd_framework/domain/entities.py +33 -0
- python_ddd_framework/domain/errors.py +12 -0
- python_ddd_framework/domain/value_objects.py +31 -0
- python_ddd_framework/errors/__init__.py +75 -0
- python_ddd_framework/errors/base.py +13 -0
- python_ddd_framework/errors/business.py +53 -0
- python_ddd_framework/errors/configuration.py +119 -0
- python_ddd_framework/errors/diagnostics.py +12 -0
- python_ddd_framework/errors/lifecycle.py +164 -0
- python_ddd_framework/errors/modularity.py +100 -0
- python_ddd_framework/errors/services.py +100 -0
- python_ddd_framework/events/__init__.py +25 -0
- python_ddd_framework/events/aggregate.py +39 -0
- python_ddd_framework/events/catalog.py +136 -0
- python_ddd_framework/events/contracts.py +39 -0
- python_ddd_framework/events/contribution.py +128 -0
- python_ddd_framework/events/discovery.py +105 -0
- python_ddd_framework/events/errors.py +48 -0
- python_ddd_framework/events/runtime.py +192 -0
- python_ddd_framework/fastapi/__init__.py +49 -0
- python_ddd_framework/fastapi/action.py +175 -0
- python_ddd_framework/fastapi/adapter.py +391 -0
- python_ddd_framework/fastapi/application_services.py +654 -0
- python_ddd_framework/fastapi/background.py +42 -0
- python_ddd_framework/fastapi/contracts.py +275 -0
- python_ddd_framework/fastapi/errors.py +32 -0
- python_ddd_framework/fastapi/filters.py +111 -0
- python_ddd_framework/fastapi/health.py +44 -0
- python_ddd_framework/fastapi/http.py +72 -0
- python_ddd_framework/fastapi/http_router.py +216 -0
- python_ddd_framework/fastapi/manual_action.py +105 -0
- python_ddd_framework/fastapi/middleware.py +93 -0
- python_ddd_framework/fastapi/parameters.py +97 -0
- python_ddd_framework/fastapi/realtime/__init__.py +13 -0
- python_ddd_framework/fastapi/realtime/authentication.py +181 -0
- python_ddd_framework/fastapi/realtime/connection.py +166 -0
- python_ddd_framework/fastapi/realtime/module.py +41 -0
- python_ddd_framework/fastapi/realtime/options.py +50 -0
- python_ddd_framework/fastapi/realtime/runtime.py +423 -0
- python_ddd_framework/fastapi/request_context.py +247 -0
- python_ddd_framework/fastapi/route_integrity.py +88 -0
- python_ddd_framework/fastapi/routing.py +424 -0
- python_ddd_framework/fastapi/server.py +182 -0
- python_ddd_framework/fastapi/settings.py +40 -0
- python_ddd_framework/fastapi/tracing.py +62 -0
- python_ddd_framework/fastapi/transfer.py +128 -0
- python_ddd_framework/fastapi/upload_limits.py +63 -0
- python_ddd_framework/fastapi/uploads.py +94 -0
- python_ddd_framework/hosted_services/__init__.py +29 -0
- python_ddd_framework/hosted_services/bridge.py +420 -0
- python_ddd_framework/hosted_services/catalog.py +265 -0
- python_ddd_framework/hosted_services/contracts.py +55 -0
- python_ddd_framework/hosted_services/errors.py +53 -0
- python_ddd_framework/hosted_services/options.py +17 -0
- python_ddd_framework/hosted_services/runtime.py +267 -0
- python_ddd_framework/hosted_services/state.py +40 -0
- python_ddd_framework/hosting/__init__.py +4 -0
- python_ddd_framework/hosting/instance.py +40 -0
- python_ddd_framework/identity/__init__.py +73 -0
- python_ddd_framework/identity/application.py +287 -0
- python_ddd_framework/identity/contracts.py +283 -0
- python_ddd_framework/identity/errors.py +28 -0
- python_ddd_framework/identity/http_api.py +90 -0
- python_ddd_framework/identity/module.py +49 -0
- python_ddd_framework/identity/passwords.py +34 -0
- python_ddd_framework/identity/permissions.py +14 -0
- python_ddd_framework/identity/services.py +108 -0
- python_ddd_framework/identity/sqlalchemy/__init__.py +5 -0
- python_ddd_framework/identity/sqlalchemy/migrations/0001_identity.py +143 -0
- python_ddd_framework/identity/sqlalchemy/migrations/0002_physical_delete.py +42 -0
- python_ddd_framework/identity/sqlalchemy/migrations/__init__.py +1 -0
- python_ddd_framework/identity/sqlalchemy/models.py +85 -0
- python_ddd_framework/identity/sqlalchemy/module.py +62 -0
- python_ddd_framework/identity/sqlalchemy/stores.py +526 -0
- python_ddd_framework/identity/tokens.py +106 -0
- python_ddd_framework/invocation/__init__.py +3 -0
- python_ddd_framework/invocation/callables.py +171 -0
- python_ddd_framework/invocation/contracts.py +33 -0
- python_ddd_framework/invocation/entries.py +54 -0
- python_ddd_framework/invocation/function_runtime.py +48 -0
- python_ddd_framework/invocation/interception.py +193 -0
- python_ddd_framework/lifecycle/__init__.py +25 -0
- python_ddd_framework/lifecycle/composition.py +35 -0
- python_ddd_framework/lifecycle/context.py +31 -0
- python_ddd_framework/lifecycle/runtime.py +43 -0
- python_ddd_framework/lifecycle/state.py +20 -0
- python_ddd_framework/modularity/__init__.py +15 -0
- python_ddd_framework/modularity/contracts.py +91 -0
- python_ddd_framework/modularity/discovery.py +157 -0
- python_ddd_framework/modularity/graph.py +334 -0
- python_ddd_framework/modularity/registry.py +100 -0
- python_ddd_framework/modularity/selection.py +16 -0
- python_ddd_framework/notifications/__init__.py +19 -0
- python_ddd_framework/notifications/catalog.py +46 -0
- python_ddd_framework/notifications/contracts.py +107 -0
- python_ddd_framework/observability/__init__.py +5 -0
- python_ddd_framework/observability/context.py +43 -0
- python_ddd_framework/observability/export.py +73 -0
- python_ddd_framework/observability/formatting.py +89 -0
- python_ddd_framework/observability/logging.py +118 -0
- python_ddd_framework/observability/options.py +45 -0
- python_ddd_framework/observability/tracing.py +80 -0
- python_ddd_framework/options/__init__.py +19 -0
- python_ddd_framework/options/aliases.py +331 -0
- python_ddd_framework/options/contribution.py +62 -0
- python_ddd_framework/options/immutability.py +48 -0
- python_ddd_framework/options/input_keys.py +214 -0
- python_ddd_framework/options/issues.py +335 -0
- python_ddd_framework/options/models.py +114 -0
- python_ddd_framework/options/registry.py +280 -0
- python_ddd_framework/options/schema.py +488 -0
- python_ddd_framework/options/validation.py +120 -0
- python_ddd_framework/py.typed +0 -0
- python_ddd_framework/realtime/__init__.py +12 -0
- python_ddd_framework/realtime/contracts.py +28 -0
- python_ddd_framework/realtime/diagnostics.py +37 -0
- python_ddd_framework/realtime/messages.py +113 -0
- python_ddd_framework/redis/__init__.py +6 -0
- python_ddd_framework/redis/distributed_lock.py +212 -0
- python_ddd_framework/redis/lease_lock.py +36 -0
- python_ddd_framework/redis/module.py +50 -0
- python_ddd_framework/redis/notification_runtime.py +182 -0
- python_ddd_framework/redis/notifications.py +25 -0
- python_ddd_framework/redis/options.py +35 -0
- python_ddd_framework/redis/runtime.py +116 -0
- python_ddd_framework/services/__init__.py +41 -0
- python_ddd_framework/services/application_bindings.py +221 -0
- python_ddd_framework/services/arbitration.py +381 -0
- python_ddd_framework/services/binding.py +102 -0
- python_ddd_framework/services/contribution.py +438 -0
- python_ddd_framework/services/convention.py +301 -0
- python_ddd_framework/services/convention_contracts.py +101 -0
- python_ddd_framework/services/exposure.py +23 -0
- python_ddd_framework/services/fixed_lifetime.py +52 -0
- python_ddd_framework/services/framework_provider.py +178 -0
- python_ddd_framework/services/native_graph.py +201 -0
- python_ddd_framework/services/provider.py +204 -0
- python_ddd_framework/services/registration.py +101 -0
- python_ddd_framework/services/repository.py +38 -0
- python_ddd_framework/services/runtime.py +302 -0
- python_ddd_framework/settings/__init__.py +30 -0
- python_ddd_framework/settings/application.py +95 -0
- python_ddd_framework/settings/binding.py +33 -0
- python_ddd_framework/settings/catalog.py +121 -0
- python_ddd_framework/settings/changes.py +14 -0
- python_ddd_framework/settings/contracts.py +115 -0
- python_ddd_framework/settings/definition_discovery.py +71 -0
- python_ddd_framework/settings/definitions.py +41 -0
- python_ddd_framework/settings/errors.py +22 -0
- python_ddd_framework/settings/handlers.py +43 -0
- python_ddd_framework/settings/management.py +57 -0
- python_ddd_framework/settings/manager.py +89 -0
- python_ddd_framework/settings/module.py +10 -0
- python_ddd_framework/settings/notifications.py +39 -0
- python_ddd_framework/settings/permissions.py +14 -0
- python_ddd_framework/settings/provider.py +74 -0
- python_ddd_framework/settings/refresh.py +140 -0
- python_ddd_framework/settings/refresh_module.py +45 -0
- python_ddd_framework/settings/sqlalchemy/__init__.py +5 -0
- python_ddd_framework/settings/sqlalchemy/migrations/0001_settings.py +31 -0
- python_ddd_framework/settings/sqlalchemy/migrations/0002_physical_delete.py +32 -0
- python_ddd_framework/settings/sqlalchemy/migrations/0003_version_tokens.py +39 -0
- python_ddd_framework/settings/sqlalchemy/migrations/__init__.py +1 -0
- python_ddd_framework/settings/sqlalchemy/models.py +36 -0
- python_ddd_framework/settings/sqlalchemy/module.py +36 -0
- python_ddd_framework/settings/sqlalchemy/store.py +86 -0
- python_ddd_framework/settings/store.py +16 -0
- python_ddd_framework/settings/values.py +39 -0
- python_ddd_framework/sqlalchemy/__init__.py +54 -0
- python_ddd_framework/sqlalchemy/alembic_runtime/__init__.py +1 -0
- python_ddd_framework/sqlalchemy/alembic_runtime/env.py +33 -0
- python_ddd_framework/sqlalchemy/alembic_runtime/script.py.mako +14 -0
- python_ddd_framework/sqlalchemy/auditing.py +48 -0
- python_ddd_framework/sqlalchemy/errors.py +85 -0
- python_ddd_framework/sqlalchemy/metadata.py +576 -0
- python_ddd_framework/sqlalchemy/migration.py +378 -0
- python_ddd_framework/sqlalchemy/migration_options.py +56 -0
- python_ddd_framework/sqlalchemy/module.py +51 -0
- python_ddd_framework/sqlalchemy/module_migration.py +151 -0
- python_ddd_framework/sqlalchemy/options.py +66 -0
- python_ddd_framework/sqlalchemy/repository.py +33 -0
- python_ddd_framework/sqlalchemy/runtime.py +85 -0
- python_ddd_framework/sqlalchemy/session_provider.py +45 -0
- python_ddd_framework/sqlalchemy/unit_of_work.py +97 -0
- python_ddd_framework/testing/__init__.py +5 -0
- python_ddd_framework/testing/runtime.py +112 -0
- python_ddd_framework/unit_of_work/__init__.py +14 -0
- python_ddd_framework/unit_of_work/contracts.py +223 -0
- python_ddd_framework/unit_of_work/errors.py +27 -0
- python_ddd_framework/unit_of_work/manager.py +210 -0
- python_ddd_framework/unit_of_work/options.py +92 -0
- python_ddd_framework-0.3.1.dist-info/METADATA +379 -0
- python_ddd_framework-0.3.1.dist-info/RECORD +355 -0
- python_ddd_framework-0.3.1.dist-info/WHEEL +4 -0
- python_ddd_framework-0.3.1.dist-info/entry_points.txt +9 -0
- python_ddd_framework-0.3.1.dist-info/licenses/LICENSE +7 -0
- python_ddd_framework-0.3.1.dist-info/licenses/src/python_ddd_framework/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt +21 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""Startup Module 到 isolated Application object graph 的 composition root。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import copy
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from uuid import uuid4
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
from ..application_services.invocation import _InvocationRuntime
|
|
13
|
+
from ..authorization.catalog import _build_permission_catalog
|
|
14
|
+
from ..background_jobs.catalog import _build_background_job_catalog
|
|
15
|
+
from ..background_workers import BackgroundExecutionOptions
|
|
16
|
+
from ..background_workers.catalog import _build_background_worker_catalog
|
|
17
|
+
from ..background_workers.runtime import _BackgroundCoordinator
|
|
18
|
+
from ..caching.catalog import _build_cache_catalog
|
|
19
|
+
from ..configuration.composition import _ConfigurationComposer
|
|
20
|
+
from ..configuration.contracts import _ConfigurationDefaultContribution
|
|
21
|
+
from ..diagnostics.journal import _DiagnosticJournal
|
|
22
|
+
from ..events.contribution import EventContributionRegistry
|
|
23
|
+
from ..hosted_services import HostedServiceOptions
|
|
24
|
+
from ..hosted_services.catalog import (
|
|
25
|
+
_build_hosted_service_catalog,
|
|
26
|
+
_contribute_hosted_service_defaults,
|
|
27
|
+
)
|
|
28
|
+
from ..hosted_services.runtime import _HostedServiceCoordinator
|
|
29
|
+
from ..modularity import AppModule, ModuleDescriptor, ModuleRef
|
|
30
|
+
from ..modularity.discovery import _discover_types, _snapshot_scan_packages
|
|
31
|
+
from ..modularity.graph import _ModuleGraphBuilder
|
|
32
|
+
from ..notifications.catalog import _build_notification_catalog
|
|
33
|
+
from ..options.registry import _OptionsRegistry
|
|
34
|
+
from ..services.contribution import ServiceContributionRegistry
|
|
35
|
+
from ..services.runtime import _ServiceRuntimeBuilder
|
|
36
|
+
from ..settings.catalog import _build_setting_catalog, _contribute_setting_handler_defaults
|
|
37
|
+
from .build_spec import _ApplicationBuildSpec
|
|
38
|
+
from .composition import _CompositionLifecycle
|
|
39
|
+
from .runtime import Application
|
|
40
|
+
from .state import _ApplicationStateRoot
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ApplicationBuilder:
|
|
44
|
+
"""以 startup Module 为唯一入口建立完整、隔离的 Application object graph。"""
|
|
45
|
+
|
|
46
|
+
__slots__ = (
|
|
47
|
+
"_base_path",
|
|
48
|
+
"_cli_args",
|
|
49
|
+
"_dotenv_path",
|
|
50
|
+
"_env_prefix",
|
|
51
|
+
"_environment",
|
|
52
|
+
"_explicit_overrides",
|
|
53
|
+
"_startup_module",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
startup_module: type[AppModule] | ModuleRef,
|
|
59
|
+
*,
|
|
60
|
+
environment: str,
|
|
61
|
+
base_path: Path,
|
|
62
|
+
env_prefix: str,
|
|
63
|
+
cli_args: tuple[str, ...] | list[str] | None = None,
|
|
64
|
+
dotenv_path: Path | None = None,
|
|
65
|
+
explicit_overrides: Mapping[str, object] | None = None,
|
|
66
|
+
) -> None:
|
|
67
|
+
if cli_args is not None and (
|
|
68
|
+
not isinstance(cli_args, (tuple, list))
|
|
69
|
+
or any(not isinstance(arg, str) for arg in cli_args)
|
|
70
|
+
):
|
|
71
|
+
raise TypeError("cli_args must be a sequence of strings")
|
|
72
|
+
self._cli_args = tuple(cli_args or ())
|
|
73
|
+
self._startup_module = startup_module
|
|
74
|
+
self._environment = _validate_environment(environment)
|
|
75
|
+
self._base_path = _validate_base_path(base_path)
|
|
76
|
+
self._env_prefix = _validate_env_prefix(env_prefix)
|
|
77
|
+
self._dotenv_path = _resolve_dotenv_path(
|
|
78
|
+
dotenv_path,
|
|
79
|
+
base_path=self._base_path,
|
|
80
|
+
)
|
|
81
|
+
self._explicit_overrides = _copy_explicit_overrides(explicit_overrides)
|
|
82
|
+
|
|
83
|
+
def build(self) -> Application:
|
|
84
|
+
registry = _ModuleGraphBuilder(self._startup_module).build()
|
|
85
|
+
scan_packages = _snapshot_scan_packages(registry)
|
|
86
|
+
discoveries = _discover_types(registry, scan_packages)
|
|
87
|
+
claims: dict[type[BaseModel], tuple[str, ModuleDescriptor]] = {}
|
|
88
|
+
pre_options_registry = _OptionsRegistry(kind="PreOptions", claims=claims)
|
|
89
|
+
options_registry = _OptionsRegistry(kind="Options", claims=claims)
|
|
90
|
+
permission_catalog = _build_permission_catalog(registry, discoveries)
|
|
91
|
+
cache_catalog = _build_cache_catalog(registry)
|
|
92
|
+
setting_catalog = _build_setting_catalog(registry, discoveries)
|
|
93
|
+
notification_catalog = _build_notification_catalog(registry)
|
|
94
|
+
background_worker_catalog = _build_background_worker_catalog(registry)
|
|
95
|
+
background_job_catalog = _build_background_job_catalog(registry, discoveries)
|
|
96
|
+
hosted_service_catalog = _build_hosted_service_catalog(registry)
|
|
97
|
+
configuration = _ConfigurationComposer(
|
|
98
|
+
environment=self._environment,
|
|
99
|
+
base_path=self._base_path,
|
|
100
|
+
env_prefix=self._env_prefix,
|
|
101
|
+
dotenv_path=self._dotenv_path,
|
|
102
|
+
explicit_overrides=self._explicit_overrides,
|
|
103
|
+
cli_args=self._cli_args,
|
|
104
|
+
).build(
|
|
105
|
+
tuple(
|
|
106
|
+
_ConfigurationDefaultContribution(
|
|
107
|
+
source_location=descriptor.declaration_source,
|
|
108
|
+
values=descriptor.module_type.configuration_defaults,
|
|
109
|
+
)
|
|
110
|
+
for descriptor in registry.dependency_order
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
root = _ApplicationStateRoot(
|
|
114
|
+
application_id=uuid4(),
|
|
115
|
+
registry=registry,
|
|
116
|
+
configuration=configuration,
|
|
117
|
+
pre_options_registry=pre_options_registry,
|
|
118
|
+
options_registry=options_registry,
|
|
119
|
+
service_registry=ServiceContributionRegistry(),
|
|
120
|
+
event_registry=EventContributionRegistry(),
|
|
121
|
+
permission_catalog=permission_catalog,
|
|
122
|
+
cache_catalog=cache_catalog,
|
|
123
|
+
setting_catalog=setting_catalog,
|
|
124
|
+
background_worker_catalog=background_worker_catalog,
|
|
125
|
+
background_job_catalog=background_job_catalog,
|
|
126
|
+
hosted_service_catalog=hosted_service_catalog,
|
|
127
|
+
journal=_DiagnosticJournal(),
|
|
128
|
+
completed_stages={descriptor.key: [] for descriptor in registry.dependency_order},
|
|
129
|
+
)
|
|
130
|
+
_CompositionLifecycle(root).run()
|
|
131
|
+
_contribute_hosted_service_defaults(hosted_service_catalog, root.service_registry)
|
|
132
|
+
_contribute_setting_handler_defaults(registry, root.service_registry)
|
|
133
|
+
root.invocation_runtime = _InvocationRuntime(
|
|
134
|
+
application_id=root.application_id,
|
|
135
|
+
state_getter=lambda: root.state,
|
|
136
|
+
)
|
|
137
|
+
root.background_coordinator = _BackgroundCoordinator(
|
|
138
|
+
worker_catalog=background_worker_catalog,
|
|
139
|
+
job_catalog=background_job_catalog,
|
|
140
|
+
options=root.require_options().get(BackgroundExecutionOptions),
|
|
141
|
+
invocation_runtime=root.require_invocation_runtime(),
|
|
142
|
+
build_spec=_ApplicationBuildSpec(
|
|
143
|
+
self._startup_module,
|
|
144
|
+
self._environment,
|
|
145
|
+
self._base_path,
|
|
146
|
+
self._env_prefix,
|
|
147
|
+
self._cli_args,
|
|
148
|
+
self._dotenv_path,
|
|
149
|
+
dict(self._explicit_overrides),
|
|
150
|
+
Path.cwd().resolve(),
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
root.hosted_service_coordinator = _HostedServiceCoordinator(
|
|
154
|
+
catalog=hosted_service_catalog,
|
|
155
|
+
options=root.require_options().get(HostedServiceOptions),
|
|
156
|
+
state_getter=lambda: root.state,
|
|
157
|
+
)
|
|
158
|
+
service_runtime = _ServiceRuntimeBuilder(
|
|
159
|
+
registry,
|
|
160
|
+
root.service_registry,
|
|
161
|
+
root.event_registry,
|
|
162
|
+
scan_packages,
|
|
163
|
+
discoveries,
|
|
164
|
+
root.configuration,
|
|
165
|
+
root.require_options(),
|
|
166
|
+
root.require_invocation_runtime(),
|
|
167
|
+
permission_catalog,
|
|
168
|
+
cache_catalog,
|
|
169
|
+
setting_catalog,
|
|
170
|
+
notification_catalog,
|
|
171
|
+
background_worker_catalog,
|
|
172
|
+
background_job_catalog,
|
|
173
|
+
root.require_background_coordinator(),
|
|
174
|
+
hosted_service_catalog,
|
|
175
|
+
root.require_hosted_service_coordinator(),
|
|
176
|
+
).build()
|
|
177
|
+
root.service_catalog = service_runtime.catalog
|
|
178
|
+
root.application_service_catalog = service_runtime.application_service_catalog
|
|
179
|
+
root.event_catalog = service_runtime.event_catalog
|
|
180
|
+
root.container = service_runtime.container
|
|
181
|
+
root.require_background_coordinator().attach_container(service_runtime.container)
|
|
182
|
+
root.require_hosted_service_coordinator().attach_container(
|
|
183
|
+
service_runtime.container,
|
|
184
|
+
service_runtime.application_service_catalog,
|
|
185
|
+
)
|
|
186
|
+
return Application(root)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _validate_environment(environment: str) -> str:
|
|
190
|
+
if not isinstance(environment, str) or not environment:
|
|
191
|
+
raise TypeError("environment must be a non-empty string")
|
|
192
|
+
if environment != environment.strip() or any(
|
|
193
|
+
not (character.isalnum() or character in "_-") for character in environment
|
|
194
|
+
):
|
|
195
|
+
raise ValueError("environment must contain only letters, digits, '_' or '-'")
|
|
196
|
+
return environment
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _validate_base_path(base_path: Path) -> Path:
|
|
200
|
+
if not isinstance(base_path, Path):
|
|
201
|
+
raise TypeError("base_path must be pathlib.Path")
|
|
202
|
+
resolved = base_path.resolve()
|
|
203
|
+
if not resolved.is_dir():
|
|
204
|
+
raise ValueError("base_path must be an existing directory")
|
|
205
|
+
return resolved
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _validate_env_prefix(env_prefix: str) -> str:
|
|
209
|
+
if not isinstance(env_prefix, str) or not env_prefix:
|
|
210
|
+
raise TypeError("env_prefix must be a non-empty string")
|
|
211
|
+
if not (env_prefix[0].isalpha() or env_prefix[0] == "_") or any(
|
|
212
|
+
not (character.isalnum() or character == "_") for character in env_prefix
|
|
213
|
+
):
|
|
214
|
+
raise ValueError("env_prefix must be a valid environment-variable prefix")
|
|
215
|
+
return env_prefix
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _resolve_dotenv_path(
|
|
219
|
+
dotenv_path: Path | None,
|
|
220
|
+
*,
|
|
221
|
+
base_path: Path,
|
|
222
|
+
) -> Path | None:
|
|
223
|
+
if dotenv_path is None:
|
|
224
|
+
return None
|
|
225
|
+
if not isinstance(dotenv_path, Path):
|
|
226
|
+
raise TypeError("dotenv_path must be pathlib.Path or None")
|
|
227
|
+
candidate = dotenv_path if dotenv_path.is_absolute() else base_path / dotenv_path
|
|
228
|
+
return candidate.resolve()
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _copy_explicit_overrides(
|
|
232
|
+
explicit_overrides: Mapping[str, object] | None,
|
|
233
|
+
) -> dict[str, object]:
|
|
234
|
+
if explicit_overrides is None:
|
|
235
|
+
return {}
|
|
236
|
+
if not isinstance(explicit_overrides, Mapping):
|
|
237
|
+
raise TypeError("explicit_overrides must be a mapping")
|
|
238
|
+
try:
|
|
239
|
+
return {key: _copy_explicit_value(value) for key, value in explicit_overrides.items()}
|
|
240
|
+
except Exception as original_error:
|
|
241
|
+
raise TypeError("explicit_overrides must be defensively copyable") from original_error
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _copy_explicit_value(value: object) -> object:
|
|
245
|
+
# deepcopy 不支持 MappingProxyType;容器先按配置语义复制,再交给 source boundary 校验。
|
|
246
|
+
if isinstance(value, Mapping):
|
|
247
|
+
copied: object = {key: _copy_explicit_value(item) for key, item in value.items()}
|
|
248
|
+
elif isinstance(value, list):
|
|
249
|
+
copied = [_copy_explicit_value(item) for item in value]
|
|
250
|
+
elif isinstance(value, tuple):
|
|
251
|
+
copied = tuple(_copy_explicit_value(item) for item in value)
|
|
252
|
+
elif isinstance(value, set):
|
|
253
|
+
copied = {_copy_explicit_value(item) for item in value}
|
|
254
|
+
elif isinstance(value, frozenset):
|
|
255
|
+
copied = frozenset(_copy_explicit_value(item) for item in value)
|
|
256
|
+
elif isinstance(value, bytearray):
|
|
257
|
+
copied = bytearray(value)
|
|
258
|
+
else:
|
|
259
|
+
copied = copy.deepcopy(value)
|
|
260
|
+
return copied
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""Synchronous Module composition stages 与 PreOptions/Options barriers。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import cast
|
|
8
|
+
|
|
9
|
+
from ..auditing import AuditingOptions
|
|
10
|
+
from ..background_workers import BackgroundExecutionOptions
|
|
11
|
+
from ..diagnostics import EventStatus, LifecyclePhase, LifecycleStage
|
|
12
|
+
from ..errors import (
|
|
13
|
+
CompositionResourceError,
|
|
14
|
+
LifecycleInvocationError,
|
|
15
|
+
)
|
|
16
|
+
from ..hosted_services import HostedServiceOptions
|
|
17
|
+
from ..hosted_services.options import HOSTED_SERVICE_OPTIONS_SECTION
|
|
18
|
+
from ..lifecycle import ConfigureContext, PostConfigureContext, PreConfigureContext
|
|
19
|
+
from ..modularity import ModuleDescriptor
|
|
20
|
+
from ..unit_of_work import UnitOfWorkOptions
|
|
21
|
+
from .state import (
|
|
22
|
+
LIFECYCLE_ERROR_TYPE,
|
|
23
|
+
_ApplicationStateRoot,
|
|
24
|
+
_lifecycle_failure_message,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _CompositionLifecycle:
|
|
29
|
+
"""拥有一次全局 stage barrier 编排,不保存任何跨 Application 状态。"""
|
|
30
|
+
|
|
31
|
+
__slots__ = ("_root",)
|
|
32
|
+
|
|
33
|
+
def __init__(self, root: _ApplicationStateRoot) -> None:
|
|
34
|
+
self._root = root
|
|
35
|
+
|
|
36
|
+
def run(self) -> None:
|
|
37
|
+
# typed 调用是 lifecycle contract;不通过 getattr/string table 建第二份阶段权威。
|
|
38
|
+
for descriptor in self._root.registry.dependency_order:
|
|
39
|
+
self._invoke_pre_configure(descriptor)
|
|
40
|
+
self._root.pre_options = self._root.pre_options_registry.bind_pre_options(
|
|
41
|
+
self._root.configuration
|
|
42
|
+
)
|
|
43
|
+
for descriptor in self._root.registry.dependency_order:
|
|
44
|
+
self._invoke_configure(descriptor)
|
|
45
|
+
for descriptor in self._root.registry.dependency_order:
|
|
46
|
+
self._invoke_post_configure(descriptor)
|
|
47
|
+
options = self._root.options_registry
|
|
48
|
+
owner = self._root.registry.startup
|
|
49
|
+
# 常驻框架能力的默认声明只有此处负责;显式 Module 声明优先,默认值仍由 model 验证。
|
|
50
|
+
options.declare_default(BackgroundExecutionOptions, "background_execution", owner=owner)
|
|
51
|
+
options.declare_default(HostedServiceOptions, HOSTED_SERVICE_OPTIONS_SECTION, owner=owner)
|
|
52
|
+
options.declare_default(AuditingOptions, "auditing", owner=owner)
|
|
53
|
+
options.declare_default(UnitOfWorkOptions, "unit_of_work", owner=owner)
|
|
54
|
+
self._root.options = options.bind_options(self._root.configuration)
|
|
55
|
+
self._root.configuration = self._root.configuration._finalize(
|
|
56
|
+
sections=(
|
|
57
|
+
options.sections
|
|
58
|
+
| self._root.pre_options_registry.sections
|
|
59
|
+
| ({"settings"} if self._root.setting_catalog.definitions else set())
|
|
60
|
+
),
|
|
61
|
+
secret_paths=options.secret_paths | self._root.pre_options_registry.secret_paths,
|
|
62
|
+
mapping_paths=lambda values, reference: (
|
|
63
|
+
options.mapping_paths(values, reference, self._root.options)
|
|
64
|
+
| self._root.pre_options_registry.mapping_paths(
|
|
65
|
+
values, reference, self._root.pre_options
|
|
66
|
+
)
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def _invoke_pre_configure(self, descriptor: ModuleDescriptor) -> None:
|
|
71
|
+
stage = LifecycleStage.PRE_CONFIGURE
|
|
72
|
+
editor = self._root.pre_options_registry.contributor(
|
|
73
|
+
owner=descriptor,
|
|
74
|
+
stage=stage,
|
|
75
|
+
)
|
|
76
|
+
context = PreConfigureContext(
|
|
77
|
+
application_id=self._root.application_id,
|
|
78
|
+
descriptor=descriptor,
|
|
79
|
+
stage=stage,
|
|
80
|
+
application=self._root.view(None),
|
|
81
|
+
_emit=self._root.diagnostic_emitter(descriptor, stage),
|
|
82
|
+
configuration=self._root.configuration,
|
|
83
|
+
pre_configure=editor,
|
|
84
|
+
)
|
|
85
|
+
callback = cast(
|
|
86
|
+
Callable[[PreConfigureContext], object],
|
|
87
|
+
descriptor.instance.pre_configure,
|
|
88
|
+
)
|
|
89
|
+
try:
|
|
90
|
+
self._invoke(descriptor, stage, lambda: callback(context))
|
|
91
|
+
finally:
|
|
92
|
+
editor._close()
|
|
93
|
+
|
|
94
|
+
def _invoke_configure(self, descriptor: ModuleDescriptor) -> None:
|
|
95
|
+
stage = LifecycleStage.CONFIGURE
|
|
96
|
+
editor = self._root.options_registry.contributor(
|
|
97
|
+
owner=descriptor,
|
|
98
|
+
stage=stage,
|
|
99
|
+
)
|
|
100
|
+
services = self._root.service_registry.contributor(
|
|
101
|
+
descriptor=descriptor,
|
|
102
|
+
stage=stage,
|
|
103
|
+
)
|
|
104
|
+
events = self._root.event_registry.contributor(
|
|
105
|
+
descriptor=descriptor,
|
|
106
|
+
stage=stage,
|
|
107
|
+
)
|
|
108
|
+
context = ConfigureContext(
|
|
109
|
+
application_id=self._root.application_id,
|
|
110
|
+
descriptor=descriptor,
|
|
111
|
+
stage=stage,
|
|
112
|
+
application=self._root.view(None),
|
|
113
|
+
_emit=self._root.diagnostic_emitter(descriptor, stage),
|
|
114
|
+
configuration=self._root.configuration,
|
|
115
|
+
pre_options=self._root.require_pre_options(),
|
|
116
|
+
configure=editor,
|
|
117
|
+
services=services,
|
|
118
|
+
events=events,
|
|
119
|
+
)
|
|
120
|
+
callback = cast(
|
|
121
|
+
Callable[[ConfigureContext], object],
|
|
122
|
+
descriptor.instance.configure,
|
|
123
|
+
)
|
|
124
|
+
try:
|
|
125
|
+
self._invoke(descriptor, stage, lambda: callback(context))
|
|
126
|
+
finally:
|
|
127
|
+
editor._close()
|
|
128
|
+
services._close()
|
|
129
|
+
events._close()
|
|
130
|
+
|
|
131
|
+
def _invoke_post_configure(self, descriptor: ModuleDescriptor) -> None:
|
|
132
|
+
stage = LifecycleStage.POST_CONFIGURE
|
|
133
|
+
editor = self._root.options_registry.contributor(
|
|
134
|
+
owner=descriptor,
|
|
135
|
+
stage=stage,
|
|
136
|
+
)
|
|
137
|
+
services = self._root.service_registry.contributor(
|
|
138
|
+
descriptor=descriptor,
|
|
139
|
+
stage=stage,
|
|
140
|
+
)
|
|
141
|
+
context = PostConfigureContext(
|
|
142
|
+
application_id=self._root.application_id,
|
|
143
|
+
descriptor=descriptor,
|
|
144
|
+
stage=stage,
|
|
145
|
+
application=self._root.view(None),
|
|
146
|
+
_emit=self._root.diagnostic_emitter(descriptor, stage),
|
|
147
|
+
configuration=self._root.configuration,
|
|
148
|
+
pre_options=self._root.require_pre_options(),
|
|
149
|
+
configure=editor,
|
|
150
|
+
services=services,
|
|
151
|
+
)
|
|
152
|
+
callback = cast(
|
|
153
|
+
Callable[[PostConfigureContext], object],
|
|
154
|
+
descriptor.instance.post_configure,
|
|
155
|
+
)
|
|
156
|
+
try:
|
|
157
|
+
self._invoke(descriptor, stage, lambda: callback(context))
|
|
158
|
+
finally:
|
|
159
|
+
editor._close()
|
|
160
|
+
services._close()
|
|
161
|
+
|
|
162
|
+
def _invoke(
|
|
163
|
+
self,
|
|
164
|
+
descriptor: ModuleDescriptor,
|
|
165
|
+
stage: LifecycleStage,
|
|
166
|
+
callback: Callable[[], object],
|
|
167
|
+
) -> None:
|
|
168
|
+
subject = str(descriptor.key)
|
|
169
|
+
active_event = self._root.journal.start_event(
|
|
170
|
+
phase=LifecyclePhase.COMPOSITION,
|
|
171
|
+
stage=stage,
|
|
172
|
+
subject=subject,
|
|
173
|
+
source=descriptor.declaration_source,
|
|
174
|
+
)
|
|
175
|
+
try:
|
|
176
|
+
result = callback()
|
|
177
|
+
is_awaitable = inspect.isawaitable(result)
|
|
178
|
+
if inspect.iscoroutine(result):
|
|
179
|
+
result.close()
|
|
180
|
+
if result is not None:
|
|
181
|
+
raise CompositionResourceError(
|
|
182
|
+
module=descriptor.key,
|
|
183
|
+
stage=stage,
|
|
184
|
+
resource_kind=("awaitable" if is_awaitable else "non-None value"),
|
|
185
|
+
)
|
|
186
|
+
except Exception as original_error:
|
|
187
|
+
failure_id = self._root.journal.begin_failure(
|
|
188
|
+
error_type=LIFECYCLE_ERROR_TYPE,
|
|
189
|
+
phase=LifecyclePhase.COMPOSITION,
|
|
190
|
+
stage=stage,
|
|
191
|
+
subject=subject,
|
|
192
|
+
message=_lifecycle_failure_message(subject, stage, original_error),
|
|
193
|
+
source=descriptor.declaration_source,
|
|
194
|
+
dependency_path=tuple(str(key) for key in descriptor.dependency_path),
|
|
195
|
+
)
|
|
196
|
+
duration_ns = self._root.journal.finish_event(
|
|
197
|
+
active_event,
|
|
198
|
+
status=EventStatus.FAILED,
|
|
199
|
+
failure_id=failure_id,
|
|
200
|
+
)
|
|
201
|
+
self._root.journal.complete_failure(failure_id)
|
|
202
|
+
error = LifecycleInvocationError(
|
|
203
|
+
failure_id=failure_id,
|
|
204
|
+
module=descriptor.key,
|
|
205
|
+
phase=LifecyclePhase.COMPOSITION,
|
|
206
|
+
stage=stage,
|
|
207
|
+
dependency_path=descriptor.dependency_path,
|
|
208
|
+
duration_ns=duration_ns,
|
|
209
|
+
source=descriptor.declaration_source,
|
|
210
|
+
original_error=original_error,
|
|
211
|
+
)
|
|
212
|
+
raise error from original_error
|
|
213
|
+
|
|
214
|
+
self._root.journal.finish_event(
|
|
215
|
+
active_event,
|
|
216
|
+
status=EventStatus.SUCCEEDED,
|
|
217
|
+
failure_id=None,
|
|
218
|
+
)
|
|
219
|
+
self._root.completed_stages[descriptor.key].append(stage)
|