python-platform 0.1.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_platform/__init__.py +445 -0
- python_platform/application/__init__.py +6 -0
- python_platform/application/build_spec.py +37 -0
- python_platform/application/builder.py +260 -0
- python_platform/application/composition.py +219 -0
- python_platform/application/runtime.py +546 -0
- python_platform/application/runtime_hooks.py +327 -0
- python_platform/application/state.py +216 -0
- python_platform/application_services/__init__.py +54 -0
- python_platform/application_services/catalog.py +500 -0
- python_platform/application_services/contracts.py +188 -0
- python_platform/application_services/dispatcher.py +423 -0
- python_platform/application_services/errors.py +89 -0
- python_platform/application_services/execution.py +199 -0
- python_platform/application_services/interceptors.py +44 -0
- python_platform/application_services/invocation.py +427 -0
- python_platform/application_services/policies.py +46 -0
- python_platform/application_services/seeding.py +72 -0
- python_platform/application_services/signature.py +49 -0
- python_platform/application_services/validation.py +84 -0
- python_platform/auditing/__init__.py +12 -0
- python_platform/auditing/contracts.py +39 -0
- python_platform/auditing/control.py +48 -0
- python_platform/auditing/sqlalchemy/__init__.py +6 -0
- python_platform/auditing/sqlalchemy/migrations/0001_platform_auditing.py +45 -0
- python_platform/auditing/sqlalchemy/migrations/__init__.py +1 -0
- python_platform/auditing/sqlalchemy/models.py +31 -0
- python_platform/auditing/sqlalchemy/module.py +32 -0
- python_platform/auditing/sqlalchemy/store.py +63 -0
- python_platform/authorization/__init__.py +38 -0
- python_platform/authorization/catalog.py +63 -0
- python_platform/authorization/contracts.py +241 -0
- python_platform/authorization/definition_discovery.py +81 -0
- python_platform/authorization/definitions.py +43 -0
- python_platform/authorization/errors.py +40 -0
- python_platform/background_execution/__init__.py +15 -0
- python_platform/background_execution/application.py +41 -0
- python_platform/background_execution/child.py +123 -0
- python_platform/background_execution/contracts.py +39 -0
- python_platform/background_execution/lifecycle.py +22 -0
- python_platform/background_execution/local.py +127 -0
- python_platform/background_execution/locks.py +31 -0
- python_platform/background_execution/management.py +17 -0
- python_platform/background_execution/module.py +10 -0
- python_platform/background_execution/permissions.py +14 -0
- python_platform/background_execution/processes.py +331 -0
- python_platform/background_jobs/__init__.py +31 -0
- python_platform/background_jobs/catalog.py +287 -0
- python_platform/background_jobs/contracts.py +202 -0
- python_platform/background_jobs/errors.py +28 -0
- python_platform/background_jobs/execution.py +201 -0
- python_platform/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt +21 -0
- python_platform/background_jobs/pgqueuer/__init__.py +6 -0
- python_platform/background_jobs/pgqueuer/enqueue.py +82 -0
- python_platform/background_jobs/pgqueuer/migrations/0001_pgqueuer_1_3_2.py +63 -0
- python_platform/background_jobs/pgqueuer/migrations/__init__.py +1 -0
- python_platform/background_jobs/pgqueuer/module.py +102 -0
- python_platform/background_jobs/pgqueuer/options.py +70 -0
- python_platform/background_jobs/pgqueuer/runtime.py +479 -0
- python_platform/background_jobs/pgqueuer/sql/pgqueuer_1_3_2_install.sql +118 -0
- python_platform/background_jobs/pgqueuer/supervision.py +201 -0
- python_platform/background_workers/__init__.py +22 -0
- python_platform/background_workers/catalog.py +96 -0
- python_platform/background_workers/contracts.py +124 -0
- python_platform/background_workers/errors.py +20 -0
- python_platform/background_workers/execution.py +133 -0
- python_platform/background_workers/runtime.py +203 -0
- python_platform/caching/__init__.py +11 -0
- python_platform/caching/catalog.py +73 -0
- python_platform/caching/contracts.py +73 -0
- python_platform/caching/errors.py +20 -0
- python_platform/cli/__init__.py +87 -0
- python_platform/cli/errors.py +5 -0
- python_platform/cli/project.py +69 -0
- python_platform/cli/runtime.py +68 -0
- python_platform/configuration/__init__.py +21 -0
- python_platform/configuration/composition.py +65 -0
- python_platform/configuration/contracts.py +68 -0
- python_platform/configuration/dotenv_source.py +51 -0
- python_platform/configuration/environment_source.py +38 -0
- python_platform/configuration/immutability.py +124 -0
- python_platform/configuration/input_shape.py +58 -0
- python_platform/configuration/merge.py +103 -0
- python_platform/configuration/root.py +215 -0
- python_platform/configuration/sources.py +519 -0
- python_platform/configuration/values.py +427 -0
- python_platform/configuration/yaml_source.py +51 -0
- python_platform/developer_kit/__init__.py +1 -0
- python_platform/developer_kit/generation.py +182 -0
- python_platform/developer_kit/project_metadata.py +45 -0
- python_platform/developer_kit/source.py +53 -0
- python_platform/developer_kit/templates/module/cookiecutter.json +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/cache.py.jinja +10 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/events.py.jinja +24 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/integration.py.jinja +46 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/module.py.jinja +29 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/options.py.jinja +8 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/orders.py.jinja +81 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/tasks.py.jinja +86 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/module.py.jinja +10 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/orders.py.jinja +36 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/module.py.jinja +10 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/orders.py.jinja +57 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/repository.py.jinja +12 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/seeding.py.jinja +19 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/settings.py.jinja +16 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/definitions.py.jinja +24 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/module.py.jinja +7 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/permissions.py.jinja +15 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/files.py.jinja +74 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/module.py.jinja +58 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/realtime.py.jinja +37 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/migrations/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/models.py.jinja +26 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/module.py.jinja +32 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/repository.py.jinja +49 -0
- python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/tests/test_domain.py.jinja +18 -0
- python_platform/developer_kit/templates/project/cookiecutter.json +6 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/.dockerignore +8 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/.env.jinja +13 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/.gitignore +6 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/.python-version +1 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/Dockerfile +22 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/README.md +86 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/app.yaml.jinja +16 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/compose.dev.yaml.jinja +24 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/compose.production.yaml.jinja +13 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/pyproject.toml.jinja +28 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/__init__.py.jinja +1 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/main.py.jinja +52 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/module.py.jinja +38 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/tests/conftest.py.jinja +8 -0
- python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/tests/host/test_http.py.jinja +101 -0
- python_platform/developer_kit/wiring.py +85 -0
- python_platform/diagnostics/__init__.py +23 -0
- python_platform/diagnostics/journal.py +174 -0
- python_platform/diagnostics/model.py +83 -0
- python_platform/diagnostics/source.py +25 -0
- python_platform/distributed_lock/__init__.py +6 -0
- python_platform/distributed_lock/contracts.py +20 -0
- python_platform/distributed_lock/options.py +19 -0
- python_platform/domain/__init__.py +13 -0
- python_platform/domain/aggregates.py +64 -0
- python_platform/domain/entities.py +33 -0
- python_platform/domain/errors.py +12 -0
- python_platform/domain/value_objects.py +31 -0
- python_platform/errors/__init__.py +75 -0
- python_platform/errors/base.py +13 -0
- python_platform/errors/business.py +53 -0
- python_platform/errors/configuration.py +119 -0
- python_platform/errors/diagnostics.py +12 -0
- python_platform/errors/lifecycle.py +164 -0
- python_platform/errors/modularity.py +100 -0
- python_platform/errors/services.py +100 -0
- python_platform/events/__init__.py +25 -0
- python_platform/events/aggregate.py +39 -0
- python_platform/events/catalog.py +136 -0
- python_platform/events/contracts.py +39 -0
- python_platform/events/contribution.py +128 -0
- python_platform/events/discovery.py +105 -0
- python_platform/events/errors.py +48 -0
- python_platform/events/runtime.py +192 -0
- python_platform/fastapi/__init__.py +49 -0
- python_platform/fastapi/action.py +175 -0
- python_platform/fastapi/adapter.py +381 -0
- python_platform/fastapi/application_services.py +647 -0
- python_platform/fastapi/background.py +42 -0
- python_platform/fastapi/contracts.py +278 -0
- python_platform/fastapi/errors.py +32 -0
- python_platform/fastapi/filters.py +111 -0
- python_platform/fastapi/health.py +44 -0
- python_platform/fastapi/http.py +55 -0
- python_platform/fastapi/http_router.py +212 -0
- python_platform/fastapi/manual_action.py +105 -0
- python_platform/fastapi/middleware.py +93 -0
- python_platform/fastapi/parameters.py +97 -0
- python_platform/fastapi/realtime/__init__.py +13 -0
- python_platform/fastapi/realtime/authentication.py +181 -0
- python_platform/fastapi/realtime/connection.py +166 -0
- python_platform/fastapi/realtime/module.py +41 -0
- python_platform/fastapi/realtime/options.py +50 -0
- python_platform/fastapi/realtime/runtime.py +423 -0
- python_platform/fastapi/request_context.py +244 -0
- python_platform/fastapi/route_integrity.py +88 -0
- python_platform/fastapi/routing.py +410 -0
- python_platform/fastapi/server.py +181 -0
- python_platform/fastapi/settings.py +40 -0
- python_platform/fastapi/tracing.py +62 -0
- python_platform/fastapi/transfer.py +128 -0
- python_platform/fastapi/upload_limits.py +63 -0
- python_platform/fastapi/uploads.py +94 -0
- python_platform/hosted_services/__init__.py +29 -0
- python_platform/hosted_services/bridge.py +420 -0
- python_platform/hosted_services/catalog.py +259 -0
- python_platform/hosted_services/contracts.py +55 -0
- python_platform/hosted_services/errors.py +53 -0
- python_platform/hosted_services/options.py +17 -0
- python_platform/hosted_services/runtime.py +267 -0
- python_platform/hosted_services/state.py +40 -0
- python_platform/hosting/__init__.py +4 -0
- python_platform/hosting/instance.py +40 -0
- python_platform/identity/__init__.py +73 -0
- python_platform/identity/application.py +287 -0
- python_platform/identity/contracts.py +283 -0
- python_platform/identity/errors.py +28 -0
- python_platform/identity/http_api.py +90 -0
- python_platform/identity/module.py +46 -0
- python_platform/identity/passwords.py +34 -0
- python_platform/identity/permissions.py +14 -0
- python_platform/identity/services.py +108 -0
- python_platform/identity/sqlalchemy/__init__.py +5 -0
- python_platform/identity/sqlalchemy/migrations/0001_platform_identity.py +151 -0
- python_platform/identity/sqlalchemy/migrations/0002_physical_delete.py +42 -0
- python_platform/identity/sqlalchemy/migrations/__init__.py +1 -0
- python_platform/identity/sqlalchemy/models.py +85 -0
- python_platform/identity/sqlalchemy/module.py +62 -0
- python_platform/identity/sqlalchemy/stores.py +526 -0
- python_platform/identity/tokens.py +106 -0
- python_platform/invocation/__init__.py +3 -0
- python_platform/invocation/callables.py +171 -0
- python_platform/invocation/contracts.py +33 -0
- python_platform/invocation/entries.py +54 -0
- python_platform/invocation/function_runtime.py +48 -0
- python_platform/invocation/interception.py +184 -0
- python_platform/lifecycle/__init__.py +25 -0
- python_platform/lifecycle/composition.py +35 -0
- python_platform/lifecycle/context.py +31 -0
- python_platform/lifecycle/runtime.py +43 -0
- python_platform/lifecycle/state.py +20 -0
- python_platform/modularity/__init__.py +15 -0
- python_platform/modularity/contracts.py +90 -0
- python_platform/modularity/discovery.py +143 -0
- python_platform/modularity/graph.py +334 -0
- python_platform/modularity/registry.py +100 -0
- python_platform/modularity/selection.py +16 -0
- python_platform/notifications/__init__.py +19 -0
- python_platform/notifications/catalog.py +46 -0
- python_platform/notifications/contracts.py +107 -0
- python_platform/observability/__init__.py +5 -0
- python_platform/observability/context.py +43 -0
- python_platform/observability/export.py +73 -0
- python_platform/observability/formatting.py +89 -0
- python_platform/observability/logging.py +118 -0
- python_platform/observability/options.py +45 -0
- python_platform/observability/tracing.py +80 -0
- python_platform/options/__init__.py +19 -0
- python_platform/options/aliases.py +331 -0
- python_platform/options/contribution.py +62 -0
- python_platform/options/immutability.py +48 -0
- python_platform/options/input_keys.py +214 -0
- python_platform/options/issues.py +335 -0
- python_platform/options/models.py +114 -0
- python_platform/options/registry.py +280 -0
- python_platform/options/schema.py +488 -0
- python_platform/options/validation.py +120 -0
- python_platform/py.typed +0 -0
- python_platform/realtime/__init__.py +12 -0
- python_platform/realtime/contracts.py +28 -0
- python_platform/realtime/diagnostics.py +37 -0
- python_platform/realtime/messages.py +113 -0
- python_platform/redis/__init__.py +6 -0
- python_platform/redis/distributed_lock.py +212 -0
- python_platform/redis/lease_lock.py +36 -0
- python_platform/redis/module.py +50 -0
- python_platform/redis/notification_runtime.py +182 -0
- python_platform/redis/notifications.py +25 -0
- python_platform/redis/options.py +35 -0
- python_platform/redis/runtime.py +116 -0
- python_platform/services/__init__.py +39 -0
- python_platform/services/application_bindings.py +221 -0
- python_platform/services/arbitration.py +381 -0
- python_platform/services/binding.py +102 -0
- python_platform/services/contribution.py +438 -0
- python_platform/services/convention.py +292 -0
- python_platform/services/convention_contracts.py +94 -0
- python_platform/services/exposure.py +23 -0
- python_platform/services/framework_provider.py +178 -0
- python_platform/services/native_graph.py +172 -0
- python_platform/services/provider.py +204 -0
- python_platform/services/registration.py +101 -0
- python_platform/services/runtime.py +298 -0
- python_platform/settings/__init__.py +30 -0
- python_platform/settings/application.py +95 -0
- python_platform/settings/binding.py +33 -0
- python_platform/settings/catalog.py +121 -0
- python_platform/settings/changes.py +14 -0
- python_platform/settings/contracts.py +115 -0
- python_platform/settings/definition_discovery.py +71 -0
- python_platform/settings/definitions.py +41 -0
- python_platform/settings/errors.py +22 -0
- python_platform/settings/handlers.py +43 -0
- python_platform/settings/management.py +57 -0
- python_platform/settings/manager.py +89 -0
- python_platform/settings/module.py +7 -0
- python_platform/settings/notifications.py +39 -0
- python_platform/settings/permissions.py +14 -0
- python_platform/settings/provider.py +74 -0
- python_platform/settings/refresh.py +140 -0
- python_platform/settings/refresh_module.py +45 -0
- python_platform/settings/sqlalchemy/__init__.py +5 -0
- python_platform/settings/sqlalchemy/migrations/0001_platform_settings.py +31 -0
- python_platform/settings/sqlalchemy/migrations/0002_physical_delete.py +32 -0
- python_platform/settings/sqlalchemy/migrations/0003_version_tokens.py +39 -0
- python_platform/settings/sqlalchemy/migrations/__init__.py +1 -0
- python_platform/settings/sqlalchemy/models.py +36 -0
- python_platform/settings/sqlalchemy/module.py +36 -0
- python_platform/settings/sqlalchemy/store.py +86 -0
- python_platform/settings/store.py +16 -0
- python_platform/settings/values.py +39 -0
- python_platform/sqlalchemy/__init__.py +51 -0
- python_platform/sqlalchemy/alembic_runtime/__init__.py +1 -0
- python_platform/sqlalchemy/alembic_runtime/env.py +27 -0
- python_platform/sqlalchemy/alembic_runtime/script.py.mako +14 -0
- python_platform/sqlalchemy/auditing.py +48 -0
- python_platform/sqlalchemy/errors.py +85 -0
- python_platform/sqlalchemy/metadata.py +538 -0
- python_platform/sqlalchemy/migration.py +346 -0
- python_platform/sqlalchemy/module.py +48 -0
- python_platform/sqlalchemy/module_migration.py +148 -0
- python_platform/sqlalchemy/options.py +66 -0
- python_platform/sqlalchemy/repository.py +33 -0
- python_platform/sqlalchemy/runtime.py +85 -0
- python_platform/sqlalchemy/session_provider.py +45 -0
- python_platform/sqlalchemy/unit_of_work.py +97 -0
- python_platform/testing/__init__.py +5 -0
- python_platform/testing/runtime.py +112 -0
- python_platform/unit_of_work/__init__.py +14 -0
- python_platform/unit_of_work/contracts.py +223 -0
- python_platform/unit_of_work/errors.py +27 -0
- python_platform/unit_of_work/manager.py +210 -0
- python_platform/unit_of_work/options.py +92 -0
- python_platform-0.1.1.dist-info/METADATA +122 -0
- python_platform-0.1.1.dist-info/RECORD +344 -0
- python_platform-0.1.1.dist-info/WHEEL +4 -0
- python_platform-0.1.1.dist-info/entry_points.txt +9 -0
- python_platform-0.1.1.dist-info/licenses/LICENSE +7 -0
- python_platform-0.1.1.dist-info/licenses/src/python_platform/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt +21 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"""受 Module-owned metadata 控制且完整可诊断的 Convention discovery。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from typing import cast
|
|
8
|
+
|
|
9
|
+
from dishka import Provider, Scope
|
|
10
|
+
|
|
11
|
+
from ..application_services.catalog import _DiscoveredApplicationService
|
|
12
|
+
from ..application_services.contracts import (
|
|
13
|
+
_APPLICATION_SERVICE_DEFINITION_ATTRIBUTE,
|
|
14
|
+
ApplicationService,
|
|
15
|
+
_ApplicationServiceDefinition,
|
|
16
|
+
)
|
|
17
|
+
from ..application_services.contracts import (
|
|
18
|
+
_definition_for as _application_service_definition,
|
|
19
|
+
)
|
|
20
|
+
from ..application_services.errors import ApplicationServiceDefinitionError
|
|
21
|
+
from ..diagnostics import SourceLocation
|
|
22
|
+
from ..errors import ConventionScanError, InvalidConventionDefinitionError
|
|
23
|
+
from ..modularity import ModuleKey, ModuleRegistry
|
|
24
|
+
from ..modularity.discovery import _DiscoveredType
|
|
25
|
+
from .arbitration import _RegistrationDraft
|
|
26
|
+
from .contribution import ServiceContributionRegistry
|
|
27
|
+
from .convention_contracts import (
|
|
28
|
+
_SERVICE_DEFINITION_ATTRIBUTE,
|
|
29
|
+
ConventionalService,
|
|
30
|
+
ConventionCandidate,
|
|
31
|
+
ConventionCandidateDecision,
|
|
32
|
+
ConventionDiscoveryKind,
|
|
33
|
+
ScopedDependency,
|
|
34
|
+
SingletonDependency,
|
|
35
|
+
TransientDependency,
|
|
36
|
+
_ServiceDefinition,
|
|
37
|
+
)
|
|
38
|
+
from .exposure import _business_interfaces
|
|
39
|
+
from .registration import RegistrationDecision, RegistrationKind
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class _ConventionScanner:
|
|
43
|
+
"""拥有一次 Application scan 的顺序、去重状态和 candidate diagnostics。"""
|
|
44
|
+
|
|
45
|
+
__slots__ = (
|
|
46
|
+
"_application_services",
|
|
47
|
+
"_contributions",
|
|
48
|
+
"_discoveries",
|
|
49
|
+
"_event_handler_scopes",
|
|
50
|
+
"_lifetime_conflicts",
|
|
51
|
+
"_records",
|
|
52
|
+
"_registry",
|
|
53
|
+
"_scan_packages",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
registry: ModuleRegistry,
|
|
59
|
+
contributions: ServiceContributionRegistry,
|
|
60
|
+
scan_packages: Mapping[ModuleKey, tuple[str, ...]],
|
|
61
|
+
discoveries: tuple[_DiscoveredType, ...],
|
|
62
|
+
event_handler_scopes: Mapping[type[object], Scope],
|
|
63
|
+
) -> None:
|
|
64
|
+
self._discoveries = discoveries
|
|
65
|
+
self._event_handler_scopes = event_handler_scopes
|
|
66
|
+
self._registry = registry
|
|
67
|
+
self._contributions = contributions
|
|
68
|
+
self._scan_packages = scan_packages
|
|
69
|
+
self._records: list[ConventionCandidate] = []
|
|
70
|
+
self._application_services: list[_DiscoveredApplicationService] = []
|
|
71
|
+
self._lifetime_conflicts: set[type[object]] = set()
|
|
72
|
+
|
|
73
|
+
def validate_lifetimes(self, drafts: tuple[_RegistrationDraft, ...]) -> None:
|
|
74
|
+
for draft in drafts:
|
|
75
|
+
if (
|
|
76
|
+
draft.factory is not None
|
|
77
|
+
and isinstance(draft.factory.source, type)
|
|
78
|
+
and draft.factory.source in self._lifetime_conflicts
|
|
79
|
+
and draft.contribution.kind is RegistrationKind.CONVENTION
|
|
80
|
+
and draft.decision is RegistrationDecision.ACCEPTED
|
|
81
|
+
):
|
|
82
|
+
candidate = draft.factory.source
|
|
83
|
+
raise InvalidConventionDefinitionError(
|
|
84
|
+
symbol=f"{candidate.__module__}.{candidate.__qualname__}",
|
|
85
|
+
reason="conflicting lifetime markers require explicit service metadata",
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def discover(self) -> tuple[ConventionCandidate, ...]:
|
|
89
|
+
for descriptor in self._registry.dependency_order:
|
|
90
|
+
if descriptor.module_type.scan_packages != self._scan_packages[descriptor.key]:
|
|
91
|
+
raise ConventionScanError(
|
|
92
|
+
owner=descriptor.key,
|
|
93
|
+
package=None,
|
|
94
|
+
source=descriptor.declaration_source,
|
|
95
|
+
reason="scan_packages metadata was mutated after the Application snapshot",
|
|
96
|
+
original_error=None,
|
|
97
|
+
)
|
|
98
|
+
seen: dict[ModuleKey, set[type[object]]] = {}
|
|
99
|
+
for discovery in self._discoveries:
|
|
100
|
+
self._record_candidate(discovery, seen.setdefault(discovery.owner, set()))
|
|
101
|
+
return tuple(self._records)
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def application_services(self) -> tuple[_DiscoveredApplicationService, ...]:
|
|
105
|
+
return tuple(self._application_services)
|
|
106
|
+
|
|
107
|
+
def _record_candidate(self, discovery: _DiscoveredType, seen_types: set[type[object]]) -> None:
|
|
108
|
+
candidate = discovery.candidate
|
|
109
|
+
source = discovery.source
|
|
110
|
+
owner = discovery.owner
|
|
111
|
+
package_name = discovery.package
|
|
112
|
+
definition, application_definition, discovered_by, reason = self._definition(candidate)
|
|
113
|
+
if candidate in seen_types:
|
|
114
|
+
self._append_record(
|
|
115
|
+
owner,
|
|
116
|
+
package_name,
|
|
117
|
+
source,
|
|
118
|
+
discovered_by,
|
|
119
|
+
ConventionCandidateDecision.DUPLICATE,
|
|
120
|
+
"candidate already interpreted from an earlier scan package",
|
|
121
|
+
)
|
|
122
|
+
return
|
|
123
|
+
seen_types.add(candidate)
|
|
124
|
+
if definition is None:
|
|
125
|
+
self._append_record(
|
|
126
|
+
owner,
|
|
127
|
+
package_name,
|
|
128
|
+
source,
|
|
129
|
+
discovered_by,
|
|
130
|
+
ConventionCandidateDecision.REJECTED,
|
|
131
|
+
reason,
|
|
132
|
+
)
|
|
133
|
+
return
|
|
134
|
+
provider = Provider(scope=definition.scope)
|
|
135
|
+
provider.provide(
|
|
136
|
+
candidate,
|
|
137
|
+
provides=definition.provides if definition.provides is not None else candidate,
|
|
138
|
+
scope=definition.scope,
|
|
139
|
+
cache=definition.cache,
|
|
140
|
+
)
|
|
141
|
+
if definition.provides is None:
|
|
142
|
+
for interface in _business_interfaces(candidate):
|
|
143
|
+
provider.alias(candidate, provides=interface, cache=False)
|
|
144
|
+
self._contributions.add_convention(
|
|
145
|
+
provider=provider,
|
|
146
|
+
owner=owner,
|
|
147
|
+
source=source,
|
|
148
|
+
reason=reason,
|
|
149
|
+
)
|
|
150
|
+
if application_definition is not None:
|
|
151
|
+
# 分层模块的公开契约由实际扫描它的 Module 拥有;实现 DI 的 owner 仍由上面的
|
|
152
|
+
# contribution 保留。HTTP 因此可只依赖 Contracts,不反向引用应用实现。
|
|
153
|
+
declarations = {
|
|
154
|
+
item.owner: item
|
|
155
|
+
for item in self._discoveries
|
|
156
|
+
if item.candidate is application_definition.contract
|
|
157
|
+
}
|
|
158
|
+
if len(declarations) > 1:
|
|
159
|
+
raise ApplicationServiceDefinitionError(
|
|
160
|
+
symbol=str(application_definition.contract),
|
|
161
|
+
reason="application service contract is scanned by multiple Modules",
|
|
162
|
+
)
|
|
163
|
+
declaration = next(iter(declarations.values()), discovery)
|
|
164
|
+
self._application_services.append(
|
|
165
|
+
_DiscoveredApplicationService(
|
|
166
|
+
service_type=cast(type[ApplicationService], candidate),
|
|
167
|
+
definition=application_definition,
|
|
168
|
+
owner=declaration.owner,
|
|
169
|
+
source=declaration.source,
|
|
170
|
+
declaration_index=len(self._application_services),
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
self._append_record(
|
|
174
|
+
owner,
|
|
175
|
+
package_name,
|
|
176
|
+
source,
|
|
177
|
+
discovered_by,
|
|
178
|
+
ConventionCandidateDecision.ACCEPTED,
|
|
179
|
+
reason,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def _append_record(
|
|
183
|
+
self,
|
|
184
|
+
owner: ModuleKey,
|
|
185
|
+
package: str,
|
|
186
|
+
source: SourceLocation,
|
|
187
|
+
discovered_by: ConventionDiscoveryKind,
|
|
188
|
+
decision: ConventionCandidateDecision,
|
|
189
|
+
reason: str,
|
|
190
|
+
) -> None:
|
|
191
|
+
self._records.append(
|
|
192
|
+
ConventionCandidate(
|
|
193
|
+
owner=owner,
|
|
194
|
+
package=package,
|
|
195
|
+
source=source,
|
|
196
|
+
discovered_by=discovered_by,
|
|
197
|
+
decision=decision,
|
|
198
|
+
reason=reason,
|
|
199
|
+
ordinal=len(self._records),
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def _definition(
|
|
204
|
+
self,
|
|
205
|
+
candidate: type[object],
|
|
206
|
+
) -> tuple[
|
|
207
|
+
_ServiceDefinition | None,
|
|
208
|
+
_ApplicationServiceDefinition | None,
|
|
209
|
+
ConventionDiscoveryKind,
|
|
210
|
+
str,
|
|
211
|
+
]:
|
|
212
|
+
application_definition = _application_service_definition(candidate)
|
|
213
|
+
if application_definition is not None:
|
|
214
|
+
if _SERVICE_DEFINITION_ATTRIBUTE in candidate.__dict__:
|
|
215
|
+
raise ApplicationServiceDefinitionError(
|
|
216
|
+
symbol=f"{candidate.__module__}.{candidate.__qualname__}",
|
|
217
|
+
reason="application_service and service metadata cannot be combined",
|
|
218
|
+
)
|
|
219
|
+
decorated = _APPLICATION_SERVICE_DEFINITION_ATTRIBUTE in candidate.__dict__
|
|
220
|
+
discovered_by = (
|
|
221
|
+
ConventionDiscoveryKind.APPLICATION_SERVICE_DECORATOR
|
|
222
|
+
if decorated
|
|
223
|
+
else ConventionDiscoveryKind.FRAMEWORK_MARKER
|
|
224
|
+
)
|
|
225
|
+
reason = (
|
|
226
|
+
"accepted from immutable application_service decorator metadata"
|
|
227
|
+
if decorated
|
|
228
|
+
else "accepted from unique inherited ApplicationService contract"
|
|
229
|
+
)
|
|
230
|
+
return (
|
|
231
|
+
_ServiceDefinition(
|
|
232
|
+
provides=application_definition.contract or candidate,
|
|
233
|
+
scope=Scope.ACTION,
|
|
234
|
+
),
|
|
235
|
+
application_definition,
|
|
236
|
+
discovered_by,
|
|
237
|
+
reason,
|
|
238
|
+
)
|
|
239
|
+
metadata = candidate.__dict__.get(_SERVICE_DEFINITION_ATTRIBUTE)
|
|
240
|
+
if metadata is not None:
|
|
241
|
+
if not isinstance(metadata, _ServiceDefinition):
|
|
242
|
+
raise InvalidConventionDefinitionError(
|
|
243
|
+
symbol=f"{candidate.__module__}.{candidate.__qualname__}",
|
|
244
|
+
reason="service decorator metadata has an invalid runtime shape",
|
|
245
|
+
)
|
|
246
|
+
return (
|
|
247
|
+
metadata,
|
|
248
|
+
None,
|
|
249
|
+
ConventionDiscoveryKind.DECORATOR_METADATA,
|
|
250
|
+
"accepted from immutable service decorator metadata",
|
|
251
|
+
)
|
|
252
|
+
if candidate in self._event_handler_scopes:
|
|
253
|
+
return (
|
|
254
|
+
_ServiceDefinition(provides=candidate, scope=self._event_handler_scopes[candidate]),
|
|
255
|
+
None,
|
|
256
|
+
ConventionDiscoveryKind.DECORATOR_METADATA,
|
|
257
|
+
"accepted from immutable local_event_handler metadata",
|
|
258
|
+
)
|
|
259
|
+
lifetimes = tuple(
|
|
260
|
+
(marker, scope, cache)
|
|
261
|
+
for marker, scope, cache in (
|
|
262
|
+
(SingletonDependency, Scope.APP, True),
|
|
263
|
+
(ScopedDependency, Scope.REQUEST, True),
|
|
264
|
+
(TransientDependency, Scope.REQUEST, False),
|
|
265
|
+
)
|
|
266
|
+
if candidate is not marker and issubclass(candidate, marker)
|
|
267
|
+
)
|
|
268
|
+
if lifetimes and not inspect.isabstract(candidate):
|
|
269
|
+
if len(lifetimes) != 1:
|
|
270
|
+
# 冲突先挂起到统一仲裁后;若约定 factory 胜出,容器构建前必定拒绝。
|
|
271
|
+
# 显式覆盖链可以让它退让,扫描阶段不自行挑选有效注册。
|
|
272
|
+
self._lifetime_conflicts.add(candidate)
|
|
273
|
+
marker, scope, cache = lifetimes[0]
|
|
274
|
+
return (
|
|
275
|
+
_ServiceDefinition(provides=None, scope=scope, cache=cache),
|
|
276
|
+
None,
|
|
277
|
+
ConventionDiscoveryKind.FRAMEWORK_MARKER,
|
|
278
|
+
f"accepted from {marker.__name__} marker",
|
|
279
|
+
)
|
|
280
|
+
if issubclass(candidate, ConventionalService) and candidate is not ConventionalService:
|
|
281
|
+
return (
|
|
282
|
+
_ServiceDefinition(provides=candidate, scope=Scope.APP),
|
|
283
|
+
None,
|
|
284
|
+
ConventionDiscoveryKind.FRAMEWORK_MARKER,
|
|
285
|
+
"accepted from ConventionalService marker",
|
|
286
|
+
)
|
|
287
|
+
return (
|
|
288
|
+
None,
|
|
289
|
+
None,
|
|
290
|
+
ConventionDiscoveryKind.NONE,
|
|
291
|
+
"rejected because no service decorator metadata or framework marker exists",
|
|
292
|
+
)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Convention metadata、candidate diagnostics 与显式 marker contract。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import TypeVar
|
|
9
|
+
|
|
10
|
+
from dishka import BaseScope, Scope
|
|
11
|
+
|
|
12
|
+
from ..diagnostics import SourceLocation
|
|
13
|
+
from ..errors import InvalidConventionDefinitionError
|
|
14
|
+
from ..modularity import ModuleKey
|
|
15
|
+
from .registration import SUPPORTED_SCOPE_LABEL, SUPPORTED_SCOPES
|
|
16
|
+
|
|
17
|
+
_SERVICE_DEFINITION_ATTRIBUTE = "__python_platform_service_definition__"
|
|
18
|
+
_TService = TypeVar("_TService")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ConventionDiscoveryKind(str, Enum):
|
|
22
|
+
DECORATOR_METADATA = "decorator_metadata"
|
|
23
|
+
FRAMEWORK_MARKER = "framework_marker"
|
|
24
|
+
APPLICATION_SERVICE_DECORATOR = "application_service_decorator"
|
|
25
|
+
NONE = "none"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ConventionCandidateDecision(str, Enum):
|
|
29
|
+
ACCEPTED = "accepted"
|
|
30
|
+
REJECTED = "rejected"
|
|
31
|
+
DUPLICATE = "duplicate"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True, slots=True)
|
|
35
|
+
class ConventionCandidate:
|
|
36
|
+
owner: ModuleKey
|
|
37
|
+
package: str
|
|
38
|
+
source: SourceLocation
|
|
39
|
+
discovered_by: ConventionDiscoveryKind
|
|
40
|
+
decision: ConventionCandidateDecision
|
|
41
|
+
reason: str
|
|
42
|
+
ordinal: int
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True, slots=True)
|
|
46
|
+
class _ServiceDefinition:
|
|
47
|
+
provides: object | None
|
|
48
|
+
scope: BaseScope
|
|
49
|
+
cache: bool = True
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ConventionalService:
|
|
53
|
+
"""只表达“按自身类型注册”的 Convention marker,不承载容器行为。"""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class SingletonDependency:
|
|
57
|
+
"""约定 APP 缓存生命周期;实例所有权仍属于 Application 的 Dishka 容器。"""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ScopedDependency:
|
|
61
|
+
"""约定 REQUEST 缓存生命周期,不允许越过原生作用域访问。"""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class TransientDependency:
|
|
65
|
+
"""约定 REQUEST 非缓存生命周期;不缓存不等于解除作用域约束。"""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def service(
|
|
69
|
+
*,
|
|
70
|
+
provides: object | None = None,
|
|
71
|
+
scope: BaseScope = Scope.APP,
|
|
72
|
+
) -> Callable[[type[_TService]], type[_TService]]:
|
|
73
|
+
"""附着 immutable definition metadata;真正解释结果仍归每个 Application。"""
|
|
74
|
+
if scope not in SUPPORTED_SCOPES:
|
|
75
|
+
raise InvalidConventionDefinitionError(
|
|
76
|
+
symbol="<decorator>", reason=f"convention scope must be {SUPPORTED_SCOPE_LABEL}"
|
|
77
|
+
)
|
|
78
|
+
definition = _ServiceDefinition(provides=provides, scope=scope)
|
|
79
|
+
|
|
80
|
+
def decorate(service_type: type[_TService]) -> type[_TService]:
|
|
81
|
+
if not isinstance(service_type, type):
|
|
82
|
+
raise InvalidConventionDefinitionError(
|
|
83
|
+
symbol=type(service_type).__qualname__,
|
|
84
|
+
reason="service decorator can only target a class",
|
|
85
|
+
)
|
|
86
|
+
if _SERVICE_DEFINITION_ATTRIBUTE in service_type.__dict__:
|
|
87
|
+
raise InvalidConventionDefinitionError(
|
|
88
|
+
symbol=f"{service_type.__module__}.{service_type.__qualname__}",
|
|
89
|
+
reason="service decorator metadata is already declared",
|
|
90
|
+
)
|
|
91
|
+
setattr(service_type, _SERVICE_DEFINITION_ATTRIBUTE, definition)
|
|
92
|
+
return service_type
|
|
93
|
+
|
|
94
|
+
return decorate
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""从显式继承关系解释业务接口,不按名称或结构相似度猜测注册关系。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
import sys
|
|
7
|
+
from abc import ABC
|
|
8
|
+
from typing import Generic, Protocol
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _business_interfaces(candidate: type[object]) -> tuple[type[object], ...]:
|
|
12
|
+
# 只接受名义继承的 Protocol/ABC;实现类和标准库角色不会成为业务契约。
|
|
13
|
+
interfaces = tuple(
|
|
14
|
+
base
|
|
15
|
+
for base in candidate.__mro__[1:]
|
|
16
|
+
if base not in (ABC, Protocol, Generic)
|
|
17
|
+
and base.__module__.partition(".")[0] not in sys.stdlib_module_names
|
|
18
|
+
and (getattr(base, "_is_protocol", False) or inspect.isabstract(base))
|
|
19
|
+
)
|
|
20
|
+
# 派生契约已经表达父契约的要求;自动契约选择只看最具体的候选。
|
|
21
|
+
return tuple(
|
|
22
|
+
base for base in interfaces if not any(base in other.__mro__[1:] for other in interfaces)
|
|
23
|
+
)
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""组装平台自有依赖与 scoped proxy;业务贡献仍由原生 Dishka 管理。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
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
|
+
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
|
+
from ..modularity import ModuleRegistry
|
|
29
|
+
from ..notifications import NotificationCatalog
|
|
30
|
+
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
|
+
|
|
35
|
+
|
|
36
|
+
def _framework_provider(
|
|
37
|
+
*,
|
|
38
|
+
registry: ModuleRegistry,
|
|
39
|
+
has_unit_of_work_factory: bool,
|
|
40
|
+
entry_interceptors: _EntryInterceptionCatalog,
|
|
41
|
+
configuration: ConfigurationRoot,
|
|
42
|
+
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
|
+
) -> Provider:
|
|
56
|
+
"""框架自身 contract 直接进入 Dishka;不写入业务 ServiceCatalog 第二清单。"""
|
|
57
|
+
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
|
+
provider.provide(lambda: registry, provides=ModuleRegistry, scope=Scope.APP)
|
|
64
|
+
provider.provide(lambda: configuration, provides=ConfigurationRoot, scope=Scope.APP)
|
|
65
|
+
provider.provide(lambda: options, provides=OptionsSnapshot, scope=Scope.APP)
|
|
66
|
+
# Dishka 原生 context binding 直接发布已冻结实例,保持每个 Application 的唯一 snapshot。
|
|
67
|
+
for model_type in options.values:
|
|
68
|
+
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
|
+
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)
|