pz-cli 5.0.0__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 (399) hide show
  1. pz_cli-5.0.0.dist-info/METADATA +51 -0
  2. pz_cli-5.0.0.dist-info/RECORD +399 -0
  3. pz_cli-5.0.0.dist-info/WHEEL +4 -0
  4. pz_cli-5.0.0.dist-info/entry_points.txt +5 -0
  5. pz_core/__init__.py +64 -0
  6. pz_core/__main__.py +7 -0
  7. pz_core/app.py +45 -0
  8. pz_core/assembly/__init__.py +17 -0
  9. pz_core/assembly/app_discovery.py +1240 -0
  10. pz_core/assembly/apps/__init__.py +25 -0
  11. pz_core/assembly/apps/compiler.py +824 -0
  12. pz_core/assembly/apps/providers.py +188 -0
  13. pz_core/assembly/cli/__init__.py +9 -0
  14. pz_core/assembly/cli/compiler.py +166 -0
  15. pz_core/assembly/diagnostics/__init__.py +21 -0
  16. pz_core/assembly/diagnostics/checks.py +257 -0
  17. pz_core/assembly/diagnostics/dev_sources.py +569 -0
  18. pz_core/assembly/events/__init__.py +5 -0
  19. pz_core/assembly/events/compiler.py +219 -0
  20. pz_core/assembly/extensions/__init__.py +5 -0
  21. pz_core/assembly/extensions/compiler.py +696 -0
  22. pz_core/assembly/infra/__init__.py +6 -0
  23. pz_core/assembly/infra/compiler.py +272 -0
  24. pz_core/assembly/lifecycle/__init__.py +5 -0
  25. pz_core/assembly/lifecycle/compiler.py +95 -0
  26. pz_core/assembly/middlewares/__init__.py +19 -0
  27. pz_core/assembly/middlewares/compiler.py +508 -0
  28. pz_core/assembly/project/__init__.py +7 -0
  29. pz_core/assembly/project/compiler.py +9 -0
  30. pz_core/assembly/project/context.py +17 -0
  31. pz_core/assembly/project/discovery.py +227 -0
  32. pz_core/assembly/resources/__init__.py +19 -0
  33. pz_core/assembly/resources/compiler.py +310 -0
  34. pz_core/assembly/resources/settings.py +129 -0
  35. pz_core/assembly/routes/__init__.py +7 -0
  36. pz_core/assembly/routes/compiler.py +400 -0
  37. pz_core/assembly/runtime_manifests/__init__.py +13 -0
  38. pz_core/assembly/runtime_manifests/compiler.py +159 -0
  39. pz_core/assembly/settings/__init__.py +17 -0
  40. pz_core/assembly/settings/compiler.py +786 -0
  41. pz_core/assembly/settings/host_project_overrides.py +82 -0
  42. pz_core/assembly/settings/host_runtime_endpoint.py +207 -0
  43. pz_core/authoring/__init__.py +79 -0
  44. pz_core/authoring/app_init_service.py +946 -0
  45. pz_core/authoring/app_versions.py +814 -0
  46. pz_core/authoring/cli.py +192 -0
  47. pz_core/authoring/commands.py +1810 -0
  48. pz_core/authoring/conflicts.py +180 -0
  49. pz_core/authoring/dev_bindings.py +916 -0
  50. pz_core/authoring/dev_git.py +1087 -0
  51. pz_core/authoring/dev_import.py +1061 -0
  52. pz_core/authoring/dev_manifest.py +522 -0
  53. pz_core/authoring/dev_sources.py +1638 -0
  54. pz_core/authoring/env_cli.py +454 -0
  55. pz_core/authoring/files.py +109 -0
  56. pz_core/authoring/ide_projection.py +1129 -0
  57. pz_core/authoring/naming.py +58 -0
  58. pz_core/authoring/official_dev_sources.py +432 -0
  59. pz_core/authoring/official_sources.json +156 -0
  60. pz_core/authoring/orchestration_service.py +558 -0
  61. pz_core/authoring/project_default.jsonc +53 -0
  62. pz_core/authoring/project_defaults.py +88 -0
  63. pz_core/authoring/project_metadata_service.py +199 -0
  64. pz_core/authoring/project_settings_checks.py +51 -0
  65. pz_core/authoring/project_settings_cli.py +299 -0
  66. pz_core/authoring/project_settings_service.py +1700 -0
  67. pz_core/authoring/project_state.py +399 -0
  68. pz_core/authoring/publish_git.py +423 -0
  69. pz_core/authoring/publish_lock.py +188 -0
  70. pz_core/authoring/publish_source.py +195 -0
  71. pz_core/authoring/release.py +1382 -0
  72. pz_core/authoring/repo_keys.py +29 -0
  73. pz_core/authoring/root_cli.py +28 -0
  74. pz_core/authoring/scaffold_service.py +325 -0
  75. pz_core/authoring/sync_service.py +787 -0
  76. pz_core/authoring/templates/app/__init__.py +1 -0
  77. pz_core/authoring/templates/app/api.py +25 -0
  78. pz_core/authoring/templates/app/apps.py +31 -0
  79. pz_core/authoring/templates/app/auth_package_init.py +14 -0
  80. pz_core/authoring/templates/app/auth_readme.py +29 -0
  81. pz_core/authoring/templates/app/configs_package_init.py +14 -0
  82. pz_core/authoring/templates/app/default_env.py +18 -0
  83. pz_core/authoring/templates/app/default_jsonc.py +25 -0
  84. pz_core/authoring/templates/app/locales_readme.py +25 -0
  85. pz_core/authoring/templates/app/migrations_readme.py +19 -0
  86. pz_core/authoring/templates/app/models.py +14 -0
  87. pz_core/authoring/templates/app/package_init.py +8 -0
  88. pz_core/authoring/templates/app/pages_base.py +161 -0
  89. pz_core/authoring/templates/app/pages_readme.py +25 -0
  90. pz_core/authoring/templates/app/public.py +31 -0
  91. pz_core/authoring/templates/app/pyproject.py +77 -0
  92. pz_core/authoring/templates/app/readme.py +74 -0
  93. pz_core/authoring/templates/app/settings.py +46 -0
  94. pz_core/authoring/templates/app/static_app_js.py +24 -0
  95. pz_core/authoring/templates/app/static_readme.py +31 -0
  96. pz_core/authoring/templates/app/template_config_page.py +23 -0
  97. pz_core/authoring/templates/app/template_index_html.py +28 -0
  98. pz_core/authoring/templates/app/templates_readme.py +32 -0
  99. pz_core/authoring/templates/app/urls.py +36 -0
  100. pz_core/authoring/templates/app/views.py +36 -0
  101. pz_core/authoring/templates/project/__init__.py +1 -0
  102. pz_core/authoring/templates/project/agents.py +51 -0
  103. pz_core/authoring/templates/project/apps_container_readme.py +37 -0
  104. pz_core/authoring/templates/project/main_py.py +59 -0
  105. pz_core/authoring/templates/project/project_env.py +19 -0
  106. pz_core/authoring/templates/project/pyproject.py +26 -0
  107. pz_core/authoring/templates/project/pz_env_env.py +65 -0
  108. pz_core/authoring/templates/project/pz_env_jsonc.py +69 -0
  109. pz_core/authoring/templates/project/pz_jsonc.py +12 -0
  110. pz_core/authoring/templates/project/readme.py +94 -0
  111. pz_core/authoring/templates/project/root_gitkeep.py +8 -0
  112. pz_core/authoring/templates/shared/__init__.py +5 -0
  113. pz_core/authoring/templates/shared/text.py +10 -0
  114. pz_core/authoring/venv_service.py +87 -0
  115. pz_core/authoring/workspace.py +167 -0
  116. pz_core/cli.py +291 -0
  117. pz_core/cli_options.py +74 -0
  118. pz_core/core/__init__.py +3 -0
  119. pz_core/core/errors/__init__.py +5 -0
  120. pz_core/core/errors/models.py +117 -0
  121. pz_core/core/events/__init__.py +5 -0
  122. pz_core/core/events/registry.py +54 -0
  123. pz_core/core/extensions/__init__.py +51 -0
  124. pz_core/core/extensions/registry.py +790 -0
  125. pz_core/core/health/__init__.py +6 -0
  126. pz_core/core/health/contracts.py +10 -0
  127. pz_core/core/middlewares/__init__.py +6 -0
  128. pz_core/core/middlewares/models.py +24 -0
  129. pz_core/core/routing/__init__.py +5 -0
  130. pz_core/core/routing/models.py +21 -0
  131. pz_core/core/settings_contracts.py +25 -0
  132. pz_core/docs/README.md +20 -0
  133. pz_core/docs/distribution-README.md +438 -0
  134. pz_core/docs/pz/345/221/275/344/273/244/346/200/273/350/247/210.md +1011 -0
  135. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/00-pz/346/236/266/346/236/204/346/200/273/347/272/262.md +240 -0
  136. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/01-/347/233/256/345/275/225/344/270/216/345/210/206/345/261/202/350/247/204/350/214/203.md +216 -0
  137. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/02-/345/214/205/344/270/216/345/210/206/345/217/221/350/247/204/350/214/203.md +403 -0
  138. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/03-App/346/234/200/345/260/217/345/255/220/345/214/205/350/247/204/350/214/203.md +571 -0
  139. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/04-Settings/344/270/216/351/205/215/347/275/256/350/247/204/350/214/203.md +1177 -0
  140. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/05-/350/265/204/346/272/220/344/270/216/350/277/220/350/241/214/347/233/256/345/275/225/350/247/204/350/214/203.md +575 -0
  141. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/06-/346/225/260/346/215/256/345/272/223/344/270/216/345/217/257/351/200/211/345/237/272/347/241/200/350/256/276/346/226/275/350/247/204/350/214/203.md +499 -0
  142. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/07-App/346/233/277/346/215/242/350/247/204/350/214/203.md +206 -0
  143. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/08-/345/271/263/345/217/260/347/272/247App/344/270/216/350/277/220/350/241/214/346/227/266/345/215/225/344/276/213/350/247/204/350/214/203.md +445 -0
  144. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/09-CLI/344/270/216Worker/345/205/245/345/217/243/350/247/204/350/214/203.md +950 -0
  145. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/10-/346/265/213/350/257/225/344/270/216/345/245/221/347/272/246/350/247/204/350/214/203.md +1001 -0
  146. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/11-/344/273/223/345/272/223/347/234/237/347/233/270/346/272/220/345/234/260/345/233/276.md +102 -0
  147. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/12-/346/236/204/345/273/272/344/270/216/345/217/221/345/270/203/346/243/200/346/237/245/346/270/205/345/215/225.md +171 -0
  148. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/13-/346/255/243/345/274/217Facade/346/200/273/350/241/250.md +402 -0
  149. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/14-/345/210/206/345/261/202/344/270/216/346/211/251/345/261/225/350/247/204/350/214/203.md +550 -0
  150. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/15-/345/255/220/345/214/205/345/274/200/345/217/221/344/275/277/347/224/250/346/211/213/345/206/214.md +1004 -0
  151. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/16-/346/211/251/345/261/225/347/202/271/346/255/243/345/274/217/345/215/217/350/256/256/346/270/205/345/215/225.md +352 -0
  152. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/17-pz.protocols.v1/346/255/243/345/274/217/345/215/217/350/256/256.md +266 -0
  153. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/18-/346/211/251/345/261/225/347/202/271/345/206/262/347/252/201/350/243/201/345/206/263/346/200/273/350/241/250.md +131 -0
  154. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/19-/351/224/231/350/257/257/347/240/201/344/270/216/350/257/212/346/226/255/345/215/217/350/256/256.md +176 -0
  155. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/20-/347/247/201/346/234/211/345/214/205/344/273/223/344/270/216/347/273/237/344/270/200/350/256/244/350/257/201/351/203/250/347/275/262/350/247/204/350/214/203.md +243 -0
  156. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/21-contrib/347/272/246/345/256/232/344/270/216Provider/346/216/245/345/205/245/350/247/204/350/214/203.md +365 -0
  157. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/22-/345/244/232/345/233/275/350/257/255/350/250/200/350/265/204/346/272/220/346/262/273/347/220/206/344/270/216/346/214/211/351/234/200/345/212/240/350/275/275/350/247/204/350/214/203.md +912 -0
  158. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/23-/351/246/226/345/261/217/345/261/225/347/244/272/344/270/216/351/246/226/345/270/247/347/250/263/345/256/232/350/247/204/350/214/203.md +269 -0
  159. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/24-pz/345/220/257/345/212/250/344/270/216/350/277/220/350/241/214/346/227/266/347/274/226/350/257/221/346/265/201/347/250/213.md +245 -0
  160. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/25-/351/235/242/345/220/221/345/257/271/350/261/241/345/274/200/345/217/221/350/247/204/350/214/203.md +300 -0
  161. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/README.md +98 -0
  162. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/00-legacy_core/346/240/207/345/207/206pip/345/214/205/345/214/226/351/207/215/346/236/204/346/200/273/347/272/262.md +1073 -0
  163. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/01-/347/233/256/345/275/225/344/270/216/345/210/206/345/261/202/351/207/215/346/236/204/346/211/247/350/241/214/346/226/271/346/241/210.md +224 -0
  164. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/02-/345/214/205/344/270/216/345/210/206/345/217/221/350/247/204/350/214/203-/345/220/253/345/216/206/345/217/262/345/217/243/345/276/204.md +671 -0
  165. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/13-/344/270/200/346/254/241/346/200/247/345/256/236/346/226/275/346/270/205/345/215/225.md +387 -0
  166. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/14-/345/255/220/345/214/205/351/200/202/351/205/215/346/224/271/351/200/240/346/270/205/345/215/225.md +592 -0
  167. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/15-infra/350/243/201/345/211/252/344/270/216/350/220/275/344/275/215/346/270/205/345/215/225.md +81 -0
  168. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/19-core/345/215/225/344/270/200/346/255/243/345/274/217/346/226/271/346/241/210/346/224/266/346/225/233/346/211/247/350/241/214/346/270/205/345/215/225.md +161 -0
  169. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/25-/345/215/217/350/256/256/345/210/260/346/272/220/347/240/201/345/267/256/350/267/235/346/270/205/345/215/225.md +377 -0
  170. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/26-cutover/345/256/214/345/267/245/346/243/200/346/237/245/346/270/205/345/215/225.md +117 -0
  171. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/29-/345/244/232/345/233/275/350/257/255/350/250/200/350/265/204/346/272/220/346/262/273/347/220/206/344/270/216/346/214/211/351/234/200/345/212/240/350/275/275/350/247/204/350/214/203-/345/220/253/350/277/201/347/247/273/347/255/226/347/225/245.md +956 -0
  172. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/99-/350/265/204/346/272/220/346/224/266/345/217/243/345/220/216/347/273/255TODO.md +84 -0
  173. pz_core/docs//345/217/221/347/211/210/345/211/215/346/270/205/345/215/225-4.0.11.md +84 -0
  174. pz_core/docs//346/226/260/346/211/213/346/214/207/345/215/227.md +422 -0
  175. pz_core/infra/__init__.py +17 -0
  176. pz_core/infra/db/__init__.py +23 -0
  177. pz_core/infra/db/contracts.py +73 -0
  178. pz_core/infra/health/__init__.py +5 -0
  179. pz_core/infra/health/contracts.py +8 -0
  180. pz_core/infra/kv/__init__.py +5 -0
  181. pz_core/infra/kv/contracts.py +17 -0
  182. pz_core/infra/observability/__init__.py +23 -0
  183. pz_core/infra/observability/contracts.py +142 -0
  184. pz_core/infra/resilience/__init__.py +5 -0
  185. pz_core/infra/resilience/contracts.py +17 -0
  186. pz_core/infra/resources/__init__.py +5 -0
  187. pz_core/infra/resources/contracts.py +16 -0
  188. pz_core/infra/settings/__init__.py +17 -0
  189. pz_core/infra/settings/models.py +81 -0
  190. pz_core/infra/storage/__init__.py +5 -0
  191. pz_core/infra/storage/ports.py +27 -0
  192. pz_core/project_root_commands.py +282 -0
  193. pz_core/project_runtime_cli.py +344 -0
  194. pz_core/project_sources.py +253 -0
  195. pz_core/pz_launcher.py +209 -0
  196. pz_core/root_cli.py +70 -0
  197. pz_core/runtime/__init__.py +229 -0
  198. pz_core/runtime/access.py +86 -0
  199. pz_core/runtime/adapters/__init__.py +5 -0
  200. pz_core/runtime/adapters/base.py +18 -0
  201. pz_core/runtime/asyncio_bridge.py +18 -0
  202. pz_core/runtime/bindings/__init__.py +5 -0
  203. pz_core/runtime/bindings/container.py +50 -0
  204. pz_core/runtime/cli/__init__.py +5 -0
  205. pz_core/runtime/cli/_args.py +67 -0
  206. pz_core/runtime/cli/app_commands.py +417 -0
  207. pz_core/runtime/cli/check.py +214 -0
  208. pz_core/runtime/cli/db.py +297 -0
  209. pz_core/runtime/cli/main.py +89 -0
  210. pz_core/runtime/cli/resources.py +280 -0
  211. pz_core/runtime/discovery.py +23 -0
  212. pz_core/runtime/environment_integrity.py +157 -0
  213. pz_core/runtime/errors.py +5 -0
  214. pz_core/runtime/events.py +87 -0
  215. pz_core/runtime/facades/__init__.py +38 -0
  216. pz_core/runtime/facades/_capabilities.py +46 -0
  217. pz_core/runtime/facades/cache.py +103 -0
  218. pz_core/runtime/facades/database.py +71 -0
  219. pz_core/runtime/facades/events.py +380 -0
  220. pz_core/runtime/facades/health.py +101 -0
  221. pz_core/runtime/facades/mail.py +121 -0
  222. pz_core/runtime/facades/observability.py +102 -0
  223. pz_core/runtime/facades/providers.py +75 -0
  224. pz_core/runtime/facades/resources.py +52 -0
  225. pz_core/runtime/facades/storage.py +296 -0
  226. pz_core/runtime/health/__init__.py +5 -0
  227. pz_core/runtime/health/service.py +102 -0
  228. pz_core/runtime/host.py +188 -0
  229. pz_core/runtime/host_runner.py +282 -0
  230. pz_core/runtime/http/__init__.py +20 -0
  231. pz_core/runtime/http/app.py +576 -0
  232. pz_core/runtime/http_timing.py +173 -0
  233. pz_core/runtime/invocation.py +29 -0
  234. pz_core/runtime/json_safe.py +47 -0
  235. pz_core/runtime/lifecycle/__init__.py +25 -0
  236. pz_core/runtime/lifecycle/manager.py +533 -0
  237. pz_core/runtime/plan.py +214 -0
  238. pz_core/runtime/plan_context.py +33 -0
  239. pz_core/runtime/plan_snapshot.py +177 -0
  240. pz_core/runtime/registries/__init__.py +27 -0
  241. pz_core/runtime/registries/capabilities.py +101 -0
  242. pz_core/runtime/registries/providers.py +396 -0
  243. pz_core/runtime/resource_assets.py +344 -0
  244. pz_core/runtime/run_cli.py +211 -0
  245. pz_core/runtime/settings.py +888 -0
  246. pz_core/runtime/worker/__init__.py +21 -0
  247. pz_core/runtime/worker/engine.py +921 -0
  248. pz_core/runtime/worker/runtime.py +25 -0
  249. pz_core/testing/__init__.py +15 -0
  250. pz_core/testing/doc_route_contracts.py +305 -0
  251. pz_core/utils/__init__.py +44 -0
  252. pz_core/utils/env.py +65 -0
  253. pz_core/utils/project_jsonc/__init__.py +29 -0
  254. pz_core/utils/project_jsonc/document.py +420 -0
  255. pz_core/utils/project_settings.py +99 -0
  256. pz_foundation/__init__.py +50 -0
  257. pz_foundation/_contracts.py +81 -0
  258. pz_foundation/_errors.py +34 -0
  259. pz_foundation/api.py +14 -0
  260. pz_foundation/apps.py +127 -0
  261. pz_foundation/auth/__init__.py +1 -0
  262. pz_foundation/cache_control.py +233 -0
  263. pz_foundation/cli/__init__.py +2 -0
  264. pz_foundation/cli/workers.py +565 -0
  265. pz_foundation/configs/__init__.py +0 -0
  266. pz_foundation/configs/default.env +15 -0
  267. pz_foundation/configs/default.jsonc +452 -0
  268. pz_foundation/db/__init__.py +94 -0
  269. pz_foundation/db/aerich_executor.py +664 -0
  270. pz_foundation/db/config.py +358 -0
  271. pz_foundation/db/connection_manager.py +689 -0
  272. pz_foundation/db/connection_probe.py +204 -0
  273. pz_foundation/db/database.py +1291 -0
  274. pz_foundation/db/deps.py +47 -0
  275. pz_foundation/db/lifecycle_status.py +85 -0
  276. pz_foundation/db/migrations.py +477 -0
  277. pz_foundation/db/mysql.py +57 -0
  278. pz_foundation/db/postgresql.py +409 -0
  279. pz_foundation/db/production_pool_fallback.py +143 -0
  280. pz_foundation/db/public.py +45 -0
  281. pz_foundation/db/session.py +369 -0
  282. pz_foundation/db/sqlite.py +15 -0
  283. pz_foundation/db/tortoise_manager.py +724 -0
  284. pz_foundation/db/tortoise_psycopg.py +148 -0
  285. pz_foundation/docs/README.md +18 -0
  286. pz_foundation/docs/distribution-README.md +319 -0
  287. pz_foundation/docs/infra/350/243/201/345/211/252/344/270/216/350/220/275/344/275/215/350/257/264/346/230/216.md +39 -0
  288. pz_foundation/docs//345/205/254/345/274/200/345/205/215/350/264/271/346/216/245/345/217/243/351/230/262/346/273/245/347/224/250/344/270/216/344/272/272/346/234/272/346/240/241/351/252/214.md +680 -0
  289. pz_foundation/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +288 -0
  290. pz_foundation/docs//350/267/257/347/224/261/344/270/216URL/345/244/204/347/220/206/350/247/204/350/214/203.md +119 -0
  291. pz_foundation/health.py +105 -0
  292. pz_foundation/host/__init__.py +11 -0
  293. pz_foundation/host/builder.py +34 -0
  294. pz_foundation/host/cache_runtime.py +44 -0
  295. pz_foundation/host/db/__init__.py +17 -0
  296. pz_foundation/host/db/aerich_config.py +36 -0
  297. pz_foundation/host/db/config.py +106 -0
  298. pz_foundation/host/db/connection_manager.py +48 -0
  299. pz_foundation/host/db/deps.py +5 -0
  300. pz_foundation/host/db/orm_retry_patch.py +566 -0
  301. pz_foundation/host/db/request_adapter.py +325 -0
  302. pz_foundation/host/db/router.py +28 -0
  303. pz_foundation/host/db/session.py +284 -0
  304. pz_foundation/host/db/tortoise_manager.py +10 -0
  305. pz_foundation/host/idempotency.py +132 -0
  306. pz_foundation/host/lifespan.py +247 -0
  307. pz_foundation/host/redis_runtime.py +100 -0
  308. pz_foundation/host/web.py +790 -0
  309. pz_foundation/infra_provider.py +236 -0
  310. pz_foundation/kv/__init__.py +25 -0
  311. pz_foundation/kv/cache.py +1166 -0
  312. pz_foundation/kv/deps.py +84 -0
  313. pz_foundation/kv/public.py +25 -0
  314. pz_foundation/kv/redis_manager.py +1531 -0
  315. pz_foundation/lazy_exports.py +43 -0
  316. pz_foundation/lazy_imports.py +124 -0
  317. pz_foundation/lifecycle.py +392 -0
  318. pz_foundation/managed_workers.py +1117 -0
  319. pz_foundation/middlewares/__init__.py +26 -0
  320. pz_foundation/middlewares/_settings.py +250 -0
  321. pz_foundation/middlewares/analytics.py +124 -0
  322. pz_foundation/middlewares/cache_control.py +156 -0
  323. pz_foundation/middlewares/compression.py +202 -0
  324. pz_foundation/middlewares/cors.py +62 -0
  325. pz_foundation/middlewares/geo_country.py +44 -0
  326. pz_foundation/middlewares/inner_router.py +50 -0
  327. pz_foundation/middlewares/rate_limited/__init__.py +3 -0
  328. pz_foundation/middlewares/rate_limited/key_limiter.py +115 -0
  329. pz_foundation/middlewares/request_logging.py +104 -0
  330. pz_foundation/middlewares/route_owner.py +309 -0
  331. pz_foundation/middlewares/security_csrf.py +44 -0
  332. pz_foundation/middlewares/security_headers/__init__.py +4 -0
  333. pz_foundation/middlewares/security_headers/conflicts.py +44 -0
  334. pz_foundation/middlewares/security_headers/csp_nonce.py +200 -0
  335. pz_foundation/middlewares/security_headers/security_headers.py +44 -0
  336. pz_foundation/migrations/__init__.py +1 -0
  337. pz_foundation/migrations/pz_foundation/__init__.py +1 -0
  338. pz_foundation/models.py +22 -0
  339. pz_foundation/notifications/__init__.py +23 -0
  340. pz_foundation/notifications/email.py +542 -0
  341. pz_foundation/notifications/public.py +31 -0
  342. pz_foundation/observability/__init__.py +71 -0
  343. pz_foundation/observability/http.py +34 -0
  344. pz_foundation/observability/logger/__init__.py +49 -0
  345. pz_foundation/observability/logger/_bot_settings.py +126 -0
  346. pz_foundation/observability/logger/bot_message.py +592 -0
  347. pz_foundation/observability/logger/core.py +385 -0
  348. pz_foundation/observability/logger/delivery_audit.py +84 -0
  349. pz_foundation/observability/logger/feishu_bot.py +199 -0
  350. pz_foundation/observability/logger/telegram_bot.py +194 -0
  351. pz_foundation/observability/metrics.py +365 -0
  352. pz_foundation/observability/runtime.py +68 -0
  353. pz_foundation/public.py +405 -0
  354. pz_foundation/resources/__init__.py +12 -0
  355. pz_foundation/resources/builder.py +900 -0
  356. pz_foundation/resources/images.py +363 -0
  357. pz_foundation/root_cli.py +20 -0
  358. pz_foundation/routing/__init__.py +203 -0
  359. pz_foundation/routing/canonical.py +486 -0
  360. pz_foundation/routing/convertors.py +82 -0
  361. pz_foundation/routing/declarations.py +843 -0
  362. pz_foundation/routing/exports.py +148 -0
  363. pz_foundation/routing/loaders.py +138 -0
  364. pz_foundation/routing/manifest.py +215 -0
  365. pz_foundation/routing/manifest_provider.py +47 -0
  366. pz_foundation/routing/mounts.py +101 -0
  367. pz_foundation/routing/ordering.py +172 -0
  368. pz_foundation/routing/registry.py +133 -0
  369. pz_foundation/routing/utils.py +28 -0
  370. pz_foundation/runtime.py +234 -0
  371. pz_foundation/settings.py +253 -0
  372. pz_foundation/settings_normalization.py +130 -0
  373. pz_foundation/storage/__init__.py +25 -0
  374. pz_foundation/storage/local.py +209 -0
  375. pz_foundation/storage/public.py +106 -0
  376. pz_foundation/storage/s3.py +116 -0
  377. pz_foundation/storage/service.py +234 -0
  378. pz_foundation/urls.py +19 -0
  379. pz_foundation/utils/__init__.py +6 -0
  380. pz_foundation/utils/merge.py +160 -0
  381. pz_foundation/worker_replicas.py +55 -0
  382. pz_settings_center/__init__.py +5 -0
  383. pz_settings_center/api/__init__.py +5 -0
  384. pz_settings_center/api/runtime_overrides.py +360 -0
  385. pz_settings_center/apps.py +28 -0
  386. pz_settings_center/configs/__init__.py +0 -0
  387. pz_settings_center/configs/default.env +2 -0
  388. pz_settings_center/configs/default.jsonc +1 -0
  389. pz_settings_center/docs/01-settings_center/350/203/275/345/212/233/350/276/271/347/225/214.md +124 -0
  390. pz_settings_center/docs/README.md +12 -0
  391. pz_settings_center/docs/distribution-README.md +150 -0
  392. pz_settings_center/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +48 -0
  393. pz_settings_center/integration_payload.py +18 -0
  394. pz_settings_center/project_helpers.py +405 -0
  395. pz_settings_center/public.py +139 -0
  396. pz_settings_center/routing_helpers.py +73 -0
  397. pz_settings_center/runtime_override_provider.py +61 -0
  398. pz_settings_center/typed_settings.py +324 -0
  399. pz_settings_center/urls.py +9 -0
@@ -0,0 +1,576 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from importlib import import_module
5
+ import inspect
6
+ import json
7
+ from pathlib import Path
8
+ from dataclasses import replace
9
+ from typing import Any, Awaitable, Callable
10
+ from uuid import uuid4
11
+
12
+ from pz_core.runtime.errors import PzError
13
+ from pz_core.runtime.plan_context import active_runtime_plan
14
+ from pz_core.core.middlewares import MiddlewareDecl
15
+ from pz_core.runtime.adapters import RuntimeAdapter
16
+ from pz_core.runtime.bindings import RuntimeBindings, compile_runtime_bindings
17
+ from pz_core.runtime.facades import HealthFacade
18
+ from pz_core.runtime.lifecycle import (
19
+ LifecycleState,
20
+ activate_runtime_plan,
21
+ activate_runtime_plan_async,
22
+ bind_runtime_plan,
23
+ shutdown_runtime_plan,
24
+ shutdown_runtime_plan_async,
25
+ )
26
+ from pz_core.runtime.plan import RuntimePlan, compile_runtime_plan
27
+ from pz_core.runtime.plan_snapshot import write_runtime_plan_snapshot_if_requested
28
+ from pz_core.runtime.settings import active_settings_project, bound_settings_snapshot
29
+ from pz_core.runtime.http_timing import instrument_asgi_timing
30
+
31
+ ASGIApp = Callable[[dict[str, Any], Any, Any], Awaitable[None]]
32
+
33
+
34
+ def _http_error_from_exc(exc: PzError) -> dict[str, object]:
35
+ return _error_payload(
36
+ code=exc.code,
37
+ owner=exc.owner,
38
+ action=exc.action,
39
+ summary=exc.summary or exc.message,
40
+ message=exc.message,
41
+ )
42
+
43
+
44
+ def _decode_header_bytes(raw: object, *, action: str) -> bytes:
45
+ if isinstance(raw, bytes):
46
+ return raw
47
+ raise PzError(
48
+ code="PZ_HTTP_REQUEST_ID_INVALID",
49
+ message="x-request-id header must use bytes values.",
50
+ stage="http",
51
+ owner="runtime.http",
52
+ action=action,
53
+ summary="HTTP x-request-id header is invalid.",
54
+ )
55
+
56
+
57
+ def _read_headers(scope: dict[str, Any], *, action: str) -> list[tuple[bytes, bytes]]:
58
+ if "headers" not in scope:
59
+ return []
60
+ headers = scope.get("headers")
61
+ if headers is None:
62
+ raise PzError(
63
+ code="PZ_HTTP_HEADERS_INVALID",
64
+ message="HTTP scope headers must not be null when configured.",
65
+ stage="http",
66
+ owner="runtime.http",
67
+ action=action,
68
+ summary="HTTP headers are invalid.",
69
+ )
70
+ if not isinstance(headers, list):
71
+ raise PzError(
72
+ code="PZ_HTTP_HEADERS_INVALID",
73
+ message="HTTP scope headers must be declared as a list of header pairs.",
74
+ stage="http",
75
+ owner="runtime.http",
76
+ action=action,
77
+ summary="HTTP headers are invalid.",
78
+ )
79
+ normalized: list[tuple[bytes, bytes]] = []
80
+ for index, item in enumerate(headers):
81
+ if not isinstance(item, (list, tuple)) or len(item) != 2:
82
+ raise PzError(
83
+ code="PZ_HTTP_HEADERS_INVALID",
84
+ message=f"HTTP header entry at index {index} must be a 2-item pair.",
85
+ stage="http",
86
+ owner="runtime.http",
87
+ action=action,
88
+ summary="HTTP headers are invalid.",
89
+ )
90
+ key, value = item
91
+ try:
92
+ normalized_key = _decode_header_bytes(key, action=action)
93
+ except PzError as exc:
94
+ raise PzError(
95
+ code="PZ_HTTP_HEADERS_INVALID",
96
+ message=f"HTTP header entry at index {index} must use bytes values.",
97
+ stage="http",
98
+ owner="runtime.http",
99
+ action=action,
100
+ summary="HTTP headers are invalid.",
101
+ ) from exc
102
+ try:
103
+ normalized_value = _decode_header_bytes(value, action=action)
104
+ except PzError as exc:
105
+ if normalized_key.lower() == b"x-request-id":
106
+ raise exc
107
+ raise PzError(
108
+ code="PZ_HTTP_HEADERS_INVALID",
109
+ message=f"HTTP header entry at index {index} must use bytes values.",
110
+ stage="http",
111
+ owner="runtime.http",
112
+ action=action,
113
+ summary="HTTP headers are invalid.",
114
+ ) from exc
115
+ normalized.append((normalized_key, normalized_value))
116
+ return normalized
117
+
118
+
119
+ def _request_id(scope: dict[str, Any]) -> str:
120
+ for key, value in _read_headers(scope, action="dispatch"):
121
+ if key.lower() == b"x-request-id":
122
+ raw_value = value
123
+ try:
124
+ decoded = raw_value.decode("utf-8").strip()
125
+ except UnicodeDecodeError as exc:
126
+ raise PzError(
127
+ code="PZ_HTTP_REQUEST_ID_INVALID",
128
+ message="x-request-id header must be valid UTF-8.",
129
+ stage="http",
130
+ owner="runtime.http",
131
+ action="dispatch",
132
+ summary="HTTP x-request-id header is invalid.",
133
+ ) from exc
134
+ if decoded:
135
+ return decoded
136
+ raise PzError(
137
+ code="PZ_HTTP_REQUEST_ID_INVALID",
138
+ message="x-request-id header must be a non-empty UTF-8 string.",
139
+ stage="http",
140
+ owner="runtime.http",
141
+ action="dispatch",
142
+ summary="HTTP x-request-id header is invalid.",
143
+ )
144
+ return uuid4().hex
145
+
146
+
147
+ def _read_scope_path(scope: dict[str, Any]) -> str:
148
+ if "path" not in scope:
149
+ return "/"
150
+ raw_path = scope.get("path")
151
+ if not isinstance(raw_path, str) or not raw_path.strip():
152
+ raise PzError(
153
+ code="PZ_HTTP_PATH_INVALID",
154
+ message="HTTP scope path must be a non-empty string.",
155
+ stage="http",
156
+ owner="runtime.http",
157
+ action="dispatch",
158
+ summary="HTTP scope path is invalid.",
159
+ )
160
+ if not raw_path.startswith("/"):
161
+ raise PzError(
162
+ code="PZ_HTTP_PATH_INVALID",
163
+ message="HTTP scope path must start with '/'.",
164
+ stage="http",
165
+ owner="runtime.http",
166
+ action="dispatch",
167
+ summary="HTTP scope path is invalid.",
168
+ )
169
+ return raw_path
170
+
171
+
172
+ def _read_scope_type(scope: dict[str, Any]) -> str:
173
+ raw_type = scope.get("type")
174
+ if not isinstance(raw_type, str) or not raw_type.strip():
175
+ raise PzError(
176
+ code="PZ_HTTP_SCOPE_TYPE_INVALID",
177
+ message="HTTP scope type must be a non-empty string.",
178
+ stage="http",
179
+ owner="runtime.http",
180
+ action="dispatch",
181
+ summary="HTTP scope type is invalid.",
182
+ )
183
+ return raw_type
184
+
185
+
186
+ def _read_scope_method(scope: dict[str, Any]) -> str | None:
187
+ if "method" not in scope:
188
+ return None
189
+ raw_method = scope.get("method")
190
+ if not isinstance(raw_method, str) or not raw_method.strip():
191
+ raise PzError(
192
+ code="PZ_HTTP_METHOD_INVALID",
193
+ message="HTTP scope method must be a non-empty string when configured.",
194
+ stage="http",
195
+ owner="runtime.http",
196
+ action="dispatch",
197
+ summary="HTTP scope method is invalid.",
198
+ )
199
+ return raw_method
200
+
201
+
202
+ async def _send_json(send: Any, status: int, payload: dict[str, Any], *, request_id: str) -> None:
203
+ body_payload = dict(payload)
204
+ body_payload.setdefault("request_id", request_id)
205
+ body = json.dumps(body_payload, ensure_ascii=True, sort_keys=True).encode("utf-8")
206
+ headers = [
207
+ (b"content-type", b"application/json"),
208
+ (b"content-length", str(len(body)).encode("ascii")),
209
+ (b"x-request-id", request_id.encode("utf-8")),
210
+ ]
211
+ await send({"type": "http.response.start", "status": status, "headers": headers})
212
+ await send({"type": "http.response.body", "body": body})
213
+
214
+
215
+ def _error_payload(
216
+ *,
217
+ code: str,
218
+ owner: str,
219
+ action: str,
220
+ summary: str,
221
+ **extra: object,
222
+ ) -> dict[str, object]:
223
+ payload: dict[str, object] = {
224
+ "status": "error",
225
+ "code": code,
226
+ "stage": "http",
227
+ "owner": owner,
228
+ "action": action,
229
+ "summary": summary,
230
+ }
231
+ payload.update(extra)
232
+ return payload
233
+
234
+
235
+ def _import_middleware_factory(decl: MiddlewareDecl) -> Callable[..., ASGIApp]:
236
+ module_name, _, attr_name = decl.factory.partition(":")
237
+ try:
238
+ module = import_module(module_name)
239
+ factory = getattr(module, attr_name)
240
+ except Exception as exc:
241
+ raise PzError(
242
+ code="PZ_MIDDLEWARE_FACTORY_IMPORT_FAILED",
243
+ message=f"Failed to import middleware factory '{decl.factory}': {exc}",
244
+ stage="http",
245
+ owner=decl.owner,
246
+ action="create_application_runtime",
247
+ ) from exc
248
+ if not callable(factory):
249
+ raise PzError(
250
+ code="PZ_MIDDLEWARE_FACTORY_INVALID",
251
+ message=f"Middleware factory '{decl.factory}' is not callable.",
252
+ stage="http",
253
+ owner=decl.owner,
254
+ action="create_application_runtime",
255
+ )
256
+ return factory
257
+
258
+
259
+ def apply_runtime_middlewares(
260
+ app: ASGIApp,
261
+ *,
262
+ plan: RuntimePlan,
263
+ bindings: RuntimeBindings,
264
+ ) -> ASGIApp:
265
+ host_app = app
266
+ wrapped = instrument_asgi_timing(app, label="app.core")
267
+ for decl in reversed(plan.middleware_manifest.middlewares):
268
+ factory = _import_middleware_factory(decl)
269
+ try:
270
+ runtime_params = dict(decl.params or {})
271
+ call_kwargs = {
272
+ "bindings": bindings,
273
+ "plan": plan,
274
+ "decl": decl,
275
+ "params": runtime_params,
276
+ "host_app": host_app,
277
+ }
278
+ for name, value in runtime_params.items():
279
+ if name not in call_kwargs:
280
+ call_kwargs[name] = value
281
+ try:
282
+ signature = inspect.signature(factory)
283
+ except (TypeError, ValueError):
284
+ signature = None
285
+ if signature is None:
286
+ filtered_kwargs = call_kwargs
287
+ else:
288
+ accepts_var_kwargs = any(
289
+ parameter.kind is inspect.Parameter.VAR_KEYWORD
290
+ for parameter in signature.parameters.values()
291
+ )
292
+ if accepts_var_kwargs:
293
+ filtered_kwargs = call_kwargs
294
+ else:
295
+ filtered_kwargs = {
296
+ name: value
297
+ for name, value in call_kwargs.items()
298
+ if name in signature.parameters
299
+ }
300
+ candidate = factory(wrapped, **filtered_kwargs)
301
+ except PzError:
302
+ raise
303
+ except Exception as exc:
304
+ raise PzError(
305
+ code="PZ_MIDDLEWARE_FACTORY_FAILED",
306
+ message=f"Middleware '{decl.id}' factory execution failed: {exc}",
307
+ stage="http",
308
+ owner=decl.owner,
309
+ action="create_application_runtime",
310
+ ) from exc
311
+ if not callable(candidate):
312
+ raise PzError(
313
+ code="PZ_MIDDLEWARE_FACTORY_INVALID",
314
+ message=f"Middleware '{decl.id}' did not return an ASGI callable.",
315
+ stage="http",
316
+ owner=decl.owner,
317
+ action="create_application_runtime",
318
+ )
319
+ wrapped = instrument_asgi_timing(candidate, label=f"middleware:{decl.id}")
320
+ return instrument_asgi_timing(wrapped, label="middleware.total")
321
+
322
+
323
+ @dataclass(frozen=True, slots=True)
324
+ class ApplicationRuntime:
325
+ adapter: RuntimeAdapter
326
+ http_app: ASGIApp | None = None
327
+
328
+ @property
329
+ def pz_runtime(self) -> "ApplicationRuntime":
330
+ return self
331
+
332
+ @property
333
+ def plan(self) -> RuntimePlan:
334
+ return self.adapter.plan
335
+
336
+ @property
337
+ def state(self) -> LifecycleState:
338
+ return self.adapter.state
339
+
340
+ @property
341
+ def bindings(self) -> RuntimeBindings:
342
+ return self.adapter.bindings
343
+
344
+ def activate(self) -> "ApplicationRuntime":
345
+ if self.state.phase == "started":
346
+ return self
347
+ started_state = activate_runtime_plan(
348
+ self.plan,
349
+ self.state,
350
+ bindings=self.bindings,
351
+ host=self,
352
+ )
353
+ bindings = replace(
354
+ self.bindings,
355
+ health=HealthFacade(
356
+ self.plan,
357
+ started_state,
358
+ providers=self.bindings.providers,
359
+ ),
360
+ )
361
+ runtime = replace(
362
+ self,
363
+ adapter=replace(
364
+ self.adapter,
365
+ state=started_state,
366
+ bindings=bindings,
367
+ ),
368
+ )
369
+ return replace(runtime, http_app=_compile_http_app(runtime))
370
+
371
+ def shutdown(self) -> "ApplicationRuntime":
372
+ if self.state.phase == "stopped":
373
+ return self
374
+ stopped_state = shutdown_runtime_plan(
375
+ self.plan,
376
+ self.state,
377
+ bindings=self.bindings,
378
+ host=self,
379
+ )
380
+ bindings = replace(
381
+ self.bindings,
382
+ health=HealthFacade(
383
+ self.plan,
384
+ stopped_state,
385
+ providers=self.bindings.providers,
386
+ ),
387
+ )
388
+ runtime = replace(
389
+ self,
390
+ adapter=replace(
391
+ self.adapter,
392
+ state=stopped_state,
393
+ bindings=bindings,
394
+ ),
395
+ )
396
+ return replace(runtime, http_app=_compile_http_app(runtime))
397
+
398
+ async def activate_async(self) -> "ApplicationRuntime":
399
+ if self.state.phase == "started":
400
+ return self
401
+ started_state = await activate_runtime_plan_async(
402
+ self.plan,
403
+ self.state,
404
+ bindings=self.bindings,
405
+ host=self,
406
+ )
407
+ bindings = replace(
408
+ self.bindings,
409
+ health=HealthFacade(
410
+ self.plan,
411
+ started_state,
412
+ providers=self.bindings.providers,
413
+ ),
414
+ )
415
+ runtime = replace(
416
+ self,
417
+ adapter=replace(
418
+ self.adapter,
419
+ state=started_state,
420
+ bindings=bindings,
421
+ ),
422
+ )
423
+ return replace(runtime, http_app=_compile_http_app(runtime))
424
+
425
+ async def shutdown_async(self) -> "ApplicationRuntime":
426
+ if self.state.phase == "stopped":
427
+ return self
428
+ stopped_state = await shutdown_runtime_plan_async(
429
+ self.plan,
430
+ self.state,
431
+ bindings=self.bindings,
432
+ host=self,
433
+ )
434
+ bindings = replace(
435
+ self.bindings,
436
+ health=HealthFacade(
437
+ self.plan,
438
+ stopped_state,
439
+ providers=self.bindings.providers,
440
+ ),
441
+ )
442
+ runtime = replace(
443
+ self,
444
+ adapter=replace(
445
+ self.adapter,
446
+ state=stopped_state,
447
+ bindings=bindings,
448
+ ),
449
+ )
450
+ return replace(runtime, http_app=_compile_http_app(runtime))
451
+
452
+ async def _dispatch(self, scope: dict[str, Any], receive: Any, send: Any) -> None:
453
+ request_id = uuid4().hex
454
+ try:
455
+ request_id = _request_id(scope)
456
+ except PzError as exc:
457
+ await _send_json(send, 500, _http_error_from_exc(exc), request_id=request_id)
458
+ return
459
+ try:
460
+ scope_type = _read_scope_type(scope)
461
+ except PzError as exc:
462
+ await _send_json(send, 500, _http_error_from_exc(exc), request_id=request_id)
463
+ return
464
+ if scope_type != "http":
465
+ await _send_json(
466
+ send,
467
+ 500,
468
+ _error_payload(
469
+ code="PZ_HTTP_UNSUPPORTED_SCOPE",
470
+ owner="runtime.http",
471
+ action="dispatch",
472
+ summary="HTTP runtime only supports ASGI http scope.",
473
+ scope_type=scope_type,
474
+ ),
475
+ request_id=request_id,
476
+ )
477
+ return
478
+ try:
479
+ _read_scope_method(scope)
480
+ except PzError as exc:
481
+ await _send_json(send, 500, _http_error_from_exc(exc), request_id=request_id)
482
+ return
483
+
484
+ try:
485
+ path = _read_scope_path(scope)
486
+ except PzError as exc:
487
+ await _send_json(send, 500, _http_error_from_exc(exc), request_id=request_id)
488
+ return
489
+ await _send_json(
490
+ send,
491
+ 404,
492
+ _error_payload(
493
+ code="PZ_HTTP_ROUTE_NOT_FOUND",
494
+ owner="runtime.http",
495
+ action="dispatch",
496
+ summary="Route was not found in the formal HTTP runtime.",
497
+ path=path,
498
+ ),
499
+ request_id=request_id,
500
+ )
501
+
502
+ async def __call__(self, scope: dict[str, Any], receive: Any, send: Any) -> None:
503
+ if self.http_app is None:
504
+ raise PzError(
505
+ code="PZ_HTTP_APP_MISSING",
506
+ message="Formal HTTP runtime requires a compiled ASGI application.",
507
+ stage="http",
508
+ owner="runtime.http",
509
+ action="__call__",
510
+ summary="HTTP runtime cannot serve requests without a compiled ASGI application.",
511
+ )
512
+ await self.http_app(scope, receive, send)
513
+
514
+
515
+ def _compile_http_app(runtime: ApplicationRuntime) -> ASGIApp:
516
+ project_dir = str(runtime.plan.project.project_dir)
517
+
518
+ async def _base(scope: dict[str, Any], receive: Any, send: Any) -> None:
519
+ with (
520
+ bound_settings_snapshot(runtime.plan.settings, project_dir=project_dir),
521
+ active_settings_project(project_dir),
522
+ active_runtime_plan(runtime.plan),
523
+ ):
524
+ await runtime._dispatch(scope, receive, send)
525
+
526
+ with active_settings_project(project_dir), active_runtime_plan(runtime.plan):
527
+ return apply_runtime_middlewares(
528
+ _base,
529
+ plan=runtime.plan,
530
+ bindings=runtime.bindings,
531
+ )
532
+
533
+
534
+ def create_application_runtime(
535
+ project_dir: str | Path | None = None,
536
+ *,
537
+ installed_apps: tuple[str, ...] | None = None,
538
+ compile_http_app: bool = True,
539
+ ) -> ApplicationRuntime:
540
+ plan = compile_runtime_plan(
541
+ project_dir=project_dir,
542
+ installed_apps=installed_apps,
543
+ include_cli_manifest=False,
544
+ )
545
+ write_runtime_plan_snapshot_if_requested(plan)
546
+ state = bind_runtime_plan(plan)
547
+ bindings = compile_runtime_bindings(plan, state)
548
+ runtime = ApplicationRuntime(
549
+ adapter=RuntimeAdapter(kind="http", plan=plan, state=state, bindings=bindings)
550
+ )
551
+ if not compile_http_app:
552
+ return runtime
553
+ return replace(runtime, http_app=_compile_http_app(runtime))
554
+
555
+
556
+ def create_application_runtime_from_plan(
557
+ plan: RuntimePlan,
558
+ *,
559
+ compile_http_app: bool = True,
560
+ ) -> ApplicationRuntime:
561
+ if not isinstance(plan, RuntimePlan):
562
+ raise PzError(
563
+ code="PZ_APPLICATION_RUNTIME_PLAN_INVALID",
564
+ message="Application runtime requires a compiled RuntimePlan.",
565
+ stage="http",
566
+ owner="runtime.http",
567
+ action="create_application_runtime_from_plan",
568
+ )
569
+ state = bind_runtime_plan(plan)
570
+ bindings = compile_runtime_bindings(plan, state)
571
+ runtime = ApplicationRuntime(
572
+ adapter=RuntimeAdapter(kind="http", plan=plan, state=state, bindings=bindings)
573
+ )
574
+ if not compile_http_app:
575
+ return runtime
576
+ return replace(runtime, http_app=_compile_http_app(runtime))