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.
- pz_cli-5.0.0.dist-info/METADATA +51 -0
- pz_cli-5.0.0.dist-info/RECORD +399 -0
- pz_cli-5.0.0.dist-info/WHEEL +4 -0
- pz_cli-5.0.0.dist-info/entry_points.txt +5 -0
- pz_core/__init__.py +64 -0
- pz_core/__main__.py +7 -0
- pz_core/app.py +45 -0
- pz_core/assembly/__init__.py +17 -0
- pz_core/assembly/app_discovery.py +1240 -0
- pz_core/assembly/apps/__init__.py +25 -0
- pz_core/assembly/apps/compiler.py +824 -0
- pz_core/assembly/apps/providers.py +188 -0
- pz_core/assembly/cli/__init__.py +9 -0
- pz_core/assembly/cli/compiler.py +166 -0
- pz_core/assembly/diagnostics/__init__.py +21 -0
- pz_core/assembly/diagnostics/checks.py +257 -0
- pz_core/assembly/diagnostics/dev_sources.py +569 -0
- pz_core/assembly/events/__init__.py +5 -0
- pz_core/assembly/events/compiler.py +219 -0
- pz_core/assembly/extensions/__init__.py +5 -0
- pz_core/assembly/extensions/compiler.py +696 -0
- pz_core/assembly/infra/__init__.py +6 -0
- pz_core/assembly/infra/compiler.py +272 -0
- pz_core/assembly/lifecycle/__init__.py +5 -0
- pz_core/assembly/lifecycle/compiler.py +95 -0
- pz_core/assembly/middlewares/__init__.py +19 -0
- pz_core/assembly/middlewares/compiler.py +508 -0
- pz_core/assembly/project/__init__.py +7 -0
- pz_core/assembly/project/compiler.py +9 -0
- pz_core/assembly/project/context.py +17 -0
- pz_core/assembly/project/discovery.py +227 -0
- pz_core/assembly/resources/__init__.py +19 -0
- pz_core/assembly/resources/compiler.py +310 -0
- pz_core/assembly/resources/settings.py +129 -0
- pz_core/assembly/routes/__init__.py +7 -0
- pz_core/assembly/routes/compiler.py +400 -0
- pz_core/assembly/runtime_manifests/__init__.py +13 -0
- pz_core/assembly/runtime_manifests/compiler.py +159 -0
- pz_core/assembly/settings/__init__.py +17 -0
- pz_core/assembly/settings/compiler.py +786 -0
- pz_core/assembly/settings/host_project_overrides.py +82 -0
- pz_core/assembly/settings/host_runtime_endpoint.py +207 -0
- pz_core/authoring/__init__.py +79 -0
- pz_core/authoring/app_init_service.py +946 -0
- pz_core/authoring/app_versions.py +814 -0
- pz_core/authoring/cli.py +192 -0
- pz_core/authoring/commands.py +1810 -0
- pz_core/authoring/conflicts.py +180 -0
- pz_core/authoring/dev_bindings.py +916 -0
- pz_core/authoring/dev_git.py +1087 -0
- pz_core/authoring/dev_import.py +1061 -0
- pz_core/authoring/dev_manifest.py +522 -0
- pz_core/authoring/dev_sources.py +1638 -0
- pz_core/authoring/env_cli.py +454 -0
- pz_core/authoring/files.py +109 -0
- pz_core/authoring/ide_projection.py +1129 -0
- pz_core/authoring/naming.py +58 -0
- pz_core/authoring/official_dev_sources.py +432 -0
- pz_core/authoring/official_sources.json +156 -0
- pz_core/authoring/orchestration_service.py +558 -0
- pz_core/authoring/project_default.jsonc +53 -0
- pz_core/authoring/project_defaults.py +88 -0
- pz_core/authoring/project_metadata_service.py +199 -0
- pz_core/authoring/project_settings_checks.py +51 -0
- pz_core/authoring/project_settings_cli.py +299 -0
- pz_core/authoring/project_settings_service.py +1700 -0
- pz_core/authoring/project_state.py +399 -0
- pz_core/authoring/publish_git.py +423 -0
- pz_core/authoring/publish_lock.py +188 -0
- pz_core/authoring/publish_source.py +195 -0
- pz_core/authoring/release.py +1382 -0
- pz_core/authoring/repo_keys.py +29 -0
- pz_core/authoring/root_cli.py +28 -0
- pz_core/authoring/scaffold_service.py +325 -0
- pz_core/authoring/sync_service.py +787 -0
- pz_core/authoring/templates/app/__init__.py +1 -0
- pz_core/authoring/templates/app/api.py +25 -0
- pz_core/authoring/templates/app/apps.py +31 -0
- pz_core/authoring/templates/app/auth_package_init.py +14 -0
- pz_core/authoring/templates/app/auth_readme.py +29 -0
- pz_core/authoring/templates/app/configs_package_init.py +14 -0
- pz_core/authoring/templates/app/default_env.py +18 -0
- pz_core/authoring/templates/app/default_jsonc.py +25 -0
- pz_core/authoring/templates/app/locales_readme.py +25 -0
- pz_core/authoring/templates/app/migrations_readme.py +19 -0
- pz_core/authoring/templates/app/models.py +14 -0
- pz_core/authoring/templates/app/package_init.py +8 -0
- pz_core/authoring/templates/app/pages_base.py +161 -0
- pz_core/authoring/templates/app/pages_readme.py +25 -0
- pz_core/authoring/templates/app/public.py +31 -0
- pz_core/authoring/templates/app/pyproject.py +77 -0
- pz_core/authoring/templates/app/readme.py +74 -0
- pz_core/authoring/templates/app/settings.py +46 -0
- pz_core/authoring/templates/app/static_app_js.py +24 -0
- pz_core/authoring/templates/app/static_readme.py +31 -0
- pz_core/authoring/templates/app/template_config_page.py +23 -0
- pz_core/authoring/templates/app/template_index_html.py +28 -0
- pz_core/authoring/templates/app/templates_readme.py +32 -0
- pz_core/authoring/templates/app/urls.py +36 -0
- pz_core/authoring/templates/app/views.py +36 -0
- pz_core/authoring/templates/project/__init__.py +1 -0
- pz_core/authoring/templates/project/agents.py +51 -0
- pz_core/authoring/templates/project/apps_container_readme.py +37 -0
- pz_core/authoring/templates/project/main_py.py +59 -0
- pz_core/authoring/templates/project/project_env.py +19 -0
- pz_core/authoring/templates/project/pyproject.py +26 -0
- pz_core/authoring/templates/project/pz_env_env.py +65 -0
- pz_core/authoring/templates/project/pz_env_jsonc.py +69 -0
- pz_core/authoring/templates/project/pz_jsonc.py +12 -0
- pz_core/authoring/templates/project/readme.py +94 -0
- pz_core/authoring/templates/project/root_gitkeep.py +8 -0
- pz_core/authoring/templates/shared/__init__.py +5 -0
- pz_core/authoring/templates/shared/text.py +10 -0
- pz_core/authoring/venv_service.py +87 -0
- pz_core/authoring/workspace.py +167 -0
- pz_core/cli.py +291 -0
- pz_core/cli_options.py +74 -0
- pz_core/core/__init__.py +3 -0
- pz_core/core/errors/__init__.py +5 -0
- pz_core/core/errors/models.py +117 -0
- pz_core/core/events/__init__.py +5 -0
- pz_core/core/events/registry.py +54 -0
- pz_core/core/extensions/__init__.py +51 -0
- pz_core/core/extensions/registry.py +790 -0
- pz_core/core/health/__init__.py +6 -0
- pz_core/core/health/contracts.py +10 -0
- pz_core/core/middlewares/__init__.py +6 -0
- pz_core/core/middlewares/models.py +24 -0
- pz_core/core/routing/__init__.py +5 -0
- pz_core/core/routing/models.py +21 -0
- pz_core/core/settings_contracts.py +25 -0
- pz_core/docs/README.md +20 -0
- pz_core/docs/distribution-README.md +438 -0
- pz_core/docs/pz/345/221/275/344/273/244/346/200/273/350/247/210.md +1011 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/README.md +98 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- pz_core/docs//345/217/221/347/211/210/345/211/215/346/270/205/345/215/225-4.0.11.md +84 -0
- pz_core/docs//346/226/260/346/211/213/346/214/207/345/215/227.md +422 -0
- pz_core/infra/__init__.py +17 -0
- pz_core/infra/db/__init__.py +23 -0
- pz_core/infra/db/contracts.py +73 -0
- pz_core/infra/health/__init__.py +5 -0
- pz_core/infra/health/contracts.py +8 -0
- pz_core/infra/kv/__init__.py +5 -0
- pz_core/infra/kv/contracts.py +17 -0
- pz_core/infra/observability/__init__.py +23 -0
- pz_core/infra/observability/contracts.py +142 -0
- pz_core/infra/resilience/__init__.py +5 -0
- pz_core/infra/resilience/contracts.py +17 -0
- pz_core/infra/resources/__init__.py +5 -0
- pz_core/infra/resources/contracts.py +16 -0
- pz_core/infra/settings/__init__.py +17 -0
- pz_core/infra/settings/models.py +81 -0
- pz_core/infra/storage/__init__.py +5 -0
- pz_core/infra/storage/ports.py +27 -0
- pz_core/project_root_commands.py +282 -0
- pz_core/project_runtime_cli.py +344 -0
- pz_core/project_sources.py +253 -0
- pz_core/pz_launcher.py +209 -0
- pz_core/root_cli.py +70 -0
- pz_core/runtime/__init__.py +229 -0
- pz_core/runtime/access.py +86 -0
- pz_core/runtime/adapters/__init__.py +5 -0
- pz_core/runtime/adapters/base.py +18 -0
- pz_core/runtime/asyncio_bridge.py +18 -0
- pz_core/runtime/bindings/__init__.py +5 -0
- pz_core/runtime/bindings/container.py +50 -0
- pz_core/runtime/cli/__init__.py +5 -0
- pz_core/runtime/cli/_args.py +67 -0
- pz_core/runtime/cli/app_commands.py +417 -0
- pz_core/runtime/cli/check.py +214 -0
- pz_core/runtime/cli/db.py +297 -0
- pz_core/runtime/cli/main.py +89 -0
- pz_core/runtime/cli/resources.py +280 -0
- pz_core/runtime/discovery.py +23 -0
- pz_core/runtime/environment_integrity.py +157 -0
- pz_core/runtime/errors.py +5 -0
- pz_core/runtime/events.py +87 -0
- pz_core/runtime/facades/__init__.py +38 -0
- pz_core/runtime/facades/_capabilities.py +46 -0
- pz_core/runtime/facades/cache.py +103 -0
- pz_core/runtime/facades/database.py +71 -0
- pz_core/runtime/facades/events.py +380 -0
- pz_core/runtime/facades/health.py +101 -0
- pz_core/runtime/facades/mail.py +121 -0
- pz_core/runtime/facades/observability.py +102 -0
- pz_core/runtime/facades/providers.py +75 -0
- pz_core/runtime/facades/resources.py +52 -0
- pz_core/runtime/facades/storage.py +296 -0
- pz_core/runtime/health/__init__.py +5 -0
- pz_core/runtime/health/service.py +102 -0
- pz_core/runtime/host.py +188 -0
- pz_core/runtime/host_runner.py +282 -0
- pz_core/runtime/http/__init__.py +20 -0
- pz_core/runtime/http/app.py +576 -0
- pz_core/runtime/http_timing.py +173 -0
- pz_core/runtime/invocation.py +29 -0
- pz_core/runtime/json_safe.py +47 -0
- pz_core/runtime/lifecycle/__init__.py +25 -0
- pz_core/runtime/lifecycle/manager.py +533 -0
- pz_core/runtime/plan.py +214 -0
- pz_core/runtime/plan_context.py +33 -0
- pz_core/runtime/plan_snapshot.py +177 -0
- pz_core/runtime/registries/__init__.py +27 -0
- pz_core/runtime/registries/capabilities.py +101 -0
- pz_core/runtime/registries/providers.py +396 -0
- pz_core/runtime/resource_assets.py +344 -0
- pz_core/runtime/run_cli.py +211 -0
- pz_core/runtime/settings.py +888 -0
- pz_core/runtime/worker/__init__.py +21 -0
- pz_core/runtime/worker/engine.py +921 -0
- pz_core/runtime/worker/runtime.py +25 -0
- pz_core/testing/__init__.py +15 -0
- pz_core/testing/doc_route_contracts.py +305 -0
- pz_core/utils/__init__.py +44 -0
- pz_core/utils/env.py +65 -0
- pz_core/utils/project_jsonc/__init__.py +29 -0
- pz_core/utils/project_jsonc/document.py +420 -0
- pz_core/utils/project_settings.py +99 -0
- pz_foundation/__init__.py +50 -0
- pz_foundation/_contracts.py +81 -0
- pz_foundation/_errors.py +34 -0
- pz_foundation/api.py +14 -0
- pz_foundation/apps.py +127 -0
- pz_foundation/auth/__init__.py +1 -0
- pz_foundation/cache_control.py +233 -0
- pz_foundation/cli/__init__.py +2 -0
- pz_foundation/cli/workers.py +565 -0
- pz_foundation/configs/__init__.py +0 -0
- pz_foundation/configs/default.env +15 -0
- pz_foundation/configs/default.jsonc +452 -0
- pz_foundation/db/__init__.py +94 -0
- pz_foundation/db/aerich_executor.py +664 -0
- pz_foundation/db/config.py +358 -0
- pz_foundation/db/connection_manager.py +689 -0
- pz_foundation/db/connection_probe.py +204 -0
- pz_foundation/db/database.py +1291 -0
- pz_foundation/db/deps.py +47 -0
- pz_foundation/db/lifecycle_status.py +85 -0
- pz_foundation/db/migrations.py +477 -0
- pz_foundation/db/mysql.py +57 -0
- pz_foundation/db/postgresql.py +409 -0
- pz_foundation/db/production_pool_fallback.py +143 -0
- pz_foundation/db/public.py +45 -0
- pz_foundation/db/session.py +369 -0
- pz_foundation/db/sqlite.py +15 -0
- pz_foundation/db/tortoise_manager.py +724 -0
- pz_foundation/db/tortoise_psycopg.py +148 -0
- pz_foundation/docs/README.md +18 -0
- pz_foundation/docs/distribution-README.md +319 -0
- 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
- 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
- pz_foundation/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +288 -0
- 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
- pz_foundation/health.py +105 -0
- pz_foundation/host/__init__.py +11 -0
- pz_foundation/host/builder.py +34 -0
- pz_foundation/host/cache_runtime.py +44 -0
- pz_foundation/host/db/__init__.py +17 -0
- pz_foundation/host/db/aerich_config.py +36 -0
- pz_foundation/host/db/config.py +106 -0
- pz_foundation/host/db/connection_manager.py +48 -0
- pz_foundation/host/db/deps.py +5 -0
- pz_foundation/host/db/orm_retry_patch.py +566 -0
- pz_foundation/host/db/request_adapter.py +325 -0
- pz_foundation/host/db/router.py +28 -0
- pz_foundation/host/db/session.py +284 -0
- pz_foundation/host/db/tortoise_manager.py +10 -0
- pz_foundation/host/idempotency.py +132 -0
- pz_foundation/host/lifespan.py +247 -0
- pz_foundation/host/redis_runtime.py +100 -0
- pz_foundation/host/web.py +790 -0
- pz_foundation/infra_provider.py +236 -0
- pz_foundation/kv/__init__.py +25 -0
- pz_foundation/kv/cache.py +1166 -0
- pz_foundation/kv/deps.py +84 -0
- pz_foundation/kv/public.py +25 -0
- pz_foundation/kv/redis_manager.py +1531 -0
- pz_foundation/lazy_exports.py +43 -0
- pz_foundation/lazy_imports.py +124 -0
- pz_foundation/lifecycle.py +392 -0
- pz_foundation/managed_workers.py +1117 -0
- pz_foundation/middlewares/__init__.py +26 -0
- pz_foundation/middlewares/_settings.py +250 -0
- pz_foundation/middlewares/analytics.py +124 -0
- pz_foundation/middlewares/cache_control.py +156 -0
- pz_foundation/middlewares/compression.py +202 -0
- pz_foundation/middlewares/cors.py +62 -0
- pz_foundation/middlewares/geo_country.py +44 -0
- pz_foundation/middlewares/inner_router.py +50 -0
- pz_foundation/middlewares/rate_limited/__init__.py +3 -0
- pz_foundation/middlewares/rate_limited/key_limiter.py +115 -0
- pz_foundation/middlewares/request_logging.py +104 -0
- pz_foundation/middlewares/route_owner.py +309 -0
- pz_foundation/middlewares/security_csrf.py +44 -0
- pz_foundation/middlewares/security_headers/__init__.py +4 -0
- pz_foundation/middlewares/security_headers/conflicts.py +44 -0
- pz_foundation/middlewares/security_headers/csp_nonce.py +200 -0
- pz_foundation/middlewares/security_headers/security_headers.py +44 -0
- pz_foundation/migrations/__init__.py +1 -0
- pz_foundation/migrations/pz_foundation/__init__.py +1 -0
- pz_foundation/models.py +22 -0
- pz_foundation/notifications/__init__.py +23 -0
- pz_foundation/notifications/email.py +542 -0
- pz_foundation/notifications/public.py +31 -0
- pz_foundation/observability/__init__.py +71 -0
- pz_foundation/observability/http.py +34 -0
- pz_foundation/observability/logger/__init__.py +49 -0
- pz_foundation/observability/logger/_bot_settings.py +126 -0
- pz_foundation/observability/logger/bot_message.py +592 -0
- pz_foundation/observability/logger/core.py +385 -0
- pz_foundation/observability/logger/delivery_audit.py +84 -0
- pz_foundation/observability/logger/feishu_bot.py +199 -0
- pz_foundation/observability/logger/telegram_bot.py +194 -0
- pz_foundation/observability/metrics.py +365 -0
- pz_foundation/observability/runtime.py +68 -0
- pz_foundation/public.py +405 -0
- pz_foundation/resources/__init__.py +12 -0
- pz_foundation/resources/builder.py +900 -0
- pz_foundation/resources/images.py +363 -0
- pz_foundation/root_cli.py +20 -0
- pz_foundation/routing/__init__.py +203 -0
- pz_foundation/routing/canonical.py +486 -0
- pz_foundation/routing/convertors.py +82 -0
- pz_foundation/routing/declarations.py +843 -0
- pz_foundation/routing/exports.py +148 -0
- pz_foundation/routing/loaders.py +138 -0
- pz_foundation/routing/manifest.py +215 -0
- pz_foundation/routing/manifest_provider.py +47 -0
- pz_foundation/routing/mounts.py +101 -0
- pz_foundation/routing/ordering.py +172 -0
- pz_foundation/routing/registry.py +133 -0
- pz_foundation/routing/utils.py +28 -0
- pz_foundation/runtime.py +234 -0
- pz_foundation/settings.py +253 -0
- pz_foundation/settings_normalization.py +130 -0
- pz_foundation/storage/__init__.py +25 -0
- pz_foundation/storage/local.py +209 -0
- pz_foundation/storage/public.py +106 -0
- pz_foundation/storage/s3.py +116 -0
- pz_foundation/storage/service.py +234 -0
- pz_foundation/urls.py +19 -0
- pz_foundation/utils/__init__.py +6 -0
- pz_foundation/utils/merge.py +160 -0
- pz_foundation/worker_replicas.py +55 -0
- pz_settings_center/__init__.py +5 -0
- pz_settings_center/api/__init__.py +5 -0
- pz_settings_center/api/runtime_overrides.py +360 -0
- pz_settings_center/apps.py +28 -0
- pz_settings_center/configs/__init__.py +0 -0
- pz_settings_center/configs/default.env +2 -0
- pz_settings_center/configs/default.jsonc +1 -0
- pz_settings_center/docs/01-settings_center/350/203/275/345/212/233/350/276/271/347/225/214.md +124 -0
- pz_settings_center/docs/README.md +12 -0
- pz_settings_center/docs/distribution-README.md +150 -0
- pz_settings_center/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +48 -0
- pz_settings_center/integration_payload.py +18 -0
- pz_settings_center/project_helpers.py +405 -0
- pz_settings_center/public.py +139 -0
- pz_settings_center/routing_helpers.py +73 -0
- pz_settings_center/runtime_override_provider.py +61 -0
- pz_settings_center/typed_settings.py +324 -0
- 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
|
+
]
|