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,55 @@
|
|
|
1
|
+
"""主 Host 拥有的服务生命周期契约;连接恢复由服务实现负责。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
9
|
+
|
|
10
|
+
from .errors import HostedServiceDefinitionError
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from ..lifecycle import ShutdownReason
|
|
14
|
+
from .bridge import HostedServiceContext
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class HostedService(ABC):
|
|
18
|
+
"""APP 单例;start 返回即启动成功,stop 必须等待自身资源退出。"""
|
|
19
|
+
|
|
20
|
+
run_in_background_processes: ClassVar[bool] = False
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
async def start(self, context: HostedServiceContext) -> None:
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def stop(self, reason: ShutdownReason) -> None:
|
|
28
|
+
raise NotImplementedError
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class HostedServiceStatus(str, Enum):
|
|
32
|
+
STARTING = "starting"
|
|
33
|
+
RUNNING = "running"
|
|
34
|
+
STOPPING = "stopping"
|
|
35
|
+
STOPPED = "stopped"
|
|
36
|
+
FAILED = "failed"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _validate_service_type(candidate: type[HostedService]) -> None:
|
|
40
|
+
if not isinstance(candidate, type) or not issubclass(candidate, HostedService):
|
|
41
|
+
raise HostedServiceDefinitionError(
|
|
42
|
+
service=repr(candidate), reason="hosted_services must contain HostedService types"
|
|
43
|
+
)
|
|
44
|
+
name = f"{candidate.__module__}.{candidate.__qualname__}"
|
|
45
|
+
if not isinstance(candidate.run_in_background_processes, bool):
|
|
46
|
+
raise HostedServiceDefinitionError(
|
|
47
|
+
service=name, reason="run_in_background_processes must be bool"
|
|
48
|
+
)
|
|
49
|
+
if inspect.isabstract(candidate):
|
|
50
|
+
raise HostedServiceDefinitionError(service=name, reason="service type must be concrete")
|
|
51
|
+
for operation in ("start", "stop"):
|
|
52
|
+
if not inspect.iscoroutinefunction(getattr(candidate, operation, None)):
|
|
53
|
+
raise HostedServiceDefinitionError(
|
|
54
|
+
service=name, reason=f"{operation} must use async def"
|
|
55
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Hosted Service definition、lifecycle 与 bridge 的脱敏错误边界。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..errors.base import FrameworkError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HostedServiceDefinitionError(FrameworkError):
|
|
9
|
+
def __init__(self, *, service: str, reason: str) -> None:
|
|
10
|
+
self.service = service
|
|
11
|
+
self.reason = reason
|
|
12
|
+
super().__init__(f"Invalid Hosted Service {service!r}: {reason}")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class HostedServiceContractError(FrameworkError):
|
|
16
|
+
"""只发布 Service identity、操作与稳定错误类型,不保留 provider 异常正文。"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, *, service: str, operation: str, error_type: str) -> None:
|
|
19
|
+
self.service = service
|
|
20
|
+
self.operation = operation
|
|
21
|
+
self.error_type = error_type
|
|
22
|
+
super().__init__(
|
|
23
|
+
f"Hosted Service {service!r} contract rejected {operation} with {error_type}"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class HostedServiceLifecycleError(FrameworkError):
|
|
28
|
+
"""Service 第三方异常在此终止传播,避免设备或 SDK 文本进入终态。"""
|
|
29
|
+
|
|
30
|
+
failure_id = None
|
|
31
|
+
stage = None
|
|
32
|
+
dependency_path: tuple[object, ...] = ()
|
|
33
|
+
|
|
34
|
+
def __init__(self, *, service: str, operation: str, error_type: str) -> None:
|
|
35
|
+
self.service = service
|
|
36
|
+
self.operation = operation
|
|
37
|
+
self.error_type = error_type
|
|
38
|
+
super().__init__(f"Hosted Service {service!r} {operation} failed with {error_type}")
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def original_error(self) -> BaseException:
|
|
42
|
+
# 与 ApplicationStartError 的统一 primary shape 对齐,但绝不返回第三方异常。
|
|
43
|
+
return self
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class HostedServiceInvocationRejectedError(FrameworkError):
|
|
47
|
+
def __init__(self, *, service: str, operation: str, error_type: str) -> None:
|
|
48
|
+
self.service = service
|
|
49
|
+
self.operation = operation
|
|
50
|
+
self.error_type = error_type
|
|
51
|
+
super().__init__(
|
|
52
|
+
f"Hosted Service {service!r} invocation {operation} rejected with {error_type}"
|
|
53
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Hosted Service 的 Host-owned 容量与 lifecycle deadline。"""
|
|
2
|
+
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
|
|
5
|
+
from pydantic import ConfigDict, Field
|
|
6
|
+
|
|
7
|
+
from ..options import BaseOptions
|
|
8
|
+
|
|
9
|
+
HOSTED_SERVICE_OPTIONS_SECTION = "hosted_service"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class HostedServiceOptions(BaseOptions):
|
|
13
|
+
model_config = ConfigDict(extra="forbid")
|
|
14
|
+
|
|
15
|
+
max_pending_invocations: int = Field(default=128, ge=1)
|
|
16
|
+
startup_timeout: timedelta = Field(default=timedelta(seconds=30), gt=timedelta(0))
|
|
17
|
+
shutdown_timeout: timedelta = Field(default=timedelta(seconds=30), gt=timedelta(0))
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"""Hosted Service resolution、bootstrap 与逆序 shutdown owner。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import Awaitable, Callable
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import cast
|
|
9
|
+
|
|
10
|
+
from dishka import AsyncContainer
|
|
11
|
+
|
|
12
|
+
from ..application_services import ApplicationServiceCatalog
|
|
13
|
+
from ..lifecycle import ApplicationState, ShutdownReason
|
|
14
|
+
from .bridge import HostedServiceContext, _HostedServiceBridge
|
|
15
|
+
from .catalog import HostedServiceCatalog, HostedServiceRegistration
|
|
16
|
+
from .contracts import HostedService, HostedServiceStatus
|
|
17
|
+
from .errors import HostedServiceDefinitionError, HostedServiceLifecycleError
|
|
18
|
+
from .options import HostedServiceOptions
|
|
19
|
+
from .state import ApplicationReadinessSnapshot, _HostedServiceStateOwner
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(slots=True)
|
|
23
|
+
class _HostedServiceEntry:
|
|
24
|
+
registration: HostedServiceRegistration
|
|
25
|
+
service: HostedService
|
|
26
|
+
context: HostedServiceContext
|
|
27
|
+
bridge: _HostedServiceBridge
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class _HostedServiceCoordinator:
|
|
31
|
+
"""单 Application 的 Service/bridge/task owner;不强制终止实现拥有的 OS thread。"""
|
|
32
|
+
|
|
33
|
+
__slots__ = (
|
|
34
|
+
"_application_service_catalog",
|
|
35
|
+
"_catalog",
|
|
36
|
+
"_container",
|
|
37
|
+
"_entries",
|
|
38
|
+
"_options",
|
|
39
|
+
"_registrations",
|
|
40
|
+
"_started",
|
|
41
|
+
"_state_getter",
|
|
42
|
+
"_state_owner",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
*,
|
|
48
|
+
catalog: HostedServiceCatalog,
|
|
49
|
+
options: HostedServiceOptions,
|
|
50
|
+
state_getter: Callable[[], ApplicationState],
|
|
51
|
+
) -> None:
|
|
52
|
+
self._catalog = catalog
|
|
53
|
+
self._options = options
|
|
54
|
+
self._state_getter = state_getter
|
|
55
|
+
self._registrations = catalog.registrations
|
|
56
|
+
self._state_owner = _HostedServiceStateOwner(self._registrations)
|
|
57
|
+
self._container: AsyncContainer | None = None
|
|
58
|
+
self._application_service_catalog: ApplicationServiceCatalog | None = None
|
|
59
|
+
self._entries: list[_HostedServiceEntry] = []
|
|
60
|
+
self._started = False
|
|
61
|
+
|
|
62
|
+
def attach_container(
|
|
63
|
+
self,
|
|
64
|
+
container: AsyncContainer,
|
|
65
|
+
application_service_catalog: ApplicationServiceCatalog,
|
|
66
|
+
) -> None:
|
|
67
|
+
if self._container is not None:
|
|
68
|
+
raise RuntimeError("Hosted Service coordinator container is already attached")
|
|
69
|
+
self._container = container
|
|
70
|
+
self._application_service_catalog = application_service_catalog
|
|
71
|
+
|
|
72
|
+
def readiness(self) -> ApplicationReadinessSnapshot:
|
|
73
|
+
return self._state_owner.snapshot(self._state_getter())
|
|
74
|
+
|
|
75
|
+
def select_child(self) -> None:
|
|
76
|
+
if self._started:
|
|
77
|
+
raise RuntimeError("Hosted Service process selection must precede start")
|
|
78
|
+
# 先按 build 冻结的声明选择;解析、bridge、readiness 与 stop 共用同一进程集合。
|
|
79
|
+
self._registrations = tuple(
|
|
80
|
+
item for item in self._catalog.registrations if item.run_in_background_processes
|
|
81
|
+
)
|
|
82
|
+
self._state_owner = _HostedServiceStateOwner(self._registrations)
|
|
83
|
+
|
|
84
|
+
async def start(self) -> None:
|
|
85
|
+
if self._started:
|
|
86
|
+
raise RuntimeError("Hosted Service coordinator is already started")
|
|
87
|
+
try:
|
|
88
|
+
self._catalog._assert_unchanged()
|
|
89
|
+
except HostedServiceDefinitionError as original_error:
|
|
90
|
+
raise HostedServiceLifecycleError(
|
|
91
|
+
service=original_error.service,
|
|
92
|
+
operation="metadata",
|
|
93
|
+
error_type=type(original_error).__name__,
|
|
94
|
+
) from None
|
|
95
|
+
container = self._container
|
|
96
|
+
application_service_catalog = self._application_service_catalog
|
|
97
|
+
if container is None or application_service_catalog is None:
|
|
98
|
+
raise RuntimeError("Hosted Service coordinator container is unavailable")
|
|
99
|
+
self._started = True
|
|
100
|
+
for registration in self._registrations:
|
|
101
|
+
self._state_owner.set_status(registration.name, HostedServiceStatus.STARTING)
|
|
102
|
+
try:
|
|
103
|
+
resolved = await container.get(registration.service_type)
|
|
104
|
+
except BaseException as original_error:
|
|
105
|
+
self._state_owner.set_status(registration.name, HostedServiceStatus.FAILED)
|
|
106
|
+
raise HostedServiceLifecycleError(
|
|
107
|
+
service=registration.name,
|
|
108
|
+
operation="resolve",
|
|
109
|
+
error_type=type(original_error).__name__,
|
|
110
|
+
) from None
|
|
111
|
+
if not isinstance(resolved, registration.service_type):
|
|
112
|
+
self._state_owner.set_status(registration.name, HostedServiceStatus.FAILED)
|
|
113
|
+
raise HostedServiceLifecycleError(
|
|
114
|
+
service=registration.name,
|
|
115
|
+
operation="resolve",
|
|
116
|
+
error_type="InvalidRuntimeInstance",
|
|
117
|
+
)
|
|
118
|
+
bridge = _HostedServiceBridge(
|
|
119
|
+
name=registration.name,
|
|
120
|
+
loop=asyncio.get_running_loop(),
|
|
121
|
+
container=container,
|
|
122
|
+
catalog=application_service_catalog,
|
|
123
|
+
limit=self._options.max_pending_invocations,
|
|
124
|
+
)
|
|
125
|
+
context = HostedServiceContext(registration.name, bridge)
|
|
126
|
+
entry = _HostedServiceEntry(registration, resolved, context, bridge)
|
|
127
|
+
self._entries.append(entry)
|
|
128
|
+
bridge.open()
|
|
129
|
+
await self._start_entry(entry)
|
|
130
|
+
|
|
131
|
+
def close_admission(self) -> None:
|
|
132
|
+
for entry in self._entries:
|
|
133
|
+
entry.bridge.close()
|
|
134
|
+
|
|
135
|
+
async def stop(
|
|
136
|
+
self,
|
|
137
|
+
reason: ShutdownReason,
|
|
138
|
+
) -> tuple[HostedServiceLifecycleError, ...]:
|
|
139
|
+
if not self._started and not self._entries:
|
|
140
|
+
return ()
|
|
141
|
+
self.close_admission()
|
|
142
|
+
failures: list[HostedServiceLifecycleError] = []
|
|
143
|
+
for entry in reversed(self._entries):
|
|
144
|
+
name = entry.registration.name
|
|
145
|
+
self._state_owner.set_status(name, HostedServiceStatus.STOPPING)
|
|
146
|
+
failure = await self._stop_entry(entry, reason)
|
|
147
|
+
if failure is not None:
|
|
148
|
+
failures.append(failure)
|
|
149
|
+
|
|
150
|
+
if self._entries:
|
|
151
|
+
await asyncio.gather(
|
|
152
|
+
*(
|
|
153
|
+
entry.bridge.drain(self._options.shutdown_timeout.total_seconds())
|
|
154
|
+
for entry in self._entries
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
failed_names = {failure.service for failure in failures}
|
|
158
|
+
for entry in self._entries:
|
|
159
|
+
name = entry.registration.name
|
|
160
|
+
self._state_owner.set_status(
|
|
161
|
+
name,
|
|
162
|
+
HostedServiceStatus.FAILED if name in failed_names else HostedServiceStatus.STOPPED,
|
|
163
|
+
)
|
|
164
|
+
self._started = False
|
|
165
|
+
return tuple(failures)
|
|
166
|
+
|
|
167
|
+
async def _start_entry(self, entry: _HostedServiceEntry) -> None:
|
|
168
|
+
name = entry.registration.name
|
|
169
|
+
callback = cast(
|
|
170
|
+
Callable[[HostedServiceContext], Awaitable[object]],
|
|
171
|
+
entry.service.start,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
async def invoke_start() -> object:
|
|
175
|
+
return await callback(entry.context)
|
|
176
|
+
|
|
177
|
+
start_task = asyncio.create_task(
|
|
178
|
+
invoke_start(),
|
|
179
|
+
name=f"python-platform-hosted-service-start:{name}",
|
|
180
|
+
)
|
|
181
|
+
try:
|
|
182
|
+
done, _ = await asyncio.wait(
|
|
183
|
+
(start_task,),
|
|
184
|
+
timeout=self._options.startup_timeout.total_seconds(),
|
|
185
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
186
|
+
)
|
|
187
|
+
except BaseException as original_error:
|
|
188
|
+
# coordinator 创建的 start task 必须由 coordinator 收口;否则取消外层
|
|
189
|
+
# Application.start 会留下仍在运行、却已失去 owner 的 SDK bootstrap。
|
|
190
|
+
start_task.cancel()
|
|
191
|
+
await asyncio.gather(start_task, return_exceptions=True)
|
|
192
|
+
self._state_owner.set_status(name, HostedServiceStatus.FAILED)
|
|
193
|
+
raise HostedServiceLifecycleError(
|
|
194
|
+
service=name,
|
|
195
|
+
operation="start",
|
|
196
|
+
error_type=type(original_error).__name__,
|
|
197
|
+
) from None
|
|
198
|
+
if start_task not in done:
|
|
199
|
+
start_task.cancel()
|
|
200
|
+
await asyncio.gather(start_task, return_exceptions=True)
|
|
201
|
+
self._state_owner.set_status(name, HostedServiceStatus.FAILED)
|
|
202
|
+
raise HostedServiceLifecycleError(
|
|
203
|
+
service=name, operation="start", error_type="TimeoutError"
|
|
204
|
+
)
|
|
205
|
+
try:
|
|
206
|
+
result = start_task.result()
|
|
207
|
+
except BaseException as original_error:
|
|
208
|
+
self._state_owner.set_status(name, HostedServiceStatus.FAILED)
|
|
209
|
+
raise HostedServiceLifecycleError(
|
|
210
|
+
service=name,
|
|
211
|
+
operation="start",
|
|
212
|
+
error_type=type(original_error).__name__,
|
|
213
|
+
) from None
|
|
214
|
+
if result is not None:
|
|
215
|
+
self._state_owner.set_status(name, HostedServiceStatus.FAILED)
|
|
216
|
+
raise HostedServiceLifecycleError(
|
|
217
|
+
service=name,
|
|
218
|
+
operation="start",
|
|
219
|
+
error_type="InvalidReturnValue",
|
|
220
|
+
)
|
|
221
|
+
self._state_owner.set_status(name, HostedServiceStatus.RUNNING)
|
|
222
|
+
|
|
223
|
+
async def _stop_entry(
|
|
224
|
+
self,
|
|
225
|
+
entry: _HostedServiceEntry,
|
|
226
|
+
reason: ShutdownReason,
|
|
227
|
+
) -> HostedServiceLifecycleError | None:
|
|
228
|
+
name = entry.registration.name
|
|
229
|
+
callback = cast(
|
|
230
|
+
Callable[[ShutdownReason], Awaitable[object]],
|
|
231
|
+
entry.service.stop,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
async def invoke_stop() -> object:
|
|
235
|
+
return await callback(reason)
|
|
236
|
+
|
|
237
|
+
stop_task = asyncio.create_task(
|
|
238
|
+
invoke_stop(), name=f"python-platform-hosted-service-stop:{name}"
|
|
239
|
+
)
|
|
240
|
+
done, _ = await asyncio.wait(
|
|
241
|
+
(stop_task,), timeout=self._options.shutdown_timeout.total_seconds()
|
|
242
|
+
)
|
|
243
|
+
timed_out = not done
|
|
244
|
+
if timed_out:
|
|
245
|
+
# 取消只是一项请求。实现可能在 finally 中异步释放 SDK 资源;完成前不能释放容器。
|
|
246
|
+
stop_task.cancel()
|
|
247
|
+
try:
|
|
248
|
+
result = await stop_task
|
|
249
|
+
except BaseException as original_error:
|
|
250
|
+
return HostedServiceLifecycleError(
|
|
251
|
+
service=name,
|
|
252
|
+
operation="stop",
|
|
253
|
+
error_type="TimeoutError"
|
|
254
|
+
if timed_out and isinstance(original_error, asyncio.CancelledError)
|
|
255
|
+
else type(original_error).__name__,
|
|
256
|
+
)
|
|
257
|
+
if timed_out:
|
|
258
|
+
return HostedServiceLifecycleError(
|
|
259
|
+
service=name, operation="stop", error_type="TimeoutError"
|
|
260
|
+
)
|
|
261
|
+
if result is not None:
|
|
262
|
+
return HostedServiceLifecycleError(
|
|
263
|
+
service=name,
|
|
264
|
+
operation="stop",
|
|
265
|
+
error_type="InvalidReturnValue",
|
|
266
|
+
)
|
|
267
|
+
return None
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Application 所属 loop 修改生命周期状态;公开快照不持有可变状态。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from ..lifecycle import ApplicationState
|
|
8
|
+
from .catalog import HostedServiceRegistration
|
|
9
|
+
from .contracts import HostedServiceStatus
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True, slots=True)
|
|
13
|
+
class HostedServiceSnapshot:
|
|
14
|
+
name: str
|
|
15
|
+
status: HostedServiceStatus
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True, slots=True)
|
|
19
|
+
class ApplicationReadinessSnapshot:
|
|
20
|
+
ready: bool
|
|
21
|
+
services: tuple[HostedServiceSnapshot, ...]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class _HostedServiceStateOwner:
|
|
25
|
+
def __init__(self, registrations: tuple[HostedServiceRegistration, ...]) -> None:
|
|
26
|
+
self._states = {item.name: HostedServiceStatus.STOPPED for item in registrations}
|
|
27
|
+
|
|
28
|
+
def set_status(self, name: str, status: HostedServiceStatus) -> None:
|
|
29
|
+
self._states[name] = status
|
|
30
|
+
|
|
31
|
+
def snapshot(self, application_state: ApplicationState) -> ApplicationReadinessSnapshot:
|
|
32
|
+
return ApplicationReadinessSnapshot(
|
|
33
|
+
# Module 已完成 runtime hook 时 Application 可能已为 RUNNING;全部服务
|
|
34
|
+
# start 返回之前仍不能报告启动完成,这不是服务自报的连接健康度。
|
|
35
|
+
ready=application_state is ApplicationState.RUNNING
|
|
36
|
+
and all(state is HostedServiceStatus.RUNNING for state in self._states.values()),
|
|
37
|
+
services=tuple(
|
|
38
|
+
HostedServiceSnapshot(name, state) for name, state in self._states.items()
|
|
39
|
+
),
|
|
40
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""同一实际项目目录和环境的进程位置;占用事实由操作系统锁决定。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from filelock import BaseFileLock, UnixFileLock, WindowsFileLock
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _instance_lock(project: Path, environment: str, position: str = "host") -> BaseFileLock:
|
|
13
|
+
# 锁放在解析后的项目下,避免相对路径、junction/symlink 或不同用户的临时目录分裂身份。
|
|
14
|
+
# environment/position 只参与摘要,不作为路径片段,且互相独立编码避免拼接碰撞。
|
|
15
|
+
identity = hashlib.sha256(repr((environment, position)).encode()).hexdigest()
|
|
16
|
+
path = project.resolve(strict=True) / ".python-platform" / "locks" / f"{identity}.lock"
|
|
17
|
+
return _native_lock(path)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _native_lock(path: Path) -> BaseFileLock:
|
|
21
|
+
path = _native_path(path)
|
|
22
|
+
lock_type = WindowsFileLock if sys.platform == "win32" else UnixFileLock
|
|
23
|
+
return lock_type(
|
|
24
|
+
path,
|
|
25
|
+
timeout=0,
|
|
26
|
+
fallback_to_soft=False,
|
|
27
|
+
preserve_lock_file=True,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _native_path(path: Path) -> Path:
|
|
32
|
+
# Windows Unicode 长路径语法不依赖进程 manifest/注册表;不 resolve 最后的锁文件,
|
|
33
|
+
# 保留 filelock 自身对 symlink/reparse point 的拒绝,实际项目目录已由调用方解析。
|
|
34
|
+
if sys.platform == "win32":
|
|
35
|
+
value = str(path)
|
|
36
|
+
if value.startswith("\\\\?\\"):
|
|
37
|
+
return path
|
|
38
|
+
return Path("\\\\?\\UNC\\" + value[2:] if value.startswith("\\\\") else "\\\\?\\" + value)
|
|
39
|
+
else:
|
|
40
|
+
return path
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from .contracts import (
|
|
2
|
+
IDENTITY_ROLES_MANAGE,
|
|
3
|
+
IDENTITY_USERS_MANAGE,
|
|
4
|
+
AuthenticationApplicationService,
|
|
5
|
+
CreateRoleCommand,
|
|
6
|
+
CreateUserCommand,
|
|
7
|
+
CurrentUserView,
|
|
8
|
+
IdentityAccessStore,
|
|
9
|
+
IdentityLoginStore,
|
|
10
|
+
IdentityManagementApplicationService,
|
|
11
|
+
IdentityOptions,
|
|
12
|
+
IdentityRepository,
|
|
13
|
+
IdentityRole,
|
|
14
|
+
IdentityUser,
|
|
15
|
+
LoginCommand,
|
|
16
|
+
RefreshRotationResult,
|
|
17
|
+
RefreshRotationStatus,
|
|
18
|
+
RefreshSession,
|
|
19
|
+
RefreshSessionStore,
|
|
20
|
+
RefreshTokenCommand,
|
|
21
|
+
RevokeTokenCommand,
|
|
22
|
+
RoleView,
|
|
23
|
+
SetRolePermissionsCommand,
|
|
24
|
+
SetUserRolesCommand,
|
|
25
|
+
TokenPair,
|
|
26
|
+
UserView,
|
|
27
|
+
)
|
|
28
|
+
from .errors import (
|
|
29
|
+
IdentityConflictError,
|
|
30
|
+
IdentityDefinitionError,
|
|
31
|
+
IdentityResourceNotFoundError,
|
|
32
|
+
InvalidCredentialsError,
|
|
33
|
+
)
|
|
34
|
+
from .module import IdentityModule
|
|
35
|
+
from .passwords import PasswordHasher
|
|
36
|
+
from .services import IdentityAuthenticator
|
|
37
|
+
from .tokens import JwtTokenService
|
|
38
|
+
|
|
39
|
+
__all__ = (
|
|
40
|
+
"IDENTITY_ROLES_MANAGE",
|
|
41
|
+
"IDENTITY_USERS_MANAGE",
|
|
42
|
+
"AuthenticationApplicationService",
|
|
43
|
+
"CreateRoleCommand",
|
|
44
|
+
"CreateUserCommand",
|
|
45
|
+
"CurrentUserView",
|
|
46
|
+
"IdentityAccessStore",
|
|
47
|
+
"IdentityAuthenticator",
|
|
48
|
+
"IdentityConflictError",
|
|
49
|
+
"IdentityDefinitionError",
|
|
50
|
+
"IdentityLoginStore",
|
|
51
|
+
"IdentityManagementApplicationService",
|
|
52
|
+
"IdentityModule",
|
|
53
|
+
"IdentityOptions",
|
|
54
|
+
"IdentityRepository",
|
|
55
|
+
"IdentityResourceNotFoundError",
|
|
56
|
+
"IdentityRole",
|
|
57
|
+
"IdentityUser",
|
|
58
|
+
"InvalidCredentialsError",
|
|
59
|
+
"JwtTokenService",
|
|
60
|
+
"LoginCommand",
|
|
61
|
+
"PasswordHasher",
|
|
62
|
+
"RefreshRotationResult",
|
|
63
|
+
"RefreshRotationStatus",
|
|
64
|
+
"RefreshSession",
|
|
65
|
+
"RefreshSessionStore",
|
|
66
|
+
"RefreshTokenCommand",
|
|
67
|
+
"RevokeTokenCommand",
|
|
68
|
+
"RoleView",
|
|
69
|
+
"SetRolePermissionsCommand",
|
|
70
|
+
"SetUserRolesCommand",
|
|
71
|
+
"TokenPair",
|
|
72
|
+
"UserView",
|
|
73
|
+
)
|