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,139 @@
1
+ """Formal contrib-level public surface for unified settings access."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+ from dataclasses import dataclass
7
+
8
+ import pz_core.runtime.settings as _runtime
9
+
10
+ from .api import runtime_overrides
11
+ from .integration_payload import IntegrationPayloadSettings, empty_integration_payload
12
+ from .project_helpers import get_project_dir, get_project_upload_path
13
+ from .typed_settings import SettingsCenterProxy, resolve_app_settings_payload, resolve_settings, settings
14
+ from .routing_helpers import get_routing_default_language, get_routing_language_aliases, get_routing_supported_languages
15
+
16
+
17
+ ResolvedSettings = _runtime.ResolvedSettings
18
+
19
+ active_settings_project = _runtime.active_settings_project
20
+ bind_settings_snapshot = _runtime.bind_settings_snapshot
21
+ bound_settings_snapshot = _runtime.bound_settings_snapshot
22
+ build_local_default_settings = _runtime.build_local_default_settings
23
+ build_local_default_settings_chain = _runtime.build_local_default_settings_chain
24
+ current_pz_env = _runtime.current_pz_env
25
+ current_settings_project_dir = _runtime.current_settings_project_dir
26
+ ensure_full_settings = _runtime.ensure_full_settings
27
+ get_route_token_catalog = _runtime.get_route_token_catalog
28
+ get_applied_runtime_overrides = runtime_overrides.get_applied_runtime_overrides
29
+ load_local_default_settings = _runtime.load_local_default_settings
30
+ load_local_default_settings_chain = _runtime.load_local_default_settings_chain
31
+ register_route_token_catalog_provider = _runtime.register_route_token_catalog_provider
32
+ reset_route_token_catalog_provider = _runtime.reset_route_token_catalog_provider
33
+ reset_settings_binding = _runtime.reset_settings_binding
34
+
35
+
36
+ @dataclass(frozen=True, slots=True)
37
+ class RuntimeNamespaceSettingsSnapshot:
38
+ namespace: str
39
+ values: dict[str, Any]
40
+ signature: tuple[Any, ...]
41
+
42
+ def get(self, key: str, default: Any = None) -> Any:
43
+ return self.values.get(str(key), default)
44
+
45
+
46
+ _RUNTIME_NAMESPACE_SETTINGS_CACHE: dict[
47
+ tuple[str, str | None, int, tuple[Any, ...]],
48
+ RuntimeNamespaceSettingsSnapshot,
49
+ ] = {}
50
+
51
+
52
+ def get_settings_snapshot(*, project_dir: str | None = None):
53
+ return resolve_settings(project_dir=project_dir).snapshot
54
+
55
+
56
+ def get_settings_snapshot_section(
57
+ name: str,
58
+ *,
59
+ project_dir: str | None = None,
60
+ default: Any = None,
61
+ ):
62
+ snapshot = get_settings_snapshot(project_dir=project_dir)
63
+ getter = getattr(snapshot, "get", None)
64
+ if callable(getter):
65
+ value = getter(str(name).strip(), default=default)
66
+ else:
67
+ value = getattr(snapshot, str(name).strip(), default)
68
+ return default if value is None else value
69
+
70
+
71
+ def _signature_value(value: Any) -> Any:
72
+ if isinstance(value, dict):
73
+ return tuple((str(key), _signature_value(item)) for key, item in sorted(value.items(), key=lambda item: str(item[0])))
74
+ if isinstance(value, (list, tuple)):
75
+ return tuple(_signature_value(item) for item in value)
76
+ if isinstance(value, set):
77
+ return tuple(sorted(_signature_value(item) for item in value))
78
+ return value
79
+
80
+
81
+ def get_runtime_namespace_settings_snapshot(
82
+ namespace: str,
83
+ *,
84
+ project_dir: str | None = None,
85
+ ) -> RuntimeNamespaceSettingsSnapshot:
86
+ app_id = str(namespace or "").strip()
87
+ if not app_id:
88
+ raise ValueError("namespace must be a non-empty app_id string")
89
+ resolved = resolve_settings(project_dir=project_dir)
90
+ resolved_project_dir = getattr(resolved, "project_dir", project_dir)
91
+ runtime_signature = runtime_overrides.get_runtime_overrides_signature(project_dir=project_dir)
92
+ cache_key = (app_id, str(resolved_project_dir) if resolved_project_dir is not None else None, id(getattr(resolved, "snapshot", None)), runtime_signature)
93
+ cached = _RUNTIME_NAMESPACE_SETTINGS_CACHE.get(cache_key)
94
+ if cached is not None:
95
+ return cached
96
+ values = dict(resolve_app_settings_payload(resolved, app_id) or {})
97
+ signature = (
98
+ app_id,
99
+ id(getattr(resolved, "snapshot", None)),
100
+ runtime_signature,
101
+ _signature_value(values),
102
+ )
103
+ snapshot = RuntimeNamespaceSettingsSnapshot(namespace=app_id, values=values, signature=signature)
104
+ _RUNTIME_NAMESPACE_SETTINGS_CACHE[cache_key] = snapshot
105
+ return snapshot
106
+
107
+
108
+ __all__ = [
109
+ "ResolvedSettings",
110
+ "RuntimeNamespaceSettingsSnapshot",
111
+ "SettingsCenterProxy",
112
+ "IntegrationPayloadSettings",
113
+ "active_settings_project",
114
+ "bind_settings_snapshot",
115
+ "bound_settings_snapshot",
116
+ "build_local_default_settings",
117
+ "build_local_default_settings_chain",
118
+ "current_pz_env",
119
+ "current_settings_project_dir",
120
+ "ensure_full_settings",
121
+ "empty_integration_payload",
122
+ "get_applied_runtime_overrides",
123
+ "get_route_token_catalog",
124
+ "get_project_dir",
125
+ "get_project_upload_path",
126
+ "get_routing_default_language",
127
+ "get_routing_language_aliases",
128
+ "get_routing_supported_languages",
129
+ "get_runtime_namespace_settings_snapshot",
130
+ "get_settings_snapshot",
131
+ "get_settings_snapshot_section",
132
+ "load_local_default_settings",
133
+ "load_local_default_settings_chain",
134
+ "register_route_token_catalog_provider",
135
+ "reset_route_token_catalog_provider",
136
+ "reset_settings_binding",
137
+ "resolve_settings",
138
+ "settings",
139
+ ]
@@ -0,0 +1,73 @@
1
+ """Routing-level helper accessors built on the formal ``routing`` snapshot section."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib import import_module
6
+ from typing import Any
7
+
8
+
9
+ def _settings_snapshot(project_dir: str | None = None):
10
+ getter = import_module("pz_settings_center.public").get_settings_snapshot
11
+ return getter(project_dir=project_dir)
12
+
13
+
14
+ def _routing_value(name: str, default: Any = None, *, project_dir: str | None = None) -> Any:
15
+ snapshot = _settings_snapshot(project_dir=project_dir)
16
+ getter = getattr(snapshot, "get", None)
17
+ if not callable(getter):
18
+ return default
19
+ key = str(name or "").strip()
20
+ if not key:
21
+ return default
22
+ value = getter("routing", key, default=None)
23
+ return default if value is None else value
24
+
25
+
26
+ def get_routing_default_language(default: str = "en", *, project_dir: str | None = None) -> str:
27
+ try:
28
+ value = str(_routing_value("default_language", default, project_dir=project_dir) or default).strip()
29
+ except Exception:
30
+ value = default
31
+ return value or default
32
+
33
+
34
+ def get_routing_supported_languages(
35
+ default: tuple[str, ...] = ("en",),
36
+ *,
37
+ project_dir: str | None = None,
38
+ ) -> tuple[str, ...]:
39
+ try:
40
+ values = _routing_value("all_supported_languages", (), project_dir=project_dir) or ()
41
+ except Exception:
42
+ values = ()
43
+ if not isinstance(values, (list, tuple, set)):
44
+ return tuple(default)
45
+ languages = tuple(str(item).strip() for item in values if str(item).strip())
46
+ return languages or tuple(default)
47
+
48
+
49
+ def get_routing_language_aliases(
50
+ default: dict[str, str] | None = None,
51
+ *,
52
+ project_dir: str | None = None,
53
+ ) -> dict[str, str]:
54
+ try:
55
+ values = _routing_value("language_aliases", {}, project_dir=project_dir) or {}
56
+ except Exception:
57
+ values = {}
58
+ if not isinstance(values, dict):
59
+ return dict(default or {})
60
+ aliases: dict[str, str] = {}
61
+ for raw_alias, raw_target in values.items():
62
+ alias = str(raw_alias or "").strip().strip("/")
63
+ target = str(raw_target or "").strip().strip("/")
64
+ if alias and target:
65
+ aliases[alias] = target
66
+ return aliases or dict(default or {})
67
+
68
+
69
+ __all__ = [
70
+ "get_routing_default_language",
71
+ "get_routing_language_aliases",
72
+ "get_routing_supported_languages",
73
+ ]
@@ -0,0 +1,61 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from pz_core.core.extensions import SettingsPatch, SettingsProviderContext
6
+
7
+ from .api import runtime_overrides
8
+
9
+
10
+ def build_runtime_override_settings_provider(
11
+ context: SettingsProviderContext,
12
+ ) -> tuple[SettingsPatch, ...]:
13
+ project_dir = getattr(getattr(context, "project", None), "project_dir", None)
14
+ snapshot = getattr(context, "snapshot", None)
15
+ allowed_namespaces = {
16
+ str(app_id).strip()
17
+ for app_id in dict(getattr(snapshot, "apps", {}) or {}).keys()
18
+ if str(app_id).strip()
19
+ }
20
+ schema_by_namespace = runtime_overrides.get_runtime_overrides_schema()
21
+ patches: list[SettingsPatch] = []
22
+ for namespace, raw_values in runtime_overrides.get_applied_runtime_overrides(project_dir).items():
23
+ source = str(namespace or "").strip()
24
+ if source not in allowed_namespaces:
25
+ continue
26
+ schema = dict(schema_by_namespace.get(source, {}) or {})
27
+ if not schema:
28
+ continue
29
+ payload: dict[str, Any] = {}
30
+ for key, value in dict(raw_values or {}).items():
31
+ field_name = str(key or "").strip()
32
+ if field_name in schema:
33
+ payload[field_name] = value
34
+ if payload:
35
+ patches.append(
36
+ SettingsPatch(
37
+ app_id=source,
38
+ payload=payload,
39
+ source="pz_settings_center.runtime_overrides",
40
+ priority=10000,
41
+ )
42
+ )
43
+ return tuple(patches)
44
+
45
+
46
+ class RuntimeOverrideSettingsProvider:
47
+ def provide(
48
+ self,
49
+ context: SettingsProviderContext,
50
+ ) -> tuple[SettingsPatch, ...]:
51
+ return build_runtime_override_settings_provider(context)
52
+
53
+
54
+ SETTINGS_PROVIDER = RuntimeOverrideSettingsProvider()
55
+
56
+
57
+ __all__ = [
58
+ "RuntimeOverrideSettingsProvider",
59
+ "SETTINGS_PROVIDER",
60
+ "build_runtime_override_settings_provider",
61
+ ]
@@ -0,0 +1,324 @@
1
+ """Application-facing typed settings loading for settings_center."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from functools import lru_cache
6
+ from importlib import import_module
7
+ from types import ModuleType
8
+ from typing import Any, Mapping
9
+
10
+ ResolvedSettings = Any
11
+ _APP_SETTINGS_TYPE_CACHE: dict[tuple[int, str | None, str], type | None] = {}
12
+
13
+
14
+ def resolve_settings(project_dir: str | None = None) -> ResolvedSettings:
15
+ runtime_module = import_module("pz_core.runtime")
16
+ return runtime_module.resolve_settings(project_dir=project_dir)
17
+
18
+
19
+ def _active_resolve_settings(project_dir: str | None = None):
20
+ """Resolve settings lazily through the public surface.
21
+
22
+ Importing settings_center must stay side-effect free. The first concrete
23
+ read from SettingsCenterProxy is the point where the active SettingsSnapshot
24
+ may be compiled or an already-bound runtime snapshot is reused.
25
+ """
26
+ resolver = import_module("pz_settings_center.public").resolve_settings
27
+ return resolver(project_dir=project_dir)
28
+
29
+
30
+ def _normalize_key_token(value: Any) -> str:
31
+ return str(value or "").strip().replace("-", "_").lower()
32
+
33
+
34
+ def _iter_validation_aliases(field_info: Any) -> tuple[str, ...]:
35
+ alias = getattr(field_info, "validation_alias", None)
36
+ if alias is None:
37
+ return ()
38
+ if isinstance(alias, str):
39
+ return (alias,)
40
+ choices = getattr(alias, "choices", None)
41
+ if choices is not None:
42
+ values: list[str] = []
43
+ for item in tuple(choices or ()):
44
+ if isinstance(item, str):
45
+ values.append(item)
46
+ continue
47
+ path = getattr(item, "path", None)
48
+ if isinstance(path, tuple) and len(path) == 1 and isinstance(path[0], str):
49
+ values.append(path[0])
50
+ return tuple(values)
51
+ path = getattr(alias, "path", None)
52
+ if isinstance(path, tuple) and len(path) == 1 and isinstance(path[0], str):
53
+ return (path[0],)
54
+ return ()
55
+
56
+
57
+ @lru_cache(maxsize=None)
58
+ def _field_name_lookup(settings_type: type) -> dict[str, str]:
59
+ model_fields = getattr(settings_type, "model_fields", None)
60
+ if not isinstance(model_fields, Mapping):
61
+ return {}
62
+ lookup: dict[str, str] = {}
63
+ for field_name, field_info in model_fields.items():
64
+ candidates = {
65
+ str(field_name).strip(),
66
+ str(getattr(field_info, "alias", "") or "").strip(),
67
+ *_iter_validation_aliases(field_info),
68
+ }
69
+ for candidate in candidates:
70
+ token = _normalize_key_token(candidate)
71
+ if token and token not in lookup:
72
+ lookup[token] = str(field_name)
73
+ return lookup
74
+
75
+
76
+ def _normalize_settings_payload_keys(payload: Mapping[str, Any] | None, settings_type: type) -> dict[str, Any]:
77
+ lookup = _field_name_lookup(settings_type)
78
+ if not lookup:
79
+ return dict(payload or {})
80
+ normalized: dict[str, Any] = {}
81
+ for raw_key, value in dict(payload or {}).items():
82
+ key = str(raw_key or "").strip()
83
+ if not key:
84
+ continue
85
+ normalized[lookup.get(_normalize_key_token(key), key)] = value
86
+ return normalized
87
+
88
+
89
+ def _is_missing_module_error(exc: ModuleNotFoundError, module_name: str) -> bool:
90
+ missing_name = str(getattr(exc, "name", "") or "")
91
+ return missing_name == module_name or module_name.startswith(missing_name + ".")
92
+
93
+
94
+ def _import_optional_module(module_name: str) -> ModuleType | None:
95
+ try:
96
+ return import_module(module_name)
97
+ except ModuleNotFoundError as exc:
98
+ if _is_missing_module_error(exc, module_name):
99
+ return None
100
+ raise
101
+
102
+
103
+ def _snapshot_installed_app_paths(resolved: Any) -> tuple[str, ...]:
104
+ snapshot = getattr(resolved, "snapshot", None)
105
+ values: list[str] = []
106
+ for attr_name in ("installed_apps", "declared_installed_apps"):
107
+ for item in tuple(getattr(snapshot, attr_name, ()) or ()):
108
+ text = str(item or "").strip()
109
+ if text and text not in values:
110
+ values.append(text)
111
+ return tuple(values)
112
+
113
+
114
+ def _declared_app_ids(resolved: Any) -> frozenset[str]:
115
+ snapshot = getattr(resolved, "snapshot", None)
116
+ apps = getattr(snapshot, "apps", None)
117
+ if isinstance(apps, Mapping):
118
+ return frozenset(str(app_id) for app_id in apps.keys())
119
+ return frozenset()
120
+
121
+
122
+ def _candidate_settings_module_names(resolved: Any, app_id: str) -> tuple[str, ...]:
123
+ normalized_app_id = str(app_id or "").strip().replace("-", "_")
124
+ names: list[str] = []
125
+ if normalized_app_id:
126
+ names.append(f"{normalized_app_id}.settings")
127
+ resolver = import_module("pz_core.assembly.app_discovery").resolve_declared_app_id
128
+ for module_path in _snapshot_installed_app_paths(resolved):
129
+ try:
130
+ declared_app_id = str(resolver(module_path) or "").strip()
131
+ except Exception:
132
+ declared_app_id = ""
133
+ if declared_app_id != str(app_id or "").strip():
134
+ continue
135
+ normalized_module = module_path.replace("-", "_")
136
+ candidate = f"{normalized_module}.settings"
137
+ if candidate not in names:
138
+ names.append(candidate)
139
+ return tuple(names)
140
+
141
+
142
+ def _project_import_context(resolved: Any):
143
+ snapshot = getattr(resolved, "snapshot", None)
144
+ project_dir = getattr(resolved, "project_dir", None) or getattr(snapshot, "project_dir", None)
145
+ import_roots = tuple(getattr(snapshot, "import_roots", ()) or ())
146
+ helper = import_module("pz_core.assembly.project").active_project_import_root
147
+ return helper(project_dir, extra_import_roots=import_roots)
148
+
149
+
150
+ def _app_settings_module_and_type(resolved: Any, app_id: str) -> tuple[ModuleType, type] | tuple[None, None]:
151
+ normalized_app_id = str(app_id or "").strip()
152
+ if not normalized_app_id:
153
+ return None, None
154
+ snapshot = getattr(resolved, "snapshot", None)
155
+ project_dir = str(getattr(resolved, "project_dir", None) or getattr(snapshot, "project_dir", None) or "")
156
+ cache_key = (id(snapshot), project_dir or None, normalized_app_id)
157
+ if cache_key in _APP_SETTINGS_TYPE_CACHE:
158
+ settings_type = _APP_SETTINGS_TYPE_CACHE[cache_key]
159
+ if settings_type is None:
160
+ return None, None
161
+ module_name = str(getattr(settings_type, "__module__", "") or "").strip()
162
+ if not module_name:
163
+ return None, None
164
+ return import_module(module_name), settings_type
165
+ with _project_import_context(resolved):
166
+ for module_name in _candidate_settings_module_names(resolved, normalized_app_id):
167
+ module = _import_optional_module(module_name)
168
+ if module is None:
169
+ continue
170
+ declared_app_id = str(getattr(module, "APP_ID", "") or "").strip()
171
+ if declared_app_id and declared_app_id != normalized_app_id:
172
+ continue
173
+ settings_type = getattr(module, "AppSettings", None)
174
+ if isinstance(settings_type, type):
175
+ _APP_SETTINGS_TYPE_CACHE[cache_key] = settings_type
176
+ return module, settings_type
177
+ _APP_SETTINGS_TYPE_CACHE[cache_key] = None
178
+ return None, None
179
+
180
+
181
+ def _normalize_with_app_schema(module: ModuleType, settings_type: type, values: dict[str, Any]) -> dict[str, Any]:
182
+ normalized = _normalize_settings_payload_keys(values, settings_type)
183
+ app_normalize = getattr(module, "_normalize_settings_payload", None)
184
+ if callable(app_normalize):
185
+ normalized = dict(app_normalize(normalized) or {})
186
+ return normalized
187
+
188
+
189
+ def _typed_or_raw_app_namespace(resolved: Any, app_id: str) -> Any:
190
+ typed_app_settings = getattr(resolved, "typed_app_settings", None)
191
+ if not callable(typed_app_settings):
192
+ return getattr(resolved, app_id)
193
+ settings_module, settings_type = _app_settings_module_and_type(resolved, app_id)
194
+ if settings_type is None:
195
+ return getattr(resolved, app_id)
196
+ return typed_app_settings(
197
+ app_id,
198
+ settings_type,
199
+ normalize=lambda values: _normalize_with_app_schema(settings_module, settings_type, values),
200
+ )
201
+
202
+
203
+ def _payload_from_namespace(namespace: Any) -> dict[str, Any]:
204
+ if isinstance(namespace, dict):
205
+ return dict(namespace)
206
+ model_dump = getattr(namespace, "model_dump", None)
207
+ if callable(model_dump):
208
+ mapped = model_dump()
209
+ if isinstance(mapped, dict):
210
+ return dict(mapped)
211
+ to_dict = getattr(namespace, "to_dict", None)
212
+ if callable(to_dict):
213
+ mapped = to_dict()
214
+ if isinstance(mapped, dict):
215
+ return dict(mapped)
216
+ return dict(getattr(namespace, "__dict__", {}) or {})
217
+
218
+
219
+ def resolve_app_settings_payload(resolved: Any, app_id: str) -> dict[str, Any]:
220
+ return _payload_from_namespace(_typed_or_raw_app_namespace(resolved, app_id))
221
+
222
+
223
+ def _mapping_path_value(mapping: dict[str, Any], path: tuple[str, ...], *, default: Any = None) -> Any:
224
+ current: Any = mapping
225
+ for key in path:
226
+ if not isinstance(current, dict) or key not in current:
227
+ return default
228
+ current = current[key]
229
+ return default if current is None else current
230
+
231
+
232
+ class _NamespaceProxy:
233
+ def __init__(self, payload: Any) -> None:
234
+ self._payload = payload
235
+
236
+ def _mapping(self) -> dict[str, Any]:
237
+ if isinstance(self._payload, dict):
238
+ return self._payload
239
+ model_dump = getattr(self._payload, "model_dump", None)
240
+ if callable(model_dump):
241
+ mapped = model_dump()
242
+ if isinstance(mapped, dict):
243
+ return mapped
244
+ to_dict = getattr(self._payload, "to_dict", None)
245
+ if callable(to_dict):
246
+ mapped = to_dict()
247
+ if isinstance(mapped, dict):
248
+ return mapped
249
+ return getattr(self._payload, "__dict__", {})
250
+
251
+ def get(self, key: str, default: Any = None) -> Any:
252
+ mapping = self._mapping()
253
+ if key in mapping:
254
+ return _wrap_namespace(mapping[key])
255
+ return default
256
+
257
+ def to_dict(self) -> dict[str, Any]:
258
+ return dict(self._mapping())
259
+
260
+ def __getattr__(self, name: str) -> Any:
261
+ mapping = self._mapping()
262
+ if name not in mapping:
263
+ raise AttributeError(name)
264
+ return _wrap_namespace(mapping[name])
265
+
266
+ def __bool__(self) -> bool:
267
+ return bool(self._payload)
268
+
269
+ def __iter__(self):
270
+ return iter(self._mapping())
271
+
272
+ def items(self):
273
+ return self._mapping().items()
274
+
275
+
276
+ def _wrap_namespace(payload: Any) -> Any:
277
+ if isinstance(payload, dict):
278
+ return _NamespaceProxy(payload)
279
+ if hasattr(payload, "to_dict"):
280
+ try:
281
+ mapped = payload.to_dict()
282
+ except Exception:
283
+ mapped = None
284
+ if isinstance(mapped, dict):
285
+ return _NamespaceProxy(mapped)
286
+ if hasattr(payload, "__dict__"):
287
+ mapping = getattr(payload, "__dict__", {}) or {}
288
+ if mapping:
289
+ return _NamespaceProxy(payload)
290
+ return payload
291
+
292
+
293
+ class SettingsCenterProxy:
294
+ """Application-facing settings proxy with settings-only lazy autoload."""
295
+
296
+ @property
297
+ def project(self):
298
+ return _wrap_namespace(_active_resolve_settings().project)
299
+
300
+ def app_settings(self, app_id: str) -> dict[str, Any]:
301
+ return resolve_app_settings_payload(_active_resolve_settings(), app_id)
302
+
303
+ def get(self, *path: str, default: Any = None) -> Any:
304
+ resolved = _active_resolve_settings()
305
+ if path and str(path[0]).strip() in _declared_app_ids(resolved):
306
+ app_values = resolve_app_settings_payload(resolved, str(path[0]).strip())
307
+ if len(path) == 1:
308
+ return app_values
309
+ return _mapping_path_value(app_values, tuple(str(item) for item in path[1:]), default=default)
310
+ return resolved.get(*path, default=default)
311
+
312
+ def __getattr__(self, name: str) -> Any:
313
+ return _wrap_namespace(_typed_or_raw_app_namespace(_active_resolve_settings(), name))
314
+
315
+
316
+ settings = SettingsCenterProxy()
317
+
318
+ __all__ = [
319
+ "ResolvedSettings",
320
+ "SettingsCenterProxy",
321
+ "resolve_app_settings_payload",
322
+ "resolve_settings",
323
+ "settings",
324
+ ]
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ app_name = "pz_settings_center"
5
+
6
+ urlpatterns = ()
7
+
8
+
9
+ __all__ = ["app_name", "urlpatterns"]