python-ddd-framework 0.3.2__py3-none-any.whl → 0.5.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 +139 -21
- python_ddd_framework/application/builder.py +23 -78
- python_ddd_framework/application/composition.py +4 -22
- python_ddd_framework/application/runtime.py +120 -288
- python_ddd_framework/application/state.py +7 -75
- python_ddd_framework/application_services/__init__.py +5 -21
- python_ddd_framework/{services/application_bindings.py → application_services/bindings.py} +52 -9
- python_ddd_framework/application_services/catalog.py +36 -288
- python_ddd_framework/application_services/contracts.py +14 -13
- python_ddd_framework/application_services/dispatcher.py +19 -269
- python_ddd_framework/application_services/invocation.py +197 -15
- python_ddd_framework/application_services/module.py +168 -0
- python_ddd_framework/application_services/pagination.py +21 -0
- python_ddd_framework/auditing/control.py +1 -1
- python_ddd_framework/auditing/module.py +15 -0
- python_ddd_framework/authorization/__init__.py +2 -0
- python_ddd_framework/authorization/contracts.py +7 -2
- python_ddd_framework/authorization/definitions.py +5 -0
- python_ddd_framework/authorization/module.py +40 -0
- python_ddd_framework/authorization/options.py +7 -0
- python_ddd_framework/background_execution/child.py +13 -3
- python_ddd_framework/background_execution/declarations.py +45 -0
- python_ddd_framework/background_execution/lifecycle.py +12 -0
- python_ddd_framework/background_execution/local.py +20 -1
- python_ddd_framework/background_execution/module.py +107 -1
- python_ddd_framework/background_execution/processes.py +11 -1
- python_ddd_framework/background_jobs/catalog.py +59 -42
- python_ddd_framework/background_jobs/contracts.py +16 -19
- python_ddd_framework/background_jobs/pgqueuer/enqueue.py +4 -0
- python_ddd_framework/background_jobs/pgqueuer/module.py +2 -1
- python_ddd_framework/background_jobs/pgqueuer/runtime.py +7 -7
- python_ddd_framework/background_workers/catalog.py +23 -36
- python_ddd_framework/background_workers/contracts.py +3 -0
- python_ddd_framework/background_workers/execution.py +1 -1
- python_ddd_framework/background_workers/runtime.py +47 -1
- python_ddd_framework/caching/__init__.py +7 -6
- python_ddd_framework/caching/contracts.py +65 -67
- python_ddd_framework/caching/errors.py +0 -7
- python_ddd_framework/caching/module.py +18 -0
- python_ddd_framework/caching/naming.py +29 -0
- python_ddd_framework/caching/options.py +38 -0
- python_ddd_framework/caching/unit_of_work.py +46 -0
- python_ddd_framework/cli/__init__.py +31 -6
- python_ddd_framework/cli/project.py +68 -6
- python_ddd_framework/cli/runtime.py +1 -1
- python_ddd_framework/developer_kit/generation.py +75 -22
- python_ddd_framework/developer_kit/project_metadata.py +2 -4
- python_ddd_framework/developer_kit/templates/basic/cookiecutter.json +4 -0
- python_ddd_framework/developer_kit/templates/basic/{{cookiecutter.module_name}}/README.md +45 -0
- python_ddd_framework/developer_kit/templates/basic/{{cookiecutter.module_name}}/__init__.py.jinja +0 -0
- python_ddd_framework/developer_kit/templates/basic/{{cookiecutter.module_name}}/contracts/__init__.py.jinja +0 -0
- python_ddd_framework/developer_kit/templates/basic/{{cookiecutter.module_name}}/contracts/conversion_service.py.jinja +7 -0
- python_ddd_framework/developer_kit/templates/basic/{{cookiecutter.module_name}}/module.py.jinja +38 -0
- python_ddd_framework/developer_kit/templates/basic/{{cookiecutter.module_name}}/services/__init__.py.jinja +0 -0
- python_ddd_framework/developer_kit/templates/basic/{{cookiecutter.module_name}}/services/default_conversion_service.py.jinja +10 -0
- python_ddd_framework/developer_kit/templates/module/cookiecutter.json +1 -1
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/README.md +42 -49
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_jobs/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_jobs/order_approval/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_jobs/order_approval/handler.py.jinja +45 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_jobs/order_approval/payload.py.jinja +8 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_jobs/order_statistics/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_jobs/order_statistics/handler.py.jinja +35 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_jobs/order_statistics/payload.py.jinja +5 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_jobs/order_statistics/schedule.py.jinja +15 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_workers/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_workers/order_maintenance_worker.py.jinja +28 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/background_workers/order_statistics_worker.py.jinja +26 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/caching/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/caching/order_cache.py.jinja +9 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/caching/statistics_cache.py.jinja +9 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/event_handlers/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/event_handlers/order_changed_handler.py.jinja +23 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/hosted_services/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/hosted_services/order_integration_service.py.jinja +71 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/hosted_services/order_observation_handler.py.jinja +16 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/integration_services/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/integration_services/order_reporting_service.py.jinja +16 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/interceptors/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/interceptors/order_timing_interceptor.py.jinja +17 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/module.py.jinja +105 -10
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/options/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/{options.py.jinja → options/order_options.py.jinja} +1 -1
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/services/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/services/order_approval_service.py.jinja +65 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/services/order_management_service.py.jinja +35 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/services/order_query_service.py.jinja +41 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/setting_handlers/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/setting_handlers/approval_setting_observer.py.jinja +17 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/inputs/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/inputs/approve_order.py.jinja +6 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/inputs/create_order.py.jinja +7 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/integration_services/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/integration_services/order_reporting_service.py.jinja +7 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/module.py.jinja +39 -2
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/services/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/services/order_approval_service.py.jinja +13 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/services/order_management_service.py.jinja +10 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/services/order_query_service.py.jinja +12 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/views/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/views/order_statistics_snapshot.py.jinja +9 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/views/order_view.py.jinja +12 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/entities/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/{orders.py.jinja → entities/order.py.jinja} +10 -18
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/events/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/events/order_changed.py.jinja +13 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/module.py.jinja +42 -3
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/repositories/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/repositories/order_repository.py.jinja +17 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/seeding/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/seeding/order_seed_contributor.py.jinja +22 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/services/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/services/order_approval_service.py.jinja +23 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/settings/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/{settings.py.jinja → settings/approval_settings.py.jinja} +3 -2
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/value_objects/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/value_objects/order_title.py.jinja +10 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/constants/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/constants/order_constants.py.jinja +3 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/enums/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/enums/order_status.py.jinja +6 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/errors/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/errors/order_errors.py.jinja +11 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/messages/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/messages/order_messages.py.jinja +26 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/messages/order_observation.py.jinja +13 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/module.py.jinja +40 -1
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/permissions/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/{permissions.py.jinja → permissions/order_permission_provider.py.jinja} +6 -2
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/permissions/order_permissions.py.jinja +7 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/value_objects/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/value_objects/money.py.jinja +18 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/filters/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/filters/export_filter.py.jinja +15 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/models/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/models/refresh_orders.py.jinja +5 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/module.py.jinja +85 -7
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/routers/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/{files.py.jinja → routers/order_files.py.jinja} +23 -20
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/websockets/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/websockets/order_socket.py.jinja +44 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/migrations/__init__.py.jinja +1 -1
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/models/__init__.py.jinja +1 -7
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/models/base.py.jinja +7 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/models/{orders.py.jinja → order_model.py.jinja} +7 -3
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/module.py.jinja +42 -5
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/repositories/order_repository.py.jinja +79 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/tests/__init__.py.jinja +1 -0
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/tests/test_domain.py.jinja +4 -3
- python_ddd_framework/developer_kit/templates/project/cookiecutter.json +1 -1
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/AGENTS.md +23 -3
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/README.md +29 -22
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{app.development.yaml.jinja → backend/app.development.yaml.jinja} +2 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{pyproject.toml.jinja → backend/pyproject.toml.jinja} +1 -1
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{src → backend/src}/host/main.py.jinja +2 -0
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{src → backend/src}/host/module.py.jinja +40 -3
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/docs/architecture.md +42 -11
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/docs/development.md +144 -23
- python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/scripts/.gitkeep +0 -0
- python_ddd_framework/distributed_lock/contracts.py +4 -1
- python_ddd_framework/domain/__init__.py +2 -0
- python_ddd_framework/domain/services.py +11 -0
- python_ddd_framework/errors/business.py +10 -1
- python_ddd_framework/errors/lifecycle.py +3 -31
- python_ddd_framework/events/__init__.py +5 -2
- python_ddd_framework/events/aggregate.py +3 -3
- python_ddd_framework/events/catalog.py +12 -11
- python_ddd_framework/events/contracts.py +6 -1
- python_ddd_framework/events/contribution.py +1 -52
- python_ddd_framework/events/entities.py +23 -0
- python_ddd_framework/events/module.py +97 -0
- python_ddd_framework/events/runtime.py +80 -29
- python_ddd_framework/events/subscription.py +36 -0
- python_ddd_framework/events/unit_of_work.py +25 -0
- python_ddd_framework/extensions/__init__.py +22 -0
- python_ddd_framework/extensions/catalog.py +198 -0
- python_ddd_framework/extensions/contracts.py +85 -0
- python_ddd_framework/extensions/models.py +142 -0
- python_ddd_framework/extensions/module.py +21 -0
- python_ddd_framework/fastapi/__init__.py +2 -0
- python_ddd_framework/fastapi/action.py +1 -2
- python_ddd_framework/fastapi/adapter.py +16 -0
- python_ddd_framework/fastapi/application_services.py +43 -25
- python_ddd_framework/fastapi/background.py +2 -1
- python_ddd_framework/fastapi/contracts.py +26 -8
- python_ddd_framework/fastapi/health.py +1 -1
- python_ddd_framework/fastapi/module.py +14 -0
- python_ddd_framework/fastapi/parameters.py +3 -18
- python_ddd_framework/fastapi/realtime/connection.py +10 -7
- python_ddd_framework/fastapi/realtime/module.py +3 -0
- python_ddd_framework/fastapi/realtime/runtime.py +10 -24
- python_ddd_framework/fastapi/request_context.py +2 -1
- python_ddd_framework/fastapi/routing.py +2 -1
- python_ddd_framework/fastapi/server.py +8 -0
- python_ddd_framework/fastapi/settings.py +2 -1
- python_ddd_framework/hosted_services/bridge.py +95 -17
- python_ddd_framework/hosted_services/catalog.py +6 -16
- python_ddd_framework/hosted_services/contracts.py +9 -1
- python_ddd_framework/hosted_services/declarations.py +15 -0
- python_ddd_framework/hosted_services/module.py +69 -0
- python_ddd_framework/hosted_services/runtime.py +101 -18
- python_ddd_framework/identity/__init__.py +24 -0
- python_ddd_framework/identity/application.py +38 -90
- python_ddd_framework/identity/contracts.py +181 -16
- python_ddd_framework/identity/http_api.py +79 -2
- python_ddd_framework/identity/management.py +166 -0
- python_ddd_framework/identity/module.py +12 -4
- python_ddd_framework/identity/services.py +29 -16
- python_ddd_framework/identity/sqlalchemy/migrations/0003_extra_properties.py +26 -0
- python_ddd_framework/identity/sqlalchemy/migrations/0004_concurrency_version.py +29 -0
- python_ddd_framework/identity/sqlalchemy/models.py +21 -2
- python_ddd_framework/identity/sqlalchemy/module.py +11 -2
- python_ddd_framework/identity/sqlalchemy/repository.py +458 -0
- python_ddd_framework/identity/sqlalchemy/session_security.py +88 -0
- python_ddd_framework/identity/sqlalchemy/stores.py +69 -290
- python_ddd_framework/identity/tokens.py +2 -5
- python_ddd_framework/{application_services/validation.py → invocation/arguments.py} +8 -6
- python_ddd_framework/invocation/contribution.py +61 -0
- python_ddd_framework/invocation/dispatcher.py +291 -0
- python_ddd_framework/invocation/entries.py +2 -25
- python_ddd_framework/invocation/entrypoints.py +126 -0
- python_ddd_framework/{application_services → invocation}/execution.py +8 -5
- python_ddd_framework/invocation/function_runtime.py +3 -1
- python_ddd_framework/invocation/interception.py +113 -42
- python_ddd_framework/{application_services → invocation}/interceptors.py +2 -2
- python_ddd_framework/invocation/managed_proxy.py +116 -0
- python_ddd_framework/invocation/managed_services.py +250 -0
- python_ddd_framework/invocation/methods.py +345 -0
- python_ddd_framework/invocation/module.py +113 -0
- python_ddd_framework/{application_services → invocation}/policies.py +8 -1
- python_ddd_framework/invocation/validation.py +25 -0
- python_ddd_framework/lifecycle/__init__.py +2 -0
- python_ddd_framework/lifecycle/composition.py +5 -2
- python_ddd_framework/lifecycle/participants.py +37 -0
- python_ddd_framework/messaging/__init__.py +25 -0
- python_ddd_framework/messaging/channel.py +232 -0
- python_ddd_framework/messaging/contracts.py +78 -0
- python_ddd_framework/messaging/module.py +114 -0
- python_ddd_framework/messaging/options.py +13 -0
- python_ddd_framework/messaging/receipt.py +27 -0
- python_ddd_framework/messaging/runtime.py +139 -0
- python_ddd_framework/modularity/__init__.py +11 -1
- python_ddd_framework/modularity/contracts.py +47 -16
- python_ddd_framework/modularity/discovery.py +21 -2
- python_ddd_framework/modularity/graph.py +45 -1
- python_ddd_framework/modularity/registry.py +83 -3
- python_ddd_framework/notifications/__init__.py +2 -0
- python_ddd_framework/notifications/catalog.py +3 -2
- python_ddd_framework/notifications/declarations.py +18 -0
- python_ddd_framework/notifications/module.py +21 -0
- python_ddd_framework/observability/logging.py +3 -0
- python_ddd_framework/observability/tracing.py +3 -0
- python_ddd_framework/options/contribution.py +12 -0
- python_ddd_framework/options/registry.py +44 -11
- python_ddd_framework/realtime/__init__.py +2 -1
- python_ddd_framework/realtime/contracts.py +3 -7
- python_ddd_framework/realtime/messages.py +26 -1
- python_ddd_framework/redis/cache.py +243 -0
- python_ddd_framework/redis/cache_scripts.py +40 -0
- python_ddd_framework/redis/distributed_lock.py +10 -2
- python_ddd_framework/redis/module.py +13 -4
- python_ddd_framework/redis/notifications.py +5 -2
- python_ddd_framework/redis/runtime.py +1 -79
- python_ddd_framework/seeding/__init__.py +13 -0
- python_ddd_framework/seeding/contracts.py +45 -0
- python_ddd_framework/seeding/module.py +73 -0
- python_ddd_framework/seeding/runtime.py +63 -0
- python_ddd_framework/services/arbitration.py +23 -0
- python_ddd_framework/services/binding.py +2 -3
- python_ddd_framework/services/composition.py +108 -0
- python_ddd_framework/services/contribution.py +44 -54
- python_ddd_framework/services/convention.py +53 -181
- python_ddd_framework/services/fixed_lifetime.py +12 -15
- python_ddd_framework/services/framework_provider.py +3 -158
- python_ddd_framework/services/native_graph.py +35 -60
- python_ddd_framework/services/provider.py +59 -4
- python_ddd_framework/services/repository.py +6 -0
- python_ddd_framework/services/runtime.py +129 -215
- python_ddd_framework/settings/catalog.py +5 -4
- python_ddd_framework/settings/declarations.py +18 -0
- python_ddd_framework/settings/definitions.py +5 -0
- python_ddd_framework/settings/manager.py +1 -1
- python_ddd_framework/settings/module.py +50 -1
- python_ddd_framework/settings/notifications.py +4 -2
- python_ddd_framework/settings/refresh_module.py +9 -2
- python_ddd_framework/settings/sqlalchemy/module.py +2 -1
- python_ddd_framework/sqlalchemy/__init__.py +12 -0
- python_ddd_framework/sqlalchemy/alembic_runtime/env.py +1 -0
- python_ddd_framework/sqlalchemy/auditing.py +7 -1
- python_ddd_framework/sqlalchemy/extensions.py +186 -0
- python_ddd_framework/sqlalchemy/metadata.py +110 -6
- python_ddd_framework/sqlalchemy/migration.py +61 -8
- python_ddd_framework/sqlalchemy/migration_operations.py +86 -0
- python_ddd_framework/sqlalchemy/module.py +14 -11
- python_ddd_framework/sqlalchemy/module_migration.py +71 -3
- python_ddd_framework/sqlalchemy/repository.py +217 -13
- python_ddd_framework/sqlalchemy/session_provider.py +14 -1
- python_ddd_framework/testing/runtime.py +5 -4
- python_ddd_framework/unit_of_work/__init__.py +2 -1
- python_ddd_framework/unit_of_work/contracts.py +6 -7
- python_ddd_framework/unit_of_work/errors.py +11 -0
- python_ddd_framework/unit_of_work/lifecycle.py +19 -0
- python_ddd_framework/unit_of_work/manager.py +86 -32
- python_ddd_framework/unit_of_work/module.py +61 -0
- python_ddd_framework/unit_of_work/options.py +7 -1
- python_ddd_framework/validation/__init__.py +1 -0
- python_ddd_framework/validation/models.py +37 -0
- {python_ddd_framework-0.3.2.dist-info → python_ddd_framework-0.5.1.dist-info}/METADATA +147 -44
- python_ddd_framework-0.5.1.dist-info/RECORD +488 -0
- {python_ddd_framework-0.3.2.dist-info → python_ddd_framework-0.5.1.dist-info}/WHEEL +1 -1
- python_ddd_framework/application_services/seeding.py +0 -72
- python_ddd_framework/caching/catalog.py +0 -73
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/cache.py.jinja +0 -10
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/events.py.jinja +0 -24
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/integration.py.jinja +0 -41
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/orders.py.jinja +0 -83
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application/tasks.py.jinja +0 -84
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/orders.py.jinja +0 -35
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/repository.py.jinja +0 -14
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/seeding.py.jinja +0 -19
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/definitions.py.jinja +0 -24
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/realtime.py.jinja +0 -36
- python_ddd_framework/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/repositories/orders.py.jinja +0 -49
- python_ddd_framework-0.3.2.dist-info/RECORD +0 -355
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{.dockerignore → backend/.dockerignore} +0 -0
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{.gitignore → backend/.gitignore} +0 -0
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{.python-version → backend/.python-version} +0 -0
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{Dockerfile → backend/Dockerfile} +0 -0
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{compose.dev.yaml.jinja → backend/compose.dev.yaml.jinja} +0 -0
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{compose.production.yaml.jinja → backend/compose.production.yaml.jinja} +0 -0
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{src → backend/src}/host/__init__.py.jinja +0 -0
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{tests → backend/tests}/conftest.py.jinja +0 -0
- /python_ddd_framework/developer_kit/templates/project/{{cookiecutter.project_name}}/{tests → backend/tests}/host/test_http.py.jinja +0 -0
- /python_ddd_framework/{application_services → invocation}/signature.py +0 -0
- {python_ddd_framework-0.3.2.dist-info → python_ddd_framework-0.5.1.dist-info}/entry_points.txt +0 -0
- {python_ddd_framework-0.3.2.dist-info → python_ddd_framework-0.5.1.dist-info}/licenses/LICENSE +0 -0
- {python_ddd_framework-0.3.2.dist-info → python_ddd_framework-0.5.1.dist-info}/licenses/src/python_ddd_framework/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt +0 -0
|
@@ -1,178 +1,23 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""通用组装事实进入原生 Dishka;具体能力的注册由模块拥有。"""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from dishka import Provider, Scope
|
|
4
4
|
|
|
5
|
-
from dishka import (
|
|
6
|
-
Provider,
|
|
7
|
-
Scope,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
from ..application_services import ApplicationServiceCatalog
|
|
11
|
-
from ..application_services.dispatcher import _ApplicationServiceDispatcher, _proxy_factory
|
|
12
|
-
from ..application_services.invocation import (
|
|
13
|
-
_InvocationRuntime,
|
|
14
|
-
_ScopedApplicationServiceInvoker,
|
|
15
|
-
)
|
|
16
|
-
from ..auditing.control import AuditingControl
|
|
17
|
-
from ..authorization import CurrentUser, PermissionCatalog
|
|
18
|
-
from ..background_jobs import BackgroundJobCatalog
|
|
19
|
-
from ..background_workers import BackgroundWorkerCatalog
|
|
20
|
-
from ..background_workers.runtime import _BackgroundCoordinator
|
|
21
|
-
from ..caching import CacheCatalog
|
|
22
5
|
from ..configuration import ConfigurationRoot
|
|
23
|
-
from ..events import AggregateEventCollector, LocalEventBus, LocalEventCatalog
|
|
24
|
-
from ..hosted_services import HostedServiceCatalog
|
|
25
|
-
from ..hosted_services.runtime import _HostedServiceCoordinator
|
|
26
|
-
from ..invocation import ApplicationInvocationContext, BackgroundSystemCaller
|
|
27
|
-
from ..invocation.interception import _EntryInterceptionCatalog
|
|
28
6
|
from ..modularity import ModuleRegistry
|
|
29
|
-
from ..notifications import NotificationCatalog
|
|
30
7
|
from ..options import Options, OptionsSnapshot
|
|
31
|
-
from ..settings import SettingCatalog
|
|
32
|
-
from ..unit_of_work import UnitOfWork, UnitOfWorkManager, UnitOfWorkOptions
|
|
33
|
-
from ..unit_of_work.contracts import _UnitOfWorkFactory
|
|
34
8
|
|
|
35
9
|
|
|
36
10
|
def _framework_provider(
|
|
37
11
|
*,
|
|
38
12
|
registry: ModuleRegistry,
|
|
39
|
-
has_unit_of_work_factory: bool,
|
|
40
|
-
entry_interceptors: _EntryInterceptionCatalog,
|
|
41
13
|
configuration: ConfigurationRoot,
|
|
42
14
|
options: OptionsSnapshot,
|
|
43
|
-
invocation_runtime: _InvocationRuntime,
|
|
44
|
-
application_service_catalog: ApplicationServiceCatalog,
|
|
45
|
-
event_catalog: LocalEventCatalog,
|
|
46
|
-
permission_catalog: PermissionCatalog,
|
|
47
|
-
cache_catalog: CacheCatalog,
|
|
48
|
-
setting_catalog: SettingCatalog,
|
|
49
|
-
notification_catalog: NotificationCatalog,
|
|
50
|
-
background_worker_catalog: BackgroundWorkerCatalog,
|
|
51
|
-
background_job_catalog: BackgroundJobCatalog,
|
|
52
|
-
background_coordinator: _BackgroundCoordinator,
|
|
53
|
-
hosted_service_catalog: HostedServiceCatalog,
|
|
54
|
-
hosted_service_coordinator: _HostedServiceCoordinator,
|
|
55
15
|
) -> Provider:
|
|
56
|
-
"""框架自身 contract 直接进入 Dishka;不写入业务 ServiceCatalog 第二清单。"""
|
|
57
16
|
provider = Provider()
|
|
58
|
-
provider.provide(
|
|
59
|
-
lambda: entry_interceptors, provides=_EntryInterceptionCatalog, scope=Scope.APP
|
|
60
|
-
)
|
|
61
|
-
provider.provide(AuditingControl, scope=Scope.APP)
|
|
62
|
-
_provide_unit_of_work(provider, has_unit_of_work_factory)
|
|
63
17
|
provider.provide(lambda: registry, provides=ModuleRegistry, scope=Scope.APP)
|
|
64
18
|
provider.provide(lambda: configuration, provides=ConfigurationRoot, scope=Scope.APP)
|
|
65
19
|
provider.provide(lambda: options, provides=OptionsSnapshot, scope=Scope.APP)
|
|
66
|
-
#
|
|
20
|
+
# 已冻结 Options 是唯一配置解释结果;容器仅发布实例,不再绑定或建立配置旁路。
|
|
67
21
|
for model_type in options.values:
|
|
68
22
|
provider.from_context(provides=Options[model_type], scope=Scope.APP) # type: ignore[valid-type]
|
|
69
|
-
provider.provide(
|
|
70
|
-
lambda: invocation_runtime,
|
|
71
|
-
provides=_InvocationRuntime,
|
|
72
|
-
scope=Scope.APP,
|
|
73
|
-
)
|
|
74
|
-
provider.provide(
|
|
75
|
-
lambda: application_service_catalog,
|
|
76
|
-
provides=ApplicationServiceCatalog,
|
|
77
|
-
scope=Scope.APP,
|
|
78
|
-
)
|
|
79
|
-
provider.provide(lambda: event_catalog, provides=LocalEventCatalog, scope=Scope.APP)
|
|
80
|
-
provider.provide(lambda: permission_catalog, provides=PermissionCatalog, scope=Scope.APP)
|
|
81
|
-
provider.provide(lambda: cache_catalog, provides=CacheCatalog, scope=Scope.APP)
|
|
82
|
-
provider.provide(lambda: setting_catalog, provides=SettingCatalog, scope=Scope.APP)
|
|
83
|
-
provider.provide(lambda: notification_catalog, provides=NotificationCatalog, scope=Scope.APP)
|
|
84
|
-
provider.provide(
|
|
85
|
-
lambda: background_worker_catalog,
|
|
86
|
-
provides=BackgroundWorkerCatalog,
|
|
87
|
-
scope=Scope.APP,
|
|
88
|
-
)
|
|
89
|
-
provider.provide(
|
|
90
|
-
lambda: background_job_catalog,
|
|
91
|
-
provides=BackgroundJobCatalog,
|
|
92
|
-
scope=Scope.APP,
|
|
93
|
-
)
|
|
94
|
-
provider.provide(
|
|
95
|
-
lambda: background_coordinator,
|
|
96
|
-
provides=_BackgroundCoordinator,
|
|
97
|
-
scope=Scope.APP,
|
|
98
|
-
)
|
|
99
|
-
provider.provide(
|
|
100
|
-
lambda: hosted_service_catalog,
|
|
101
|
-
provides=HostedServiceCatalog,
|
|
102
|
-
scope=Scope.APP,
|
|
103
|
-
)
|
|
104
|
-
provider.provide(
|
|
105
|
-
lambda: hosted_service_coordinator,
|
|
106
|
-
provides=_HostedServiceCoordinator,
|
|
107
|
-
scope=Scope.APP,
|
|
108
|
-
)
|
|
109
|
-
provider.provide(
|
|
110
|
-
lambda: background_coordinator.system_caller,
|
|
111
|
-
provides=BackgroundSystemCaller,
|
|
112
|
-
scope=Scope.APP,
|
|
113
|
-
)
|
|
114
|
-
provider.provide(
|
|
115
|
-
_current_user,
|
|
116
|
-
provides=CurrentUser,
|
|
117
|
-
scope=Scope.REQUEST,
|
|
118
|
-
)
|
|
119
|
-
provider.from_context(provides=ApplicationInvocationContext, scope=Scope.ACTION)
|
|
120
|
-
provider.provide(
|
|
121
|
-
_ApplicationServiceDispatcher,
|
|
122
|
-
provides=_ApplicationServiceDispatcher,
|
|
123
|
-
scope=Scope.REQUEST,
|
|
124
|
-
)
|
|
125
|
-
provider.provide(
|
|
126
|
-
_ScopedApplicationServiceInvoker,
|
|
127
|
-
provides=_ScopedApplicationServiceInvoker,
|
|
128
|
-
scope=Scope.APP,
|
|
129
|
-
)
|
|
130
|
-
for registration in application_service_catalog.registrations:
|
|
131
|
-
if not registration.is_public_service:
|
|
132
|
-
continue
|
|
133
|
-
provider.provide(
|
|
134
|
-
_proxy_factory(application_service_catalog._for_registration(registration)),
|
|
135
|
-
provides=registration.contract,
|
|
136
|
-
scope=Scope.REQUEST,
|
|
137
|
-
)
|
|
138
|
-
provider.provide(LocalEventBus, provides=LocalEventBus, scope=Scope.REQUEST)
|
|
139
|
-
provider.provide(
|
|
140
|
-
AggregateEventCollector,
|
|
141
|
-
provides=AggregateEventCollector,
|
|
142
|
-
scope=Scope.ACTION,
|
|
143
|
-
)
|
|
144
|
-
for worker_type in {item.worker_type for item in background_worker_catalog.definitions}:
|
|
145
|
-
if isinstance(worker_type, type):
|
|
146
|
-
provider.provide(worker_type, provides=worker_type, scope=Scope.ACTION)
|
|
147
|
-
for handler_type in {item.handler_type for item in background_job_catalog.definitions}:
|
|
148
|
-
if isinstance(handler_type, type):
|
|
149
|
-
provider.provide(handler_type, provides=handler_type, scope=Scope.ACTION)
|
|
150
23
|
return provider
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def _current_user(invocation_runtime: _InvocationRuntime) -> CurrentUser:
|
|
154
|
-
# CurrentUser 只来自当前 Application 的 task-local request context。
|
|
155
|
-
return invocation_runtime.current_user()
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def _unit_of_work_manager(
|
|
159
|
-
runtime: _InvocationRuntime,
|
|
160
|
-
factory: _UnitOfWorkFactory,
|
|
161
|
-
options: Options[UnitOfWorkOptions],
|
|
162
|
-
catalog: LocalEventCatalog,
|
|
163
|
-
) -> UnitOfWorkManager:
|
|
164
|
-
return UnitOfWorkManager(runtime, factory, options.value, catalog)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def _current_unit_of_work(manager: UnitOfWorkManager) -> UnitOfWork:
|
|
168
|
-
return manager.require_current()
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def _provide_unit_of_work(
|
|
172
|
-
provider: Provider,
|
|
173
|
-
has_unit_of_work_factory: bool,
|
|
174
|
-
) -> None:
|
|
175
|
-
if not has_unit_of_work_factory:
|
|
176
|
-
provider.provide(_UnitOfWorkFactory, scope=Scope.APP)
|
|
177
|
-
provider.provide(_unit_of_work_manager, provides=UnitOfWorkManager, scope=Scope.APP)
|
|
178
|
-
provider.provide(_current_unit_of_work, provides=UnitOfWork, scope=Scope.ACTION, cache=False)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from collections.abc import Mapping
|
|
5
|
+
from collections.abc import Iterator, Mapping
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from typing import get_origin
|
|
8
8
|
|
|
@@ -11,16 +11,12 @@ from dishka import (
|
|
|
11
11
|
AsyncContainer,
|
|
12
12
|
BaseScope,
|
|
13
13
|
DependencyKey,
|
|
14
|
-
|
|
14
|
+
Provider,
|
|
15
15
|
)
|
|
16
16
|
from dishka.dependency_source import Factory
|
|
17
17
|
from dishka.entities.factory_type import FactoryType
|
|
18
18
|
|
|
19
|
-
from ..application_services import ApplicationService, ApplicationServiceCatalog
|
|
20
|
-
from ..application_services.errors import ApplicationServiceDefinitionError
|
|
21
|
-
from ..application_services.interceptors import InterceptionStage
|
|
22
19
|
from ..errors import CatalogNativeGraphMismatchError, InvalidConventionDefinitionError
|
|
23
|
-
from ..invocation.interception import _EntryInterceptionCatalog
|
|
24
20
|
from .arbitration import (
|
|
25
21
|
_RegistrationDraft,
|
|
26
22
|
)
|
|
@@ -41,9 +37,14 @@ class _NativeGraphRegistration:
|
|
|
41
37
|
class _NativeServiceGraph:
|
|
42
38
|
"""只读投影 Dishka 已构建图,用于证明 catalog 与真实容器一致。"""
|
|
43
39
|
|
|
44
|
-
__slots__ = ("_rows"
|
|
40
|
+
__slots__ = ("_method_decorators", "_rows")
|
|
45
41
|
|
|
46
|
-
def __init__(self, container: AsyncContainer) -> None:
|
|
42
|
+
def __init__(self, container: AsyncContainer, decorators: tuple[Provider, ...] = ()) -> None:
|
|
43
|
+
self._method_decorators = {
|
|
44
|
+
id(decorator.factory.source)
|
|
45
|
+
for provider in decorators
|
|
46
|
+
for decorator in provider.decorators
|
|
47
|
+
}
|
|
47
48
|
rows: list[_NativeGraphRegistration] = []
|
|
48
49
|
native_registry = container.registry
|
|
49
50
|
while True:
|
|
@@ -61,6 +62,26 @@ class _NativeServiceGraph:
|
|
|
61
62
|
native_registry = child_registry
|
|
62
63
|
self._rows = tuple(rows)
|
|
63
64
|
|
|
65
|
+
def __iter__(self) -> Iterator[_NativeGraphRegistration]:
|
|
66
|
+
return iter(self._rows)
|
|
67
|
+
|
|
68
|
+
def effective_factory(self, row: _NativeGraphRegistration) -> Factory:
|
|
69
|
+
factory = self._undecorated_factory(row.factory)
|
|
70
|
+
# Alias 自身不缓存;只沿 Dishka 已验证的链读取实际实例 owner。
|
|
71
|
+
while factory.type is FactoryType.ALIAS:
|
|
72
|
+
factory = self._undecorated_factory(
|
|
73
|
+
next(item.factory for item in self._rows if item.key == factory.dependencies[0])
|
|
74
|
+
)
|
|
75
|
+
return factory
|
|
76
|
+
|
|
77
|
+
def _undecorated_factory(self, factory: Factory) -> Factory:
|
|
78
|
+
# 注册核对保留 alias 身份;实例 owner 核对才继续追踪 alias。
|
|
79
|
+
while id(factory.source) in self._method_decorators:
|
|
80
|
+
factory = next(
|
|
81
|
+
item.factory for item in self._rows if item.key == factory.dependencies[0]
|
|
82
|
+
)
|
|
83
|
+
return factory
|
|
84
|
+
|
|
64
85
|
def differences(self, drafts: tuple[_RegistrationDraft, ...]) -> tuple[str, ...]:
|
|
65
86
|
return tuple(
|
|
66
87
|
f"missing accepted {draft.contribution.kind.value} registration for {draft.key}"
|
|
@@ -77,18 +98,10 @@ class _NativeServiceGraph:
|
|
|
77
98
|
if scope is None or not isinstance(candidate, type):
|
|
78
99
|
continue
|
|
79
100
|
_validate_fixed_lifetime(candidate)
|
|
80
|
-
if
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
)
|
|
84
|
-
# 公开 REQUEST proxy 由框架提供;其实际实现已移入私有 ACTION component。
|
|
85
|
-
continue
|
|
86
|
-
factory = row.factory
|
|
87
|
-
# Alias 自身不缓存;沿 Dishka 已验证的链核对真正创建实例的 factory。
|
|
88
|
-
while factory.type is FactoryType.ALIAS:
|
|
89
|
-
factory = next(
|
|
90
|
-
item.factory for item in self._rows if item.key == factory.dependencies[0]
|
|
91
|
-
)
|
|
101
|
+
if candidate is row.key.type_hint and row.key.component == DEFAULT_COMPONENT:
|
|
102
|
+
# 具有代理的角色分别声明公开入口与实际实现的生命周期。
|
|
103
|
+
scope = getattr(candidate, "_public_service_scope", scope)
|
|
104
|
+
factory = self.effective_factory(row)
|
|
92
105
|
if row.scope is not scope or not factory.cache:
|
|
93
106
|
raise InvalidConventionDefinitionError(
|
|
94
107
|
symbol=str(row.key.type_hint),
|
|
@@ -115,17 +128,6 @@ class _NativeServiceGraph:
|
|
|
115
128
|
None,
|
|
116
129
|
)
|
|
117
130
|
|
|
118
|
-
def implementation_for(self, target: type[object]) -> type[object]:
|
|
119
|
-
key = DependencyKey(target, DEFAULT_COMPONENT)
|
|
120
|
-
while True:
|
|
121
|
-
factory = next(row.factory for row in self._rows if row.key == key)
|
|
122
|
-
if factory.type is FactoryType.ALIAS:
|
|
123
|
-
# 原生图已验证 alias 链及循环;沿真实依赖取得最终 class factory。
|
|
124
|
-
key = factory.dependencies[0]
|
|
125
|
-
continue
|
|
126
|
-
# 动态工厂只承诺注册契约,不能在 build 执行它来猜测运行实例。
|
|
127
|
-
return factory.source if isinstance(factory.source, type) else target
|
|
128
|
-
|
|
129
131
|
def _matches(self, draft: _RegistrationDraft) -> bool:
|
|
130
132
|
if draft.is_collection:
|
|
131
133
|
return any(
|
|
@@ -144,45 +146,18 @@ class _NativeServiceGraph:
|
|
|
144
146
|
return any(
|
|
145
147
|
row.key.type_hint == draft.key.type_hint
|
|
146
148
|
and row.key.component == draft.key.component
|
|
147
|
-
and row.factory.source is draft.factory.source
|
|
149
|
+
and self._undecorated_factory(row.factory).source is draft.factory.source
|
|
148
150
|
and row.scope is draft.scope
|
|
149
151
|
for row in self._rows
|
|
150
152
|
)
|
|
151
153
|
return any(
|
|
152
154
|
row.key == draft.key
|
|
153
|
-
and row.factory.source is draft.factory.source
|
|
155
|
+
and self._undecorated_factory(row.factory).source is draft.factory.source
|
|
154
156
|
and row.scope is draft.scope
|
|
155
157
|
for row in self._rows
|
|
156
158
|
)
|
|
157
159
|
|
|
158
160
|
|
|
159
|
-
def _validate_interceptors(
|
|
160
|
-
graph: _NativeServiceGraph,
|
|
161
|
-
catalog: ApplicationServiceCatalog,
|
|
162
|
-
entries: _EntryInterceptionCatalog,
|
|
163
|
-
) -> None:
|
|
164
|
-
# 匹配结果和实际入口 scope 来自同一编译 catalog,不另建后台类型或规则清单。
|
|
165
|
-
requirements = (
|
|
166
|
-
(
|
|
167
|
-
registration,
|
|
168
|
-
Scope.ACTION if registration.before is InterceptionStage.METHOD else Scope.REQUEST,
|
|
169
|
-
)
|
|
170
|
-
for service in catalog.registrations
|
|
171
|
-
for method in service.methods
|
|
172
|
-
for registration in method.interceptors
|
|
173
|
-
)
|
|
174
|
-
for registration, available in (*requirements, *entries.interceptor_scopes):
|
|
175
|
-
scope = graph.interceptor_scope(registration.interceptor)
|
|
176
|
-
if scope not in (Scope.APP, Scope.REQUEST, Scope.ACTION) or scope > available:
|
|
177
|
-
raise ApplicationServiceDefinitionError(
|
|
178
|
-
symbol=registration.interceptor.__qualname__,
|
|
179
|
-
reason=(
|
|
180
|
-
f"interceptor scope is unavailable before {registration.before.value}; "
|
|
181
|
-
f"owner={registration.owner}"
|
|
182
|
-
),
|
|
183
|
-
)
|
|
184
|
-
|
|
185
|
-
|
|
186
161
|
def _accepted_single_service_scopes(
|
|
187
162
|
drafts: tuple[_RegistrationDraft, ...],
|
|
188
163
|
native_graph: _NativeServiceGraph,
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from types import MethodType
|
|
7
|
+
from typing import TypeVar, get_origin
|
|
7
8
|
|
|
8
9
|
from dishka import BaseScope, DependencyKey, Provider
|
|
9
10
|
from dishka.dependency_source import Alias, Factory, FactoryUnionMode
|
|
@@ -12,6 +13,7 @@ from dishka.entities.marker import BoolMarker
|
|
|
12
13
|
|
|
13
14
|
from ..diagnostics import SourceLocation
|
|
14
15
|
from ..errors import RegistrationConflictError
|
|
16
|
+
from ..modularity.contracts import ModuleDeclaration, _module_declarations
|
|
15
17
|
from .registration import SUPPORTED_SCOPE_LABEL, SUPPORTED_SCOPES, RegistrationKind
|
|
16
18
|
|
|
17
19
|
|
|
@@ -27,6 +29,7 @@ class _FactorySignature:
|
|
|
27
29
|
allow_static_evaluation: bool
|
|
28
30
|
is_to_bind: bool
|
|
29
31
|
native_override: bool
|
|
32
|
+
declarations: tuple[tuple[object, tuple[tuple[str, ModuleDeclaration], ...]], ...]
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
@dataclass(frozen=True, slots=True)
|
|
@@ -42,6 +45,7 @@ class _CollectionSignature:
|
|
|
42
45
|
class _ProviderSignature:
|
|
43
46
|
factories: tuple[_FactorySignature, ...]
|
|
44
47
|
collections: tuple[_CollectionSignature, ...]
|
|
48
|
+
decorators: tuple[tuple[object, ...], ...]
|
|
45
49
|
|
|
46
50
|
|
|
47
51
|
@dataclass(frozen=True, slots=True)
|
|
@@ -71,14 +75,17 @@ class _ValidatedProvider:
|
|
|
71
75
|
class _NativeProviderInspector:
|
|
72
76
|
"""隔离 Dishka private dependency-source shape,返回框架拥有的稳定事实。"""
|
|
73
77
|
|
|
74
|
-
__slots__ = ("_kind", "_source")
|
|
78
|
+
__slots__ = ("_kind", "_method_decorators", "_source")
|
|
75
79
|
|
|
76
|
-
def __init__(
|
|
80
|
+
def __init__(
|
|
81
|
+
self, *, source: SourceLocation, kind: RegistrationKind, method_decorators: bool = False
|
|
82
|
+
) -> None:
|
|
77
83
|
self._source = source
|
|
78
84
|
self._kind = kind
|
|
85
|
+
self._method_decorators = method_decorators
|
|
79
86
|
|
|
80
87
|
def inspect(self, provider: Provider) -> _ValidatedProvider:
|
|
81
|
-
if provider.decorators or provider.activators:
|
|
88
|
+
if (provider.decorators and not self._method_decorators) or provider.activators:
|
|
82
89
|
raise RegistrationConflictError(
|
|
83
90
|
key=None,
|
|
84
91
|
sources=(self._source,),
|
|
@@ -93,6 +100,7 @@ class _NativeProviderInspector:
|
|
|
93
100
|
or provider.factory_union_mode
|
|
94
101
|
or provider.aliases
|
|
95
102
|
or provider.context_vars
|
|
103
|
+
or provider.decorators
|
|
96
104
|
):
|
|
97
105
|
raise RegistrationConflictError(
|
|
98
106
|
key=None,
|
|
@@ -127,6 +135,7 @@ class _NativeProviderInspector:
|
|
|
127
135
|
allow_static_evaluation=item.factory.allow_static_evaluation,
|
|
128
136
|
is_to_bind=item.factory.is_to_bind,
|
|
129
137
|
native_override=item.native_override,
|
|
138
|
+
declarations=self._declarations(item.key.type_hint, item.factory.source),
|
|
130
139
|
)
|
|
131
140
|
for item in factories
|
|
132
141
|
),
|
|
@@ -140,9 +149,55 @@ class _NativeProviderInspector:
|
|
|
140
149
|
)
|
|
141
150
|
for item in collections
|
|
142
151
|
),
|
|
152
|
+
decorators=tuple(self._decorator_signature(item) for item in provider.decorators),
|
|
143
153
|
)
|
|
144
154
|
return _ValidatedProvider(factories, collections, signature)
|
|
145
155
|
|
|
156
|
+
def _decorator_signature(self, decorator: object) -> tuple[object, ...]:
|
|
157
|
+
from dishka.dependency_source.decorator import Decorator
|
|
158
|
+
|
|
159
|
+
assert isinstance(decorator, Decorator)
|
|
160
|
+
factory = decorator.factory
|
|
161
|
+
if (
|
|
162
|
+
decorator.scope is not None
|
|
163
|
+
or decorator.when is not None
|
|
164
|
+
or decorator.allow_static_evaluation
|
|
165
|
+
or (
|
|
166
|
+
decorator.generic
|
|
167
|
+
and (
|
|
168
|
+
isinstance(decorator.provides.type_hint, TypeVar)
|
|
169
|
+
or bool(getattr(decorator.provides.type_hint, "__parameters__", ()))
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
or factory.type is not FactoryType.FACTORY
|
|
173
|
+
):
|
|
174
|
+
self._conflict(
|
|
175
|
+
decorator.provides, "managed method decorators must retain native scope/cache"
|
|
176
|
+
)
|
|
177
|
+
return (
|
|
178
|
+
decorator.provides,
|
|
179
|
+
self.source_identity(factory.source),
|
|
180
|
+
tuple(factory.dependencies),
|
|
181
|
+
tuple(sorted(factory.kw_dependencies.items())),
|
|
182
|
+
factory.provides,
|
|
183
|
+
factory.is_to_bind,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
@staticmethod
|
|
187
|
+
def _declarations(
|
|
188
|
+
*candidates: object,
|
|
189
|
+
) -> tuple[tuple[object, tuple[tuple[str, ModuleDeclaration], ...]], ...]:
|
|
190
|
+
result = []
|
|
191
|
+
for candidate in candidates:
|
|
192
|
+
candidate = get_origin(candidate) or candidate
|
|
193
|
+
if isinstance(candidate, type):
|
|
194
|
+
result.append((candidate, tuple(_module_declarations(candidate).items())))
|
|
195
|
+
return tuple(result)
|
|
196
|
+
|
|
197
|
+
def assert_unchanged(self, provider: Provider, signature: _ProviderSignature) -> None:
|
|
198
|
+
if self.inspect(provider).signature != signature:
|
|
199
|
+
self._conflict(None, "native Provider was mutated after contribution")
|
|
200
|
+
|
|
146
201
|
def _inspect_factory(
|
|
147
202
|
self,
|
|
148
203
|
provider: Provider,
|
|
@@ -192,7 +247,7 @@ class _NativeProviderInspector:
|
|
|
192
247
|
self._conflict(key, f"collection scope must be {SUPPORTED_SCOPE_LABEL}")
|
|
193
248
|
return _CollectionDefinition(collection, source_key, key, collection.scope)
|
|
194
249
|
|
|
195
|
-
def _conflict(self, key: DependencyKey, reason: str) -> None:
|
|
250
|
+
def _conflict(self, key: DependencyKey | None, reason: str) -> None:
|
|
196
251
|
raise RegistrationConflictError(key=key, sources=(self._source,), reason=reason)
|
|
197
252
|
|
|
198
253
|
@staticmethod
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Protocol
|
|
4
4
|
|
|
5
|
+
from dishka import Scope
|
|
6
|
+
|
|
5
7
|
from ..errors import InvalidConventionDefinitionError
|
|
6
8
|
from .convention_contracts import _SERVICE_DEFINITION_ATTRIBUTE, _ServiceDefinition
|
|
7
9
|
from .exposure import _business_interfaces
|
|
@@ -11,6 +13,10 @@ class RepositoryContract(Protocol):
|
|
|
11
13
|
"""仓储接口的正式角色;实例由选中 Module 的 REQUEST scope 缓存。"""
|
|
12
14
|
|
|
13
15
|
|
|
16
|
+
# 这是框架发现元数据,不是仓储实例的结构化成员契约。
|
|
17
|
+
setattr(RepositoryContract, "_fixed_service_scope", Scope.REQUEST) # noqa: B010 -- 不扩充 Protocol 成员
|
|
18
|
+
|
|
19
|
+
|
|
14
20
|
def _repository_contract(candidate: type[object]) -> type[object] | None:
|
|
15
21
|
if RepositoryContract not in candidate.__mro__:
|
|
16
22
|
return None
|