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.
Files changed (344) hide show
  1. python_platform/__init__.py +445 -0
  2. python_platform/application/__init__.py +6 -0
  3. python_platform/application/build_spec.py +37 -0
  4. python_platform/application/builder.py +260 -0
  5. python_platform/application/composition.py +219 -0
  6. python_platform/application/runtime.py +546 -0
  7. python_platform/application/runtime_hooks.py +327 -0
  8. python_platform/application/state.py +216 -0
  9. python_platform/application_services/__init__.py +54 -0
  10. python_platform/application_services/catalog.py +500 -0
  11. python_platform/application_services/contracts.py +188 -0
  12. python_platform/application_services/dispatcher.py +423 -0
  13. python_platform/application_services/errors.py +89 -0
  14. python_platform/application_services/execution.py +199 -0
  15. python_platform/application_services/interceptors.py +44 -0
  16. python_platform/application_services/invocation.py +427 -0
  17. python_platform/application_services/policies.py +46 -0
  18. python_platform/application_services/seeding.py +72 -0
  19. python_platform/application_services/signature.py +49 -0
  20. python_platform/application_services/validation.py +84 -0
  21. python_platform/auditing/__init__.py +12 -0
  22. python_platform/auditing/contracts.py +39 -0
  23. python_platform/auditing/control.py +48 -0
  24. python_platform/auditing/sqlalchemy/__init__.py +6 -0
  25. python_platform/auditing/sqlalchemy/migrations/0001_platform_auditing.py +45 -0
  26. python_platform/auditing/sqlalchemy/migrations/__init__.py +1 -0
  27. python_platform/auditing/sqlalchemy/models.py +31 -0
  28. python_platform/auditing/sqlalchemy/module.py +32 -0
  29. python_platform/auditing/sqlalchemy/store.py +63 -0
  30. python_platform/authorization/__init__.py +38 -0
  31. python_platform/authorization/catalog.py +63 -0
  32. python_platform/authorization/contracts.py +241 -0
  33. python_platform/authorization/definition_discovery.py +81 -0
  34. python_platform/authorization/definitions.py +43 -0
  35. python_platform/authorization/errors.py +40 -0
  36. python_platform/background_execution/__init__.py +15 -0
  37. python_platform/background_execution/application.py +41 -0
  38. python_platform/background_execution/child.py +123 -0
  39. python_platform/background_execution/contracts.py +39 -0
  40. python_platform/background_execution/lifecycle.py +22 -0
  41. python_platform/background_execution/local.py +127 -0
  42. python_platform/background_execution/locks.py +31 -0
  43. python_platform/background_execution/management.py +17 -0
  44. python_platform/background_execution/module.py +10 -0
  45. python_platform/background_execution/permissions.py +14 -0
  46. python_platform/background_execution/processes.py +331 -0
  47. python_platform/background_jobs/__init__.py +31 -0
  48. python_platform/background_jobs/catalog.py +287 -0
  49. python_platform/background_jobs/contracts.py +202 -0
  50. python_platform/background_jobs/errors.py +28 -0
  51. python_platform/background_jobs/execution.py +201 -0
  52. python_platform/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt +21 -0
  53. python_platform/background_jobs/pgqueuer/__init__.py +6 -0
  54. python_platform/background_jobs/pgqueuer/enqueue.py +82 -0
  55. python_platform/background_jobs/pgqueuer/migrations/0001_pgqueuer_1_3_2.py +63 -0
  56. python_platform/background_jobs/pgqueuer/migrations/__init__.py +1 -0
  57. python_platform/background_jobs/pgqueuer/module.py +102 -0
  58. python_platform/background_jobs/pgqueuer/options.py +70 -0
  59. python_platform/background_jobs/pgqueuer/runtime.py +479 -0
  60. python_platform/background_jobs/pgqueuer/sql/pgqueuer_1_3_2_install.sql +118 -0
  61. python_platform/background_jobs/pgqueuer/supervision.py +201 -0
  62. python_platform/background_workers/__init__.py +22 -0
  63. python_platform/background_workers/catalog.py +96 -0
  64. python_platform/background_workers/contracts.py +124 -0
  65. python_platform/background_workers/errors.py +20 -0
  66. python_platform/background_workers/execution.py +133 -0
  67. python_platform/background_workers/runtime.py +203 -0
  68. python_platform/caching/__init__.py +11 -0
  69. python_platform/caching/catalog.py +73 -0
  70. python_platform/caching/contracts.py +73 -0
  71. python_platform/caching/errors.py +20 -0
  72. python_platform/cli/__init__.py +87 -0
  73. python_platform/cli/errors.py +5 -0
  74. python_platform/cli/project.py +69 -0
  75. python_platform/cli/runtime.py +68 -0
  76. python_platform/configuration/__init__.py +21 -0
  77. python_platform/configuration/composition.py +65 -0
  78. python_platform/configuration/contracts.py +68 -0
  79. python_platform/configuration/dotenv_source.py +51 -0
  80. python_platform/configuration/environment_source.py +38 -0
  81. python_platform/configuration/immutability.py +124 -0
  82. python_platform/configuration/input_shape.py +58 -0
  83. python_platform/configuration/merge.py +103 -0
  84. python_platform/configuration/root.py +215 -0
  85. python_platform/configuration/sources.py +519 -0
  86. python_platform/configuration/values.py +427 -0
  87. python_platform/configuration/yaml_source.py +51 -0
  88. python_platform/developer_kit/__init__.py +1 -0
  89. python_platform/developer_kit/generation.py +182 -0
  90. python_platform/developer_kit/project_metadata.py +45 -0
  91. python_platform/developer_kit/source.py +53 -0
  92. python_platform/developer_kit/templates/module/cookiecutter.json +1 -0
  93. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/__init__.py.jinja +1 -0
  94. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/__init__.py.jinja +1 -0
  95. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/cache.py.jinja +10 -0
  96. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/events.py.jinja +24 -0
  97. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/integration.py.jinja +46 -0
  98. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/module.py.jinja +29 -0
  99. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/options.py.jinja +8 -0
  100. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/orders.py.jinja +81 -0
  101. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application/tasks.py.jinja +86 -0
  102. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/__init__.py.jinja +1 -0
  103. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/module.py.jinja +10 -0
  104. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/application_contracts/orders.py.jinja +36 -0
  105. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/__init__.py.jinja +1 -0
  106. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/module.py.jinja +10 -0
  107. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/orders.py.jinja +57 -0
  108. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/repository.py.jinja +12 -0
  109. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/seeding.py.jinja +19 -0
  110. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain/settings.py.jinja +16 -0
  111. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/__init__.py.jinja +1 -0
  112. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/definitions.py.jinja +24 -0
  113. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/module.py.jinja +7 -0
  114. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/domain_shared/permissions.py.jinja +15 -0
  115. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/__init__.py.jinja +1 -0
  116. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/files.py.jinja +74 -0
  117. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/module.py.jinja +58 -0
  118. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/http_api/realtime.py.jinja +37 -0
  119. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/__init__.py.jinja +1 -0
  120. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/migrations/__init__.py.jinja +1 -0
  121. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/models.py.jinja +26 -0
  122. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/module.py.jinja +32 -0
  123. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/sqlalchemy/repository.py.jinja +49 -0
  124. python_platform/developer_kit/templates/module/{{cookiecutter.module_name}}/tests/test_domain.py.jinja +18 -0
  125. python_platform/developer_kit/templates/project/cookiecutter.json +6 -0
  126. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/.dockerignore +8 -0
  127. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/.env.jinja +13 -0
  128. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/.gitignore +6 -0
  129. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/.python-version +1 -0
  130. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/Dockerfile +22 -0
  131. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/README.md +86 -0
  132. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/app.yaml.jinja +16 -0
  133. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/compose.dev.yaml.jinja +24 -0
  134. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/compose.production.yaml.jinja +13 -0
  135. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/pyproject.toml.jinja +28 -0
  136. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/__init__.py.jinja +1 -0
  137. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/main.py.jinja +52 -0
  138. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/src/host/module.py.jinja +38 -0
  139. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/tests/conftest.py.jinja +8 -0
  140. python_platform/developer_kit/templates/project/{{cookiecutter.project_name}}/tests/host/test_http.py.jinja +101 -0
  141. python_platform/developer_kit/wiring.py +85 -0
  142. python_platform/diagnostics/__init__.py +23 -0
  143. python_platform/diagnostics/journal.py +174 -0
  144. python_platform/diagnostics/model.py +83 -0
  145. python_platform/diagnostics/source.py +25 -0
  146. python_platform/distributed_lock/__init__.py +6 -0
  147. python_platform/distributed_lock/contracts.py +20 -0
  148. python_platform/distributed_lock/options.py +19 -0
  149. python_platform/domain/__init__.py +13 -0
  150. python_platform/domain/aggregates.py +64 -0
  151. python_platform/domain/entities.py +33 -0
  152. python_platform/domain/errors.py +12 -0
  153. python_platform/domain/value_objects.py +31 -0
  154. python_platform/errors/__init__.py +75 -0
  155. python_platform/errors/base.py +13 -0
  156. python_platform/errors/business.py +53 -0
  157. python_platform/errors/configuration.py +119 -0
  158. python_platform/errors/diagnostics.py +12 -0
  159. python_platform/errors/lifecycle.py +164 -0
  160. python_platform/errors/modularity.py +100 -0
  161. python_platform/errors/services.py +100 -0
  162. python_platform/events/__init__.py +25 -0
  163. python_platform/events/aggregate.py +39 -0
  164. python_platform/events/catalog.py +136 -0
  165. python_platform/events/contracts.py +39 -0
  166. python_platform/events/contribution.py +128 -0
  167. python_platform/events/discovery.py +105 -0
  168. python_platform/events/errors.py +48 -0
  169. python_platform/events/runtime.py +192 -0
  170. python_platform/fastapi/__init__.py +49 -0
  171. python_platform/fastapi/action.py +175 -0
  172. python_platform/fastapi/adapter.py +381 -0
  173. python_platform/fastapi/application_services.py +647 -0
  174. python_platform/fastapi/background.py +42 -0
  175. python_platform/fastapi/contracts.py +278 -0
  176. python_platform/fastapi/errors.py +32 -0
  177. python_platform/fastapi/filters.py +111 -0
  178. python_platform/fastapi/health.py +44 -0
  179. python_platform/fastapi/http.py +55 -0
  180. python_platform/fastapi/http_router.py +212 -0
  181. python_platform/fastapi/manual_action.py +105 -0
  182. python_platform/fastapi/middleware.py +93 -0
  183. python_platform/fastapi/parameters.py +97 -0
  184. python_platform/fastapi/realtime/__init__.py +13 -0
  185. python_platform/fastapi/realtime/authentication.py +181 -0
  186. python_platform/fastapi/realtime/connection.py +166 -0
  187. python_platform/fastapi/realtime/module.py +41 -0
  188. python_platform/fastapi/realtime/options.py +50 -0
  189. python_platform/fastapi/realtime/runtime.py +423 -0
  190. python_platform/fastapi/request_context.py +244 -0
  191. python_platform/fastapi/route_integrity.py +88 -0
  192. python_platform/fastapi/routing.py +410 -0
  193. python_platform/fastapi/server.py +181 -0
  194. python_platform/fastapi/settings.py +40 -0
  195. python_platform/fastapi/tracing.py +62 -0
  196. python_platform/fastapi/transfer.py +128 -0
  197. python_platform/fastapi/upload_limits.py +63 -0
  198. python_platform/fastapi/uploads.py +94 -0
  199. python_platform/hosted_services/__init__.py +29 -0
  200. python_platform/hosted_services/bridge.py +420 -0
  201. python_platform/hosted_services/catalog.py +259 -0
  202. python_platform/hosted_services/contracts.py +55 -0
  203. python_platform/hosted_services/errors.py +53 -0
  204. python_platform/hosted_services/options.py +17 -0
  205. python_platform/hosted_services/runtime.py +267 -0
  206. python_platform/hosted_services/state.py +40 -0
  207. python_platform/hosting/__init__.py +4 -0
  208. python_platform/hosting/instance.py +40 -0
  209. python_platform/identity/__init__.py +73 -0
  210. python_platform/identity/application.py +287 -0
  211. python_platform/identity/contracts.py +283 -0
  212. python_platform/identity/errors.py +28 -0
  213. python_platform/identity/http_api.py +90 -0
  214. python_platform/identity/module.py +46 -0
  215. python_platform/identity/passwords.py +34 -0
  216. python_platform/identity/permissions.py +14 -0
  217. python_platform/identity/services.py +108 -0
  218. python_platform/identity/sqlalchemy/__init__.py +5 -0
  219. python_platform/identity/sqlalchemy/migrations/0001_platform_identity.py +151 -0
  220. python_platform/identity/sqlalchemy/migrations/0002_physical_delete.py +42 -0
  221. python_platform/identity/sqlalchemy/migrations/__init__.py +1 -0
  222. python_platform/identity/sqlalchemy/models.py +85 -0
  223. python_platform/identity/sqlalchemy/module.py +62 -0
  224. python_platform/identity/sqlalchemy/stores.py +526 -0
  225. python_platform/identity/tokens.py +106 -0
  226. python_platform/invocation/__init__.py +3 -0
  227. python_platform/invocation/callables.py +171 -0
  228. python_platform/invocation/contracts.py +33 -0
  229. python_platform/invocation/entries.py +54 -0
  230. python_platform/invocation/function_runtime.py +48 -0
  231. python_platform/invocation/interception.py +184 -0
  232. python_platform/lifecycle/__init__.py +25 -0
  233. python_platform/lifecycle/composition.py +35 -0
  234. python_platform/lifecycle/context.py +31 -0
  235. python_platform/lifecycle/runtime.py +43 -0
  236. python_platform/lifecycle/state.py +20 -0
  237. python_platform/modularity/__init__.py +15 -0
  238. python_platform/modularity/contracts.py +90 -0
  239. python_platform/modularity/discovery.py +143 -0
  240. python_platform/modularity/graph.py +334 -0
  241. python_platform/modularity/registry.py +100 -0
  242. python_platform/modularity/selection.py +16 -0
  243. python_platform/notifications/__init__.py +19 -0
  244. python_platform/notifications/catalog.py +46 -0
  245. python_platform/notifications/contracts.py +107 -0
  246. python_platform/observability/__init__.py +5 -0
  247. python_platform/observability/context.py +43 -0
  248. python_platform/observability/export.py +73 -0
  249. python_platform/observability/formatting.py +89 -0
  250. python_platform/observability/logging.py +118 -0
  251. python_platform/observability/options.py +45 -0
  252. python_platform/observability/tracing.py +80 -0
  253. python_platform/options/__init__.py +19 -0
  254. python_platform/options/aliases.py +331 -0
  255. python_platform/options/contribution.py +62 -0
  256. python_platform/options/immutability.py +48 -0
  257. python_platform/options/input_keys.py +214 -0
  258. python_platform/options/issues.py +335 -0
  259. python_platform/options/models.py +114 -0
  260. python_platform/options/registry.py +280 -0
  261. python_platform/options/schema.py +488 -0
  262. python_platform/options/validation.py +120 -0
  263. python_platform/py.typed +0 -0
  264. python_platform/realtime/__init__.py +12 -0
  265. python_platform/realtime/contracts.py +28 -0
  266. python_platform/realtime/diagnostics.py +37 -0
  267. python_platform/realtime/messages.py +113 -0
  268. python_platform/redis/__init__.py +6 -0
  269. python_platform/redis/distributed_lock.py +212 -0
  270. python_platform/redis/lease_lock.py +36 -0
  271. python_platform/redis/module.py +50 -0
  272. python_platform/redis/notification_runtime.py +182 -0
  273. python_platform/redis/notifications.py +25 -0
  274. python_platform/redis/options.py +35 -0
  275. python_platform/redis/runtime.py +116 -0
  276. python_platform/services/__init__.py +39 -0
  277. python_platform/services/application_bindings.py +221 -0
  278. python_platform/services/arbitration.py +381 -0
  279. python_platform/services/binding.py +102 -0
  280. python_platform/services/contribution.py +438 -0
  281. python_platform/services/convention.py +292 -0
  282. python_platform/services/convention_contracts.py +94 -0
  283. python_platform/services/exposure.py +23 -0
  284. python_platform/services/framework_provider.py +178 -0
  285. python_platform/services/native_graph.py +172 -0
  286. python_platform/services/provider.py +204 -0
  287. python_platform/services/registration.py +101 -0
  288. python_platform/services/runtime.py +298 -0
  289. python_platform/settings/__init__.py +30 -0
  290. python_platform/settings/application.py +95 -0
  291. python_platform/settings/binding.py +33 -0
  292. python_platform/settings/catalog.py +121 -0
  293. python_platform/settings/changes.py +14 -0
  294. python_platform/settings/contracts.py +115 -0
  295. python_platform/settings/definition_discovery.py +71 -0
  296. python_platform/settings/definitions.py +41 -0
  297. python_platform/settings/errors.py +22 -0
  298. python_platform/settings/handlers.py +43 -0
  299. python_platform/settings/management.py +57 -0
  300. python_platform/settings/manager.py +89 -0
  301. python_platform/settings/module.py +7 -0
  302. python_platform/settings/notifications.py +39 -0
  303. python_platform/settings/permissions.py +14 -0
  304. python_platform/settings/provider.py +74 -0
  305. python_platform/settings/refresh.py +140 -0
  306. python_platform/settings/refresh_module.py +45 -0
  307. python_platform/settings/sqlalchemy/__init__.py +5 -0
  308. python_platform/settings/sqlalchemy/migrations/0001_platform_settings.py +31 -0
  309. python_platform/settings/sqlalchemy/migrations/0002_physical_delete.py +32 -0
  310. python_platform/settings/sqlalchemy/migrations/0003_version_tokens.py +39 -0
  311. python_platform/settings/sqlalchemy/migrations/__init__.py +1 -0
  312. python_platform/settings/sqlalchemy/models.py +36 -0
  313. python_platform/settings/sqlalchemy/module.py +36 -0
  314. python_platform/settings/sqlalchemy/store.py +86 -0
  315. python_platform/settings/store.py +16 -0
  316. python_platform/settings/values.py +39 -0
  317. python_platform/sqlalchemy/__init__.py +51 -0
  318. python_platform/sqlalchemy/alembic_runtime/__init__.py +1 -0
  319. python_platform/sqlalchemy/alembic_runtime/env.py +27 -0
  320. python_platform/sqlalchemy/alembic_runtime/script.py.mako +14 -0
  321. python_platform/sqlalchemy/auditing.py +48 -0
  322. python_platform/sqlalchemy/errors.py +85 -0
  323. python_platform/sqlalchemy/metadata.py +538 -0
  324. python_platform/sqlalchemy/migration.py +346 -0
  325. python_platform/sqlalchemy/module.py +48 -0
  326. python_platform/sqlalchemy/module_migration.py +148 -0
  327. python_platform/sqlalchemy/options.py +66 -0
  328. python_platform/sqlalchemy/repository.py +33 -0
  329. python_platform/sqlalchemy/runtime.py +85 -0
  330. python_platform/sqlalchemy/session_provider.py +45 -0
  331. python_platform/sqlalchemy/unit_of_work.py +97 -0
  332. python_platform/testing/__init__.py +5 -0
  333. python_platform/testing/runtime.py +112 -0
  334. python_platform/unit_of_work/__init__.py +14 -0
  335. python_platform/unit_of_work/contracts.py +223 -0
  336. python_platform/unit_of_work/errors.py +27 -0
  337. python_platform/unit_of_work/manager.py +210 -0
  338. python_platform/unit_of_work/options.py +92 -0
  339. python_platform-0.1.1.dist-info/METADATA +122 -0
  340. python_platform-0.1.1.dist-info/RECORD +344 -0
  341. python_platform-0.1.1.dist-info/WHEEL +4 -0
  342. python_platform-0.1.1.dist-info/entry_points.txt +9 -0
  343. python_platform-0.1.1.dist-info/licenses/LICENSE +7 -0
  344. python_platform-0.1.1.dist-info/licenses/src/python_platform/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt +21 -0
@@ -0,0 +1,31 @@
1
+ """Pydantic-backed immutable domain values."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, ConfigDict
8
+
9
+
10
+ class ValueObject(BaseModel):
11
+ """按具体类型与字段值比较的领域值;它不是 transport DTO。"""
12
+
13
+ model_config = ConfigDict(frozen=True, extra="forbid")
14
+
15
+ @classmethod
16
+ def __pydantic_init_subclass__(cls, **kwargs: Any) -> None:
17
+ super().__pydantic_init_subclass__(**kwargs)
18
+ if cls.model_config.get("frozen") is not True or cls.model_config.get("extra") != "forbid":
19
+ raise TypeError("ValueObject subclasses must remain frozen and forbid extra fields")
20
+
21
+ def __eq__(self, other: object) -> bool:
22
+ if type(self) is not type(other):
23
+ return False
24
+ return self._field_values() == other._field_values()
25
+
26
+ def __hash__(self) -> int:
27
+ # 字段中含 list/dict 等 mutable value 时由 Python 原生 hash fail closed。
28
+ return hash((type(self), self._field_values()))
29
+
30
+ def _field_values(self) -> tuple[object, ...]:
31
+ return tuple(getattr(self, name) for name in type(self).model_fields)
@@ -0,0 +1,75 @@
1
+ """按 capability 组织的 Python Platform 结构化错误公开边界。"""
2
+
3
+ from .base import FrameworkError, ResourceConflictError, ResourceNotFoundError
4
+ from .business import BusinessError, BusinessErrorDefinition, BusinessErrorField
5
+ from .configuration import (
6
+ ConfigurationSourceError,
7
+ DuplicateOptionDefinitionError,
8
+ InvalidOptionDefinitionError,
9
+ OptionsContributionClosedError,
10
+ OptionsValidationError,
11
+ UnknownOptionsError,
12
+ )
13
+ from .diagnostics import InvalidDiagnosticCodeError
14
+ from .lifecycle import (
15
+ ApplicationRuntimeError,
16
+ ApplicationStartError,
17
+ CompositionResourceError,
18
+ InvalidApplicationStateError,
19
+ LifecycleInvocationError,
20
+ LifecycleReturnValueError,
21
+ )
22
+ from .modularity import (
23
+ DuplicateModuleIdentityError,
24
+ GraphInvariantError,
25
+ InvalidModuleReferenceError,
26
+ ModuleCycleError,
27
+ ModuleInstantiationError,
28
+ ModuleResolutionError,
29
+ UnknownModuleError,
30
+ )
31
+ from .services import (
32
+ CatalogNativeGraphMismatchError,
33
+ ContainerCleanupError,
34
+ ContainerValidationError,
35
+ ConventionScanError,
36
+ InvalidConventionDefinitionError,
37
+ RegistrationConflictError,
38
+ ServiceContributorClosedError,
39
+ )
40
+
41
+ __all__ = (
42
+ "ApplicationRuntimeError",
43
+ "ApplicationStartError",
44
+ "BusinessError",
45
+ "BusinessErrorDefinition",
46
+ "BusinessErrorField",
47
+ "CatalogNativeGraphMismatchError",
48
+ "CompositionResourceError",
49
+ "ConfigurationSourceError",
50
+ "ContainerCleanupError",
51
+ "ContainerValidationError",
52
+ "ConventionScanError",
53
+ "DuplicateModuleIdentityError",
54
+ "DuplicateOptionDefinitionError",
55
+ "FrameworkError",
56
+ "GraphInvariantError",
57
+ "InvalidApplicationStateError",
58
+ "InvalidConventionDefinitionError",
59
+ "InvalidDiagnosticCodeError",
60
+ "InvalidModuleReferenceError",
61
+ "InvalidOptionDefinitionError",
62
+ "LifecycleInvocationError",
63
+ "LifecycleReturnValueError",
64
+ "ModuleCycleError",
65
+ "ModuleInstantiationError",
66
+ "ModuleResolutionError",
67
+ "OptionsContributionClosedError",
68
+ "OptionsValidationError",
69
+ "RegistrationConflictError",
70
+ "ResourceConflictError",
71
+ "ResourceNotFoundError",
72
+ "ServiceContributorClosedError",
73
+ "UnknownModuleError",
74
+ "UnknownOptionsError",
75
+ )
@@ -0,0 +1,13 @@
1
+ """所有 capability error 共享的最小命名根。"""
2
+
3
+
4
+ class FrameworkError(Exception):
5
+ """所有 Python Platform 结构化错误的命名基类。"""
6
+
7
+
8
+ class ResourceConflictError(FrameworkError):
9
+ """可信业务边界可映射为 HTTP 409 的静态冲突。"""
10
+
11
+
12
+ class ResourceNotFoundError(FrameworkError):
13
+ """可信业务边界可映射为 HTTP 404 的静态缺失。"""
@@ -0,0 +1,53 @@
1
+ """业务模块集中定义的公开安全错误,不把异常正文或动态输入当作响应。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from .base import FrameworkError
10
+
11
+
12
+ @dataclass(frozen=True, slots=True)
13
+ class BusinessErrorDefinition:
14
+ code: str
15
+ message: str
16
+
17
+ def __post_init__(self) -> None:
18
+ if (
19
+ not isinstance(self.code, str)
20
+ or not self.code
21
+ or any(not (part.isascii() and (part.isalnum() or part in "._")) for part in self.code)
22
+ ):
23
+ raise ValueError("business error code must be a stable non-empty identifier")
24
+ if not isinstance(self.message, str) or not self.message.strip():
25
+ raise ValueError("business error message must be a static safe message")
26
+
27
+
28
+ @dataclass(frozen=True, slots=True)
29
+ class BusinessErrorField:
30
+ model_type: type[BaseModel]
31
+ name: str
32
+
33
+ def __post_init__(self) -> None:
34
+ # 字段必须来自静态 DTO contract,不能把运行时字典键或用户输入混入定位信息。
35
+ if not isinstance(self.model_type, type) or not issubclass(self.model_type, BaseModel):
36
+ raise TypeError("business error field requires a Pydantic model type")
37
+ if self.name not in self.model_type.model_fields:
38
+ raise ValueError("business error field must name a declared model field")
39
+
40
+
41
+ class BusinessError(FrameworkError):
42
+ def __init__(
43
+ self, definition: BusinessErrorDefinition, *, fields: tuple[BusinessErrorField, ...] = ()
44
+ ) -> None:
45
+ if not isinstance(definition, BusinessErrorDefinition):
46
+ raise TypeError("business error requires a static definition")
47
+ if not isinstance(fields, tuple) or any(
48
+ not isinstance(field, BusinessErrorField) for field in fields
49
+ ):
50
+ raise TypeError("business error fields must be an immutable tuple")
51
+ self.definition = definition
52
+ self.fields = fields
53
+ super().__init__(definition.code)
@@ -0,0 +1,119 @@
1
+ """Configuration 与 typed Options 的结构化失败。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from .base import FrameworkError
8
+
9
+ if TYPE_CHECKING:
10
+ from pydantic import BaseModel, ValidationError
11
+
12
+ from ..diagnostics import SourceLocation
13
+ from ..modularity import ModuleKey
14
+ from ..options import OptionsValidationIssue
15
+
16
+
17
+ class ConfigurationSourceError(FrameworkError):
18
+ """配置来源加载或规范化失败;消息不复制可能含敏感值的底层异常文本。"""
19
+
20
+ def __init__(
21
+ self,
22
+ *,
23
+ source_id: str,
24
+ location: SourceLocation,
25
+ original_error: BaseException,
26
+ ) -> None:
27
+ self.source_id = source_id
28
+ self.location = location
29
+ self.original_error = original_error
30
+ self.__cause__ = original_error
31
+ self.__suppress_context__ = True
32
+ super().__init__(f"Unable to load configuration source {source_id!r}")
33
+
34
+
35
+ class InvalidOptionDefinitionError(FrameworkError):
36
+ def __init__(
37
+ self,
38
+ *,
39
+ owner: ModuleKey,
40
+ model_type: type[BaseModel] | None,
41
+ option_kind: str,
42
+ reason: str,
43
+ ) -> None:
44
+ self.owner = owner
45
+ self.model_type = model_type
46
+ self.option_kind = option_kind
47
+ self.reason = reason
48
+ model_name = (
49
+ f"{model_type.__module__}.{model_type.__qualname__}"
50
+ if model_type is not None
51
+ else "<invalid declaration>"
52
+ )
53
+ super().__init__(
54
+ f"Invalid {option_kind} definition {model_name} declared by {owner}: {reason}"
55
+ )
56
+
57
+
58
+ class DuplicateOptionDefinitionError(FrameworkError):
59
+ def __init__(
60
+ self,
61
+ *,
62
+ model_type: type[BaseModel],
63
+ option_kind: str,
64
+ first_owner: ModuleKey,
65
+ second_owner: ModuleKey,
66
+ ) -> None:
67
+ self.model_type = model_type
68
+ self.option_kind = option_kind
69
+ self.first_owner = first_owner
70
+ self.second_owner = second_owner
71
+ model_name = f"{model_type.__module__}.{model_type.__qualname__}"
72
+ super().__init__(
73
+ f"Duplicate {option_kind} definition for {model_name}: {first_owner} and {second_owner}"
74
+ )
75
+
76
+
77
+ class UnknownOptionsError(FrameworkError, KeyError):
78
+ def __init__(self, model_type: type[BaseModel], *, option_kind: str) -> None:
79
+ self.model_type = model_type
80
+ self.option_kind = option_kind
81
+ model_name = f"{model_type.__module__}.{model_type.__qualname__}"
82
+ super().__init__(f"Unknown {option_kind} model {model_name}")
83
+
84
+
85
+ class OptionsContributionClosedError(FrameworkError):
86
+ def __init__(self, *, option_kind: str, stage: str) -> None:
87
+ self.option_kind = option_kind
88
+ self.stage = stage
89
+ super().__init__(
90
+ f"{option_kind} configuration contribution is no longer active after {stage}"
91
+ )
92
+
93
+
94
+ class OptionsValidationError(FrameworkError):
95
+ """对 Pydantic 错误增加 owner/source 语义,只保留已脱敏的 Pydantic cause。"""
96
+
97
+ def __init__(
98
+ self,
99
+ *,
100
+ model_type: type[BaseModel],
101
+ section: str,
102
+ owner: ModuleKey,
103
+ option_kind: str,
104
+ issues: tuple[OptionsValidationIssue, ...],
105
+ validation_error: ValidationError,
106
+ ) -> None:
107
+ self.model_type = model_type
108
+ self.section = section
109
+ self.owner = owner
110
+ self.option_kind = option_kind
111
+ self.issues = issues
112
+ self.validation_error = validation_error
113
+ self.__cause__ = validation_error
114
+ self.__suppress_context__ = True
115
+ model_name = f"{model_type.__module__}.{model_type.__qualname__}"
116
+ paths = ", ".join(issue.field_path for issue in issues) or "<model>"
117
+ super().__init__(
118
+ f"Invalid {option_kind} {model_name} at section {section!r}; fields: {paths}"
119
+ )
@@ -0,0 +1,12 @@
1
+ """Diagnostic contract 自身的边界错误。"""
2
+
3
+ from .base import FrameworkError
4
+
5
+
6
+ class InvalidDiagnosticCodeError(FrameworkError):
7
+ def __init__(self, code: str, *, max_length: int) -> None:
8
+ self.code = code
9
+ self.max_length = max_length
10
+ super().__init__(
11
+ f"Diagnostic code must be a stable identifier of at most {max_length} characters"
12
+ )
@@ -0,0 +1,164 @@
1
+ """Application state、lifecycle invocation 与运行失败归属。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+ from uuid import UUID
7
+
8
+ from .base import FrameworkError
9
+
10
+ if TYPE_CHECKING:
11
+ from ..diagnostics import LifecyclePhase, LifecycleStage, SourceLocation
12
+ from ..hosted_services.errors import HostedServiceLifecycleError
13
+ from ..lifecycle import ApplicationState
14
+ from ..modularity import ModuleKey
15
+ from .services import ContainerCleanupError
16
+
17
+
18
+ class InvalidApplicationStateError(FrameworkError):
19
+ def __init__(
20
+ self,
21
+ *,
22
+ operation: str,
23
+ current: ApplicationState,
24
+ allowed: tuple[ApplicationState, ...],
25
+ ) -> None:
26
+ self.operation = operation
27
+ self.current = current
28
+ self.allowed = allowed
29
+ allowed_values = ", ".join(state.value for state in allowed)
30
+ super().__init__(
31
+ f"Operation {operation!r} is invalid in state {current.value}; "
32
+ f"allowed: {allowed_values}"
33
+ )
34
+
35
+
36
+ class CompositionResourceError(FrameworkError):
37
+ def __init__(
38
+ self,
39
+ *,
40
+ module: ModuleKey,
41
+ stage: LifecycleStage,
42
+ resource_kind: str,
43
+ ) -> None:
44
+ self.module = module
45
+ self.stage = stage
46
+ self.resource_kind = resource_kind
47
+ super().__init__(
48
+ f"Composition hook {module}/{stage.value} returned forbidden {resource_kind}"
49
+ )
50
+
51
+
52
+ class LifecycleReturnValueError(FrameworkError):
53
+ def __init__(
54
+ self,
55
+ *,
56
+ module: ModuleKey,
57
+ phase: LifecyclePhase,
58
+ stage: LifecycleStage,
59
+ returned_type: str,
60
+ ) -> None:
61
+ self.module = module
62
+ self.phase = phase
63
+ self.stage = stage
64
+ self.returned_type = returned_type
65
+ super().__init__(
66
+ f"Lifecycle hook {module}/{stage.value} must return None, got {returned_type}"
67
+ )
68
+
69
+
70
+ class LifecycleInvocationError(FrameworkError):
71
+ def __init__(
72
+ self,
73
+ *,
74
+ failure_id: UUID,
75
+ module: ModuleKey,
76
+ phase: LifecyclePhase,
77
+ stage: LifecycleStage,
78
+ dependency_path: tuple[ModuleKey, ...],
79
+ duration_ns: int,
80
+ source: SourceLocation,
81
+ original_error: BaseException,
82
+ ) -> None:
83
+ self.failure_id = failure_id
84
+ self.module = module
85
+ self.phase = phase
86
+ self.stage = stage
87
+ self.dependency_path = dependency_path
88
+ self.duration_ns = duration_ns
89
+ self.source = source
90
+ # cleanup 为 best-effort 会收集 wrapper,因此构造时显式建立因果链。
91
+ self.__cause__ = original_error
92
+ self.__suppress_context__ = True
93
+ self.original_error = original_error
94
+ super().__init__(
95
+ f"Lifecycle invocation failed for {module}/{stage.value} "
96
+ f"with {type(original_error).__name__}"
97
+ )
98
+
99
+
100
+ class _BackgroundExecutionStartFailure(FrameworkError):
101
+ """保留原始 background start failure,同时不伪造 Module lifecycle 位置。"""
102
+
103
+ failure_id = None
104
+ stage = None
105
+ dependency_path: tuple[ModuleKey, ...] = ()
106
+
107
+ def __init__(self, *, original_error: BaseException) -> None:
108
+ self.original_error = original_error
109
+ self.__cause__ = original_error
110
+ self.__suppress_context__ = True
111
+ super().__init__(f"Background execution start failed with {type(original_error).__name__}")
112
+
113
+
114
+ class ApplicationRuntimeError(FrameworkError):
115
+ """运行期基础设施 fatal fact;不携带第三方异常正文或原始 cause。"""
116
+
117
+ def __init__(self, *, component: str, error_type: str) -> None:
118
+ self.component = component
119
+ self.error_type = error_type
120
+ # 标识一次失败事实,不持有原始异常、task 或 provider;同名失败仍是独立事实。
121
+ self._source = object()
122
+ super().__init__(f"Application runtime {component!r} failed with {error_type}")
123
+
124
+
125
+ class ApplicationStartError(FrameworkError):
126
+ def __init__(
127
+ self,
128
+ *,
129
+ primary: (
130
+ LifecycleInvocationError
131
+ | _BackgroundExecutionStartFailure
132
+ | HostedServiceLifecycleError
133
+ ),
134
+ cleanup_failures: tuple[
135
+ LifecycleInvocationError
136
+ | ContainerCleanupError
137
+ | _BackgroundExecutionStartFailure
138
+ | HostedServiceLifecycleError,
139
+ ...,
140
+ ],
141
+ ) -> None:
142
+ self.primary = primary
143
+ self.cleanup_failures = cleanup_failures
144
+ if isinstance(primary, LifecycleInvocationError):
145
+ location = f"{primary.module}/{primary.stage.value}"
146
+ elif isinstance(primary, _BackgroundExecutionStartFailure):
147
+ location = "background-execution"
148
+ else:
149
+ location = f"hosted-service:{primary.service}/{primary.operation}"
150
+ super().__init__(
151
+ f"Application start failed at {location}; cleanup failures: {len(cleanup_failures)}"
152
+ )
153
+
154
+
155
+ def _exclude_runtime_failure(
156
+ error: BaseException, primary: ApplicationRuntimeError
157
+ ) -> BaseException | None:
158
+ # 发布 fatal 与观察 drain 可能竞争;终止 owner 才能确认哪个事实已成为主失败。
159
+ def same_source(item: BaseException) -> bool:
160
+ return isinstance(item, ApplicationRuntimeError) and item._source is primary._source
161
+
162
+ if isinstance(error, BaseExceptionGroup):
163
+ return error.split(same_source)[1]
164
+ return None if same_source(error) else error
@@ -0,0 +1,100 @@
1
+ """Module reference、graph 与 registry ownership 的结构化失败。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from .base import FrameworkError
8
+
9
+ if TYPE_CHECKING:
10
+ from ..diagnostics import SourceLocation
11
+ from ..modularity import AppModule, ModuleDependencyEdge, ModuleKey
12
+
13
+
14
+ class InvalidModuleReferenceError(FrameworkError):
15
+ def __init__(
16
+ self,
17
+ *,
18
+ owner: ModuleKey | None,
19
+ reference: str,
20
+ reason: str,
21
+ source: SourceLocation | None,
22
+ ) -> None:
23
+ self.owner = owner
24
+ self.reference = reference
25
+ self.reason = reason
26
+ self.source = source
27
+ super().__init__(f"Invalid module reference {reference!r}: {reason}")
28
+
29
+
30
+ class ModuleResolutionError(FrameworkError):
31
+ def __init__(
32
+ self,
33
+ *,
34
+ owner: ModuleKey | None,
35
+ reference: str,
36
+ resolution_chain: tuple[str, ...],
37
+ source: SourceLocation | None,
38
+ original_error: BaseException,
39
+ ) -> None:
40
+ self.owner = owner
41
+ self.reference = reference
42
+ self.resolution_chain = resolution_chain
43
+ self.source = source
44
+ self.original_error = original_error
45
+ super().__init__(f"Unable to resolve module reference {reference!r}")
46
+
47
+
48
+ class ModuleCycleError(FrameworkError):
49
+ def __init__(
50
+ self,
51
+ *,
52
+ startup: ModuleKey,
53
+ path: tuple[ModuleKey, ...],
54
+ edges: tuple[ModuleDependencyEdge, ...],
55
+ ) -> None:
56
+ self.startup = startup
57
+ self.path = path
58
+ self.edges = edges
59
+ rendered_path = " -> ".join(str(key) for key in path)
60
+ super().__init__(f"Module dependency cycle: {rendered_path}")
61
+
62
+
63
+ class GraphInvariantError(FrameworkError):
64
+ def __init__(self, detail: str) -> None:
65
+ self.detail = detail
66
+ super().__init__(f"Module graph invariant failed: {detail}")
67
+
68
+
69
+ class DuplicateModuleIdentityError(FrameworkError):
70
+ def __init__(
71
+ self,
72
+ *,
73
+ key: ModuleKey,
74
+ first_type: type[AppModule],
75
+ second_type: type[AppModule],
76
+ ) -> None:
77
+ self.key = key
78
+ self.first_type = first_type
79
+ self.second_type = second_type
80
+ super().__init__(f"Different module classes resolved to the same key {key}")
81
+
82
+
83
+ class ModuleInstantiationError(FrameworkError):
84
+ def __init__(
85
+ self,
86
+ *,
87
+ module: ModuleKey,
88
+ source: SourceLocation,
89
+ original_error: BaseException,
90
+ ) -> None:
91
+ self.module = module
92
+ self.source = source
93
+ self.original_error = original_error
94
+ super().__init__(f"Unable to instantiate module {module}")
95
+
96
+
97
+ class UnknownModuleError(FrameworkError, KeyError):
98
+ def __init__(self, module: ModuleKey) -> None:
99
+ self.module = module
100
+ super().__init__(f"Unknown module {module}")
@@ -0,0 +1,100 @@
1
+ """Service composition、Convention 与 native container 的结构化失败。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+ from uuid import UUID
7
+
8
+ from .base import FrameworkError
9
+
10
+ if TYPE_CHECKING:
11
+ from dishka import DependencyKey
12
+
13
+ from ..diagnostics import SourceLocation
14
+ from ..modularity import ModuleKey
15
+
16
+
17
+ class InvalidConventionDefinitionError(FrameworkError):
18
+ def __init__(self, *, symbol: str, reason: str) -> None:
19
+ self.symbol = symbol
20
+ self.reason = reason
21
+ super().__init__(f"Invalid convention definition {symbol}: {reason}")
22
+
23
+
24
+ class ConventionScanError(FrameworkError):
25
+ def __init__(
26
+ self,
27
+ *,
28
+ owner: ModuleKey,
29
+ package: str | None,
30
+ source: SourceLocation,
31
+ reason: str,
32
+ original_error: BaseException | None,
33
+ ) -> None:
34
+ self.owner = owner
35
+ self.package = package
36
+ self.source = source
37
+ self.reason = reason
38
+ self.original_error = original_error
39
+ if original_error is not None:
40
+ self.__cause__ = original_error
41
+ self.__suppress_context__ = True
42
+ target = package if package is not None else "<invalid metadata>"
43
+ super().__init__(f"Convention scan failed for {owner}/{target}: {reason}")
44
+
45
+
46
+ class ServiceContributorClosedError(FrameworkError):
47
+ def __init__(self, *, stage: str) -> None:
48
+ self.stage = stage
49
+ super().__init__(f"Service contributor is no longer active after {stage}")
50
+
51
+
52
+ class RegistrationConflictError(FrameworkError):
53
+ def __init__(
54
+ self,
55
+ *,
56
+ key: DependencyKey | None,
57
+ sources: tuple[SourceLocation, ...],
58
+ reason: str,
59
+ ) -> None:
60
+ self.key = key
61
+ self.sources = sources
62
+ self.reason = reason
63
+ rendered_key = str(key) if key is not None else "<provider>"
64
+ super().__init__(f"Service registration conflict for {rendered_key}: {reason}")
65
+
66
+
67
+ class ContainerValidationError(FrameworkError):
68
+ def __init__(
69
+ self,
70
+ *,
71
+ sources: tuple[SourceLocation, ...],
72
+ original_error: Exception,
73
+ ) -> None:
74
+ self.sources = sources
75
+ self.original_error = original_error
76
+ self.__cause__ = original_error
77
+ self.__suppress_context__ = True
78
+ super().__init__(
79
+ f"Dishka strict container validation failed with {type(original_error).__name__}"
80
+ )
81
+
82
+
83
+ class CatalogNativeGraphMismatchError(FrameworkError):
84
+ def __init__(self, *, differences: tuple[str, ...]) -> None:
85
+ self.differences = differences
86
+ super().__init__(f"Service catalog/native graph mismatch: {len(differences)} difference(s)")
87
+
88
+
89
+ class ContainerCleanupError(FrameworkError):
90
+ def __init__(
91
+ self,
92
+ *,
93
+ failure_id: UUID,
94
+ original_error: BaseException,
95
+ ) -> None:
96
+ self.failure_id = failure_id
97
+ self.original_error = original_error
98
+ self.__cause__ = original_error
99
+ self.__suppress_context__ = True
100
+ super().__init__(f"Dishka container cleanup failed with {type(original_error).__name__}")
@@ -0,0 +1,25 @@
1
+ from .aggregate import AggregateEventCollector
2
+ from .catalog import LocalEventCatalog, LocalEventSubscription
3
+ from .contracts import LocalEventPhase, local_event_handler
4
+ from .contribution import EventContributor
5
+ from .errors import (
6
+ EventContributionError,
7
+ EventCycleError,
8
+ LocalEventHandlerError,
9
+ PostCommitEventError,
10
+ )
11
+ from .runtime import LocalEventBus
12
+
13
+ __all__ = (
14
+ "AggregateEventCollector",
15
+ "EventContributionError",
16
+ "EventContributor",
17
+ "EventCycleError",
18
+ "LocalEventBus",
19
+ "LocalEventCatalog",
20
+ "LocalEventHandlerError",
21
+ "LocalEventPhase",
22
+ "LocalEventSubscription",
23
+ "PostCommitEventError",
24
+ "local_event_handler",
25
+ )