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,297 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from dataclasses import asdict, dataclass, replace
5
+ import json
6
+ import sys
7
+ from typing import Any
8
+
9
+ from pz_core.infra.db import (
10
+ DatabaseMigrationPort,
11
+ DatabaseMigrationSnapshot,
12
+ DbOwner,
13
+ MigrationSource,
14
+ )
15
+ from pz_core.runtime import RuntimePlan, compile_runtime_bindings, compile_runtime_plan
16
+ from pz_core.runtime.cli._args import PzArgumentParser, json_output_requested, normalize_cli_argv
17
+ from pz_core.runtime.errors import PzError, as_pz_error
18
+ from pz_core.cli_options import add_cli_option, resolve_program_name
19
+
20
+
21
+ @dataclass(frozen=True, slots=True)
22
+ class DbCliReport:
23
+ status: str
24
+ code: str
25
+ stage: str
26
+ owner: str
27
+ action: str
28
+ workspace_dir: str
29
+ manifest_path: str
30
+ orm_config_path: str
31
+ lock_path: str
32
+ database_enabled: bool
33
+ database_driver: str
34
+ migration_executor: str | None
35
+ migration_owners: tuple[DbOwner, ...]
36
+ migration_sources: tuple[MigrationSource, ...]
37
+ history_entries: dict[str, tuple[str, ...]]
38
+ prepared_workspace: bool = False
39
+ executed: bool = False
40
+ execution_result: dict[str, Any] | None = None
41
+ message: str | None = None
42
+
43
+ def to_dict(self) -> dict[str, Any]:
44
+ payload = asdict(self)
45
+ payload["migration_owners"] = [asdict(item) for item in self.migration_owners]
46
+ payload["migration_sources"] = [asdict(item) for item in self.migration_sources]
47
+ payload["history_entries"] = {
48
+ key: list(value) for key, value in self.history_entries.items()
49
+ }
50
+ return payload
51
+
52
+
53
+ def _require_database(plan: RuntimePlan, *, action: str) -> None:
54
+ if not plan.infra.database.enabled:
55
+ raise PzError(
56
+ code="PZ_DB_DISABLED",
57
+ message="Database capability is disabled for the current project.",
58
+ stage="db",
59
+ owner="infra.database",
60
+ action=action,
61
+ )
62
+ if not str(plan.infra.database.get("driver", "") or "").strip():
63
+ raise PzError(
64
+ code="PZ_DB_DRIVER_MISSING",
65
+ message="Database capability is enabled but driver is empty.",
66
+ stage="db",
67
+ owner="infra.database",
68
+ action=action,
69
+ )
70
+
71
+
72
+ def _migration_port(plan: RuntimePlan) -> DatabaseMigrationPort:
73
+ bindings = compile_runtime_bindings(plan)
74
+ bindings.providers.activate_declared(plan=plan, bindings=bindings)
75
+ provider = bindings.providers.require("database.migrations")
76
+ if not isinstance(provider, DatabaseMigrationPort):
77
+ raise PzError(
78
+ code="PZ_DB_PROVIDER_INVALID",
79
+ message=(
80
+ "Registered database.migrations provider does not implement "
81
+ "DatabaseMigrationPort."
82
+ ),
83
+ stage="db",
84
+ owner="runtime.cli.db",
85
+ action="bind_migration_provider",
86
+ )
87
+ return provider
88
+
89
+
90
+ def _compile_report(
91
+ snapshot: DatabaseMigrationSnapshot,
92
+ *,
93
+ action: str,
94
+ message: str | None = None,
95
+ ) -> DbCliReport:
96
+ return DbCliReport(
97
+ status="ok",
98
+ code="PZ_DB_OK",
99
+ stage="db",
100
+ owner="runtime.cli.db",
101
+ action=action,
102
+ workspace_dir=str(snapshot.workspace_dir),
103
+ manifest_path=str(snapshot.manifest_path),
104
+ orm_config_path=str(snapshot.orm_config_path),
105
+ lock_path=str(snapshot.lock_path),
106
+ database_enabled=snapshot.database_enabled,
107
+ database_driver=snapshot.database_driver,
108
+ migration_executor=snapshot.migration_executor,
109
+ migration_owners=snapshot.migration_owners,
110
+ migration_sources=snapshot.migration_sources,
111
+ history_entries=snapshot.history_entries,
112
+ message=message,
113
+ )
114
+
115
+
116
+ def _print_report(report: DbCliReport, *, json_output: bool) -> int:
117
+ payload = report.to_dict()
118
+ if json_output:
119
+ print(json.dumps(payload, ensure_ascii=True, sort_keys=True))
120
+ else:
121
+ print(
122
+ f"status={payload['status']} code={payload['code']} action={payload['action']} "
123
+ f"workspace_dir={payload['workspace_dir']}"
124
+ )
125
+ for item in payload["migration_owners"]:
126
+ print(f"owner {item['owner']} -> {item['module_path']}")
127
+ return 0
128
+
129
+
130
+ def _print_error(exc: Exception, *, json_output: bool) -> int:
131
+ if isinstance(exc, PzError):
132
+ payload = exc.to_dict()
133
+ else:
134
+ payload = as_pz_error(
135
+ exc,
136
+ code="PZ_DB_FAILED",
137
+ stage="db",
138
+ owner="runtime.cli.db",
139
+ action="dispatch",
140
+ ).to_dict()
141
+ payload["status"] = "error"
142
+ if json_output:
143
+ print(json.dumps(payload, ensure_ascii=True, sort_keys=True))
144
+ else:
145
+ print(f"[{payload['code']}] {payload['message']}", file=sys.stderr)
146
+ return 1
147
+
148
+
149
+ def _makemigrations(plan: RuntimePlan, *, prepare_workspace: bool) -> DbCliReport:
150
+ _require_database(plan, action="makemigrations")
151
+ provider = _migration_port(plan)
152
+ if prepare_workspace:
153
+ snapshot = provider.prepare(action="makemigrations")
154
+ report = _compile_report(
155
+ snapshot,
156
+ action="makemigrations",
157
+ message=(
158
+ "Migration planning uses the declared database.migrations provider and "
159
+ "writes workspace/config snapshots under ProjectContext cache_dir."
160
+ ),
161
+ )
162
+ return replace(report, prepared_workspace=True)
163
+ snapshot, execution_result = provider.execute(action="makemigrations")
164
+ report = _compile_report(
165
+ snapshot,
166
+ action="makemigrations",
167
+ message=(
168
+ "Migration execution uses the declared database.migrations provider and its "
169
+ "explicit migration executor contract."
170
+ ),
171
+ )
172
+ return replace(
173
+ report,
174
+ prepared_workspace=True,
175
+ executed=True,
176
+ execution_result=execution_result,
177
+ )
178
+
179
+
180
+ def _history(plan: RuntimePlan, *, action: str = "history") -> DbCliReport:
181
+ _require_database(plan, action=action)
182
+ snapshot = _migration_port(plan).prepare(action=action)
183
+ report = _compile_report(snapshot, action=action)
184
+ return replace(report, prepared_workspace=True, executed=False)
185
+
186
+
187
+ def _migrate(plan: RuntimePlan, *, prepare_workspace: bool) -> DbCliReport:
188
+ _require_database(plan, action="migrate")
189
+ provider = _migration_port(plan)
190
+ if prepare_workspace:
191
+ snapshot = provider.prepare(action="migrate")
192
+ report = _compile_report(
193
+ snapshot,
194
+ action="migrate",
195
+ message=(
196
+ "Migration preparation uses the declared database.migrations provider and "
197
+ "writes workspace/config snapshots without executing migrations."
198
+ ),
199
+ )
200
+ return replace(report, prepared_workspace=True, executed=False)
201
+ snapshot, execution_result = provider.execute(action="migrate")
202
+ report = _compile_report(
203
+ snapshot,
204
+ action="migrate",
205
+ message=(
206
+ "Migration execution uses the declared database.migrations provider and its "
207
+ "explicit migration executor contract."
208
+ ),
209
+ )
210
+ return replace(
211
+ report,
212
+ prepared_workspace=True,
213
+ executed=True,
214
+ execution_result=execution_result,
215
+ )
216
+
217
+
218
+ def main(argv: list[str] | None = None) -> int:
219
+ raw_argv = list(argv) if argv is not None else None
220
+ json_output = json_output_requested(raw_argv)
221
+ try:
222
+ argv = normalize_cli_argv(
223
+ raw_argv,
224
+ code="PZ_DB_ARGV_INVALID",
225
+ stage="db",
226
+ owner="runtime.cli.db",
227
+ action="dispatch",
228
+ )
229
+ except Exception as exc:
230
+ return _print_error(exc, json_output=json_output)
231
+ parser = PzArgumentParser(
232
+ prog=f"{resolve_program_name()} db",
233
+ description="Database CLI built on RuntimePlan and provider-backed migration orchestration.",
234
+ error_code="PZ_DB_ARGUMENTS_INVALID",
235
+ error_stage="cli",
236
+ error_owner="runtime.cli.db",
237
+ error_action="parse_args",
238
+ )
239
+ add_cli_option(parser, "--project-dir", dest="project_dir")
240
+ add_cli_option(parser, "--json", action="store_true", dest="json_output")
241
+ subparsers = parser.add_subparsers(dest="command", required=True)
242
+
243
+ showmigrations_parser = subparsers.add_parser(
244
+ "showmigrations",
245
+ prog=f"{resolve_program_name()} db showmigrations",
246
+ )
247
+ _add_db_common_arguments(showmigrations_parser)
248
+ makemigrations_parser = subparsers.add_parser(
249
+ "makemigrations",
250
+ prog=f"{resolve_program_name()} db makemigrations",
251
+ )
252
+ _add_db_common_arguments(makemigrations_parser)
253
+ add_cli_option(
254
+ makemigrations_parser,
255
+ "--prepare-workspace",
256
+ action="store_true",
257
+ dest="prepare_workspace",
258
+ )
259
+ migrate_parser = subparsers.add_parser("migrate", prog=f"{resolve_program_name()} db migrate")
260
+ _add_db_common_arguments(migrate_parser)
261
+ add_cli_option(
262
+ migrate_parser,
263
+ "--prepare-workspace",
264
+ action="store_true",
265
+ dest="prepare_workspace",
266
+ )
267
+
268
+ ns = None
269
+ try:
270
+ ns = parser.parse_args(argv)
271
+ plan = compile_runtime_plan(project_dir=ns.project_dir)
272
+ if ns.command == "showmigrations":
273
+ return _print_report(_history(plan, action="showmigrations"), json_output=ns.json_output)
274
+ if ns.command == "makemigrations":
275
+ return _print_report(
276
+ _makemigrations(plan, prepare_workspace=ns.prepare_workspace),
277
+ json_output=ns.json_output,
278
+ )
279
+ if ns.command == "migrate":
280
+ return _print_report(
281
+ _migrate(plan, prepare_workspace=ns.prepare_workspace),
282
+ json_output=ns.json_output,
283
+ )
284
+ raise PzError(
285
+ code="PZ_DB_UNKNOWN_COMMAND",
286
+ message=f"Unknown db command: {ns.command}",
287
+ stage="db",
288
+ owner="runtime.cli.db",
289
+ action="dispatch",
290
+ )
291
+ except Exception as exc:
292
+ return _print_error(exc, json_output=ns.json_output if ns is not None else json_output)
293
+
294
+
295
+ def _add_db_common_arguments(parser: argparse.ArgumentParser) -> None:
296
+ add_cli_option(parser, "--project-dir", dest="project_dir", default=argparse.SUPPRESS)
297
+ add_cli_option(parser, "--json", action="store_true", dest="json_output", default=argparse.SUPPRESS)
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import sys
5
+ from collections.abc import Sequence
6
+
7
+ from pz_core.cli_options import option_shortcuts_help, resolve_program_name
8
+
9
+ from . import app_commands as app_cli
10
+ from . import check as check_cli
11
+ from . import db as db_cli
12
+ from . import resources as resources_cli
13
+
14
+ def _usage() -> str:
15
+ program_name = resolve_program_name()
16
+ return f"""{program_name} CLI
17
+
18
+ Usage:
19
+ {program_name} --help
20
+ {program_name} list [--json] [--project-dir PATH]
21
+ {program_name} check [--json] [--project-dir PATH]
22
+ {program_name} db <makemigrations|migrate|showmigrations> [--json] [--project-dir PATH]
23
+ {program_name} resources images [--force] [--json] [--project-dir PATH]
24
+ {program_name} <app_id> <tool> [--project-dir PATH]
25
+
26
+ {option_shortcuts_help()}
27
+ """
28
+
29
+
30
+ def _is_help(value: str | None) -> bool:
31
+ return isinstance(value, str) and value.strip().lower() in {"-h", "--help", "help"}
32
+
33
+
34
+ def _json_mode(args: Sequence[object]) -> bool:
35
+ return any(isinstance(item, str) and item in {"--json", "-j"} for item in args)
36
+
37
+
38
+ def _json_error(message: str, *, code: str) -> str:
39
+ return json.dumps(
40
+ {
41
+ "status": "error",
42
+ "code": code,
43
+ "stage": "cli",
44
+ "owner": "runtime.cli",
45
+ "action": "dispatch",
46
+ "summary": message,
47
+ "message": message,
48
+ },
49
+ ensure_ascii=True,
50
+ sort_keys=True,
51
+ )
52
+
53
+
54
+ def main(argv: Sequence[str] | None = None) -> int:
55
+ args = list(argv or sys.argv[1:])
56
+ json_mode = _json_mode(args)
57
+ if not args or _is_help(args[0]):
58
+ sys.stdout.write(_usage())
59
+ return 0
60
+
61
+ raw_command = args.pop(0)
62
+ if not isinstance(raw_command, str) or not raw_command.strip():
63
+ message = "CLI command must be a non-empty string."
64
+ if json_mode:
65
+ sys.stdout.write(_json_error(message, code="PZ_CLI_COMMAND_INVALID") + "\n")
66
+ else:
67
+ sys.stderr.write(message + "\n\n" + _usage())
68
+ return 2
69
+ command = raw_command.strip().lower()
70
+ if command == "list":
71
+ return app_cli.list_main(args)
72
+ if command == "check":
73
+ return check_cli.main(args)
74
+ if command == "db":
75
+ return db_cli.main(args)
76
+ if command == "resources":
77
+ return resources_cli.main(args)
78
+ if args:
79
+ return app_cli.dispatch_app_cli(command, args)
80
+
81
+ message = f"Unknown command: {command}"
82
+ if json_mode:
83
+ sys.stdout.write(_json_error(message, code="PZ_CLI_UNKNOWN_COMMAND") + "\n")
84
+ else:
85
+ sys.stderr.write(message + "\n\n" + _usage())
86
+ return 2
87
+
88
+
89
+ __all__ = ["main"]
@@ -0,0 +1,280 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from collections.abc import Mapping
5
+ from dataclasses import asdict, dataclass
6
+ import json
7
+ from pathlib import Path
8
+ import sys
9
+ from typing import Any
10
+
11
+ from pz_core.cli_options import add_cli_option, resolve_program_name
12
+ from pz_core.runtime import compile_runtime_bindings, compile_runtime_plan
13
+ from pz_core.runtime.cli._args import PzArgumentParser, json_output_requested, normalize_cli_argv
14
+ from pz_core.runtime.errors import PzError, as_pz_error
15
+ from pz_core.runtime.resource_assets import (
16
+ RESOURCE_ASSET_BUNDLES_MANIFEST_KEY,
17
+ AssetBuildPolicy,
18
+ build_static_asset_manifest,
19
+ validate_static_asset_manifest,
20
+ )
21
+
22
+
23
+ @dataclass(frozen=True, slots=True)
24
+ class ResourceCliReport:
25
+ status: str
26
+ code: str
27
+ stage: str
28
+ owner: str
29
+ action: str
30
+ manifest_path: str
31
+ output_dir: str
32
+ forced: bool
33
+ message: str
34
+
35
+ def to_dict(self) -> dict[str, Any]:
36
+ return asdict(self)
37
+
38
+
39
+ @dataclass(frozen=True, slots=True)
40
+ class ResourceAssetCliReport:
41
+ status: str
42
+ code: str
43
+ stage: str
44
+ owner: str
45
+ action: str
46
+ environment: str
47
+ manifest_path: str
48
+ output_dir: str
49
+ assets_built: int
50
+ bundles_built: int
51
+ violations: tuple[str, ...]
52
+ message: str
53
+
54
+ def to_dict(self) -> dict[str, Any]:
55
+ return asdict(self)
56
+
57
+
58
+ def _print_report(report: ResourceCliReport | ResourceAssetCliReport, *, json_output: bool) -> int:
59
+ payload = report.to_dict()
60
+ if json_output:
61
+ print(json.dumps(payload, ensure_ascii=True, sort_keys=True))
62
+ else:
63
+ parts = [
64
+ f"status={payload['status']}",
65
+ f"code={payload['code']}",
66
+ f"action={payload['action']}",
67
+ ]
68
+ if "forced" in payload:
69
+ parts.append(f"forced={str(payload['forced']).lower()}")
70
+ if "environment" in payload:
71
+ parts.append(f"environment={payload['environment']}")
72
+ parts.append(f"output_dir={payload['output_dir']}")
73
+ print(" ".join(parts))
74
+ for violation in payload.get("violations") or ():
75
+ print(f"- {violation}", file=sys.stderr)
76
+ return 0 if payload["status"] == "ok" else 1
77
+
78
+
79
+ def _print_error(exc: Exception, *, json_output: bool) -> int:
80
+ if isinstance(exc, PzError):
81
+ payload = exc.to_dict()
82
+ else:
83
+ payload = as_pz_error(
84
+ exc,
85
+ code="PZ_RESOURCES_FAILED",
86
+ stage="resources",
87
+ owner="runtime.cli.resources",
88
+ action="dispatch",
89
+ ).to_dict()
90
+ payload["status"] = "error"
91
+ if json_output:
92
+ print(json.dumps(payload, ensure_ascii=True, sort_keys=True))
93
+ else:
94
+ print(f"[{payload['code']}] {payload['message']}", file=sys.stderr)
95
+ return 1
96
+
97
+
98
+ def _build_resources(*, project_dir: str | None, force: bool) -> ResourceCliReport:
99
+ plan = compile_runtime_plan(project_dir=project_dir)
100
+ effective_force = bool(force) or _resource_images_force_enabled(plan)
101
+ bindings = compile_runtime_bindings(plan)
102
+ bindings.providers.activate_declared(plan=plan, bindings=bindings)
103
+ result = bindings.resources.build(force=effective_force)
104
+ return ResourceCliReport(
105
+ status="ok",
106
+ code="PZ_RESOURCES_IMAGES_OK",
107
+ stage="resources",
108
+ owner="runtime.cli.resources",
109
+ action="images",
110
+ manifest_path=str(result.manifest_path),
111
+ output_dir=str(result.output_dir),
112
+ forced=effective_force,
113
+ message=(
114
+ "Resource image derivatives were built through the formal resources provider. "
115
+ "Existing derivative files are preserved unless the CLI flag or settings force is true."
116
+ ),
117
+ )
118
+
119
+
120
+ def _build_assets(*, project_dir: str | None, environment: str | None, validate_only: bool) -> ResourceAssetCliReport:
121
+ plan = compile_runtime_plan(project_dir=project_dir)
122
+ output_root = Path(plan.resource_manifest.output_root)
123
+ static_root = output_root / "static"
124
+ manifest_path = output_root / "asset-manifest.json"
125
+ env_name = str(environment or _runtime_plan_environment(plan) or "develop").strip() or "develop"
126
+ policy = AssetBuildPolicy(environment=env_name)
127
+ bundles_built = 0
128
+
129
+ if validate_only:
130
+ result = validate_static_asset_manifest(static_root=static_root, manifest_path=manifest_path, policy=policy)
131
+ else:
132
+ bindings = compile_runtime_bindings(plan)
133
+ bindings.providers.activate_declared(plan=plan, bindings=bindings)
134
+ bindings.resources.build(force=True)
135
+ result = build_static_asset_manifest(
136
+ static_root=static_root,
137
+ manifest_path=manifest_path,
138
+ policy=policy,
139
+ page_bundles=_collect_page_asset_bundles(plan),
140
+ )
141
+ bundles_built = result.bundles_built
142
+ if result.status == "ok":
143
+ result = validate_static_asset_manifest(static_root=static_root, manifest_path=manifest_path, policy=policy)
144
+ return ResourceAssetCliReport(
145
+ status=result.status,
146
+ code="PZ_RESOURCES_ASSETS_OK" if result.status == "ok" else "PZ_RESOURCES_ASSETS_INVALID",
147
+ stage="resources",
148
+ owner="runtime.cli.resources",
149
+ action="assets",
150
+ environment=env_name,
151
+ manifest_path=str(result.manifest_path),
152
+ output_dir=str(result.static_root.parent),
153
+ assets_built=result.assets_built,
154
+ bundles_built=bundles_built,
155
+ violations=result.violations,
156
+ message=(
157
+ "Resource CSS/JS assets were validated."
158
+ if validate_only
159
+ else "Resource CSS/JS assets were rebuilt through the formal resources provider and validated."
160
+ ),
161
+ )
162
+
163
+
164
+ def _runtime_plan_environment(plan: object) -> str:
165
+ settings = getattr(plan, "settings", None)
166
+ return str(getattr(settings, "pz_env", "") or "")
167
+
168
+
169
+ def _collect_page_asset_bundles(plan: object) -> tuple[dict[str, Any], ...]:
170
+ manifests = getattr(plan, "runtime_manifests", None)
171
+ if not isinstance(manifests, Mapping):
172
+ return ()
173
+ raw_bundles = manifests.get(RESOURCE_ASSET_BUNDLES_MANIFEST_KEY, ())
174
+ if not isinstance(raw_bundles, (list, tuple)):
175
+ return ()
176
+ return tuple(dict(item) for item in raw_bundles if isinstance(item, Mapping))
177
+
178
+
179
+ def _resource_images_force_enabled(plan: object) -> bool:
180
+ settings_snapshot = getattr(plan, "settings", None)
181
+ app_settings = getattr(settings_snapshot, "app_settings", None)
182
+ if not callable(app_settings):
183
+ return False
184
+ try:
185
+ app_payload = app_settings("pz_foundation")
186
+ except Exception:
187
+ return False
188
+ if not isinstance(app_payload, dict):
189
+ try:
190
+ app_payload = dict(app_payload)
191
+ except Exception:
192
+ return False
193
+ resources = app_payload.get("resources")
194
+ if not isinstance(resources, dict):
195
+ return False
196
+ images = resources.get("images")
197
+ if not isinstance(images, dict):
198
+ return False
199
+ return _coerce_bool(images.get("force", False))
200
+
201
+
202
+ def _coerce_bool(value: object) -> bool:
203
+ if isinstance(value, bool):
204
+ return value
205
+ if isinstance(value, str):
206
+ return value.strip().lower() in {"1", "true", "yes", "on"}
207
+ if isinstance(value, (int, float)):
208
+ return bool(value)
209
+ return False
210
+
211
+
212
+ def main(argv: list[str] | None = None) -> int:
213
+ raw_argv = list(argv) if argv is not None else None
214
+ json_output = json_output_requested(raw_argv)
215
+ try:
216
+ argv = normalize_cli_argv(
217
+ raw_argv,
218
+ code="PZ_RESOURCES_ARGV_INVALID",
219
+ stage="resources",
220
+ owner="runtime.cli.resources",
221
+ action="dispatch",
222
+ )
223
+ except Exception as exc:
224
+ return _print_error(exc, json_output=json_output)
225
+
226
+ parser = PzArgumentParser(
227
+ prog=f"{resolve_program_name()} resources",
228
+ description="Resource CLI built on RuntimePlan and the formal resources provider.",
229
+ error_code="PZ_RESOURCES_ARGUMENTS_INVALID",
230
+ error_stage="cli",
231
+ error_owner="runtime.cli.resources",
232
+ error_action="parse_args",
233
+ )
234
+ add_cli_option(parser, "--project-dir", dest="project_dir")
235
+ add_cli_option(parser, "--json", action="store_true", dest="json_output")
236
+ subparsers = parser.add_subparsers(dest="command", required=True)
237
+
238
+ images_parser = subparsers.add_parser("images", prog=f"{resolve_program_name()} resources images")
239
+ _add_resource_common_arguments(images_parser)
240
+ add_cli_option(images_parser, "--force", action="store_true", dest="force")
241
+
242
+ assets_parser = subparsers.add_parser("assets", prog=f"{resolve_program_name()} resources assets")
243
+ _add_resource_common_arguments(assets_parser)
244
+ assets_parser.add_argument("--environment", dest="environment", default=None)
245
+ assets_parser.add_argument("--check", action="store_true", dest="validate_only")
246
+
247
+ ns = None
248
+ try:
249
+ ns = parser.parse_args(argv)
250
+ if ns.command == "images":
251
+ return _print_report(
252
+ _build_resources(project_dir=ns.project_dir, force=bool(getattr(ns, "force", False))),
253
+ json_output=ns.json_output,
254
+ )
255
+ if ns.command == "assets":
256
+ return _print_report(
257
+ _build_assets(
258
+ project_dir=getattr(ns, "project_dir", None),
259
+ environment=getattr(ns, "environment", None),
260
+ validate_only=bool(getattr(ns, "validate_only", False)),
261
+ ),
262
+ json_output=ns.json_output,
263
+ )
264
+ raise PzError(
265
+ code="PZ_RESOURCES_UNKNOWN_COMMAND",
266
+ message=f"Unknown resources command: {ns.command}",
267
+ stage="resources",
268
+ owner="runtime.cli.resources",
269
+ action="dispatch",
270
+ )
271
+ except Exception as exc:
272
+ return _print_error(exc, json_output=ns.json_output if ns is not None else json_output)
273
+
274
+
275
+ def _add_resource_common_arguments(parser: argparse.ArgumentParser) -> None:
276
+ add_cli_option(parser, "--project-dir", dest="project_dir", default=argparse.SUPPRESS)
277
+ add_cli_option(parser, "--json", action="store_true", dest="json_output", default=argparse.SUPPRESS)
278
+
279
+
280
+ __all__ = ["main"]
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ from pz_core.assembly.app_discovery import (
4
+ discover_declared_app_references,
5
+ discover_leaf_app_packages,
6
+ import_app_settings_module,
7
+ read_static_app_declaration,
8
+ resolve_declared_app_import_roots,
9
+ resolve_declared_app_id,
10
+ resolve_import_roots_for_app_references,
11
+ resolve_package_root,
12
+ )
13
+
14
+ __all__ = [
15
+ "discover_declared_app_references",
16
+ "discover_leaf_app_packages",
17
+ "import_app_settings_module",
18
+ "read_static_app_declaration",
19
+ "resolve_declared_app_import_roots",
20
+ "resolve_declared_app_id",
21
+ "resolve_import_roots_for_app_references",
22
+ "resolve_package_root",
23
+ ]