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,282 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import shlex
|
|
6
|
+
import subprocess
|
|
7
|
+
from collections.abc import Mapping, Sequence
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from pz_core.authoring.project_defaults import load_project_default_jsonc_payload
|
|
13
|
+
from pz_core.project_runtime_cli import resolve_cli_project_dir
|
|
14
|
+
from pz_core.root_cli import CommandPath, RootCommandHandler
|
|
15
|
+
from pz_core.utils.project_jsonc import PROJECT_JSONC_NAME, load_jsonc_file
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_OWNER = "pz_core.project_root_commands"
|
|
19
|
+
_COMMAND_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9:_-]*$")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True, slots=True)
|
|
23
|
+
class ProjectRootCommandBinding:
|
|
24
|
+
name: str
|
|
25
|
+
source_kind: str
|
|
26
|
+
target: str
|
|
27
|
+
description: str | None
|
|
28
|
+
handler: RootCommandHandler
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True, slots=True)
|
|
32
|
+
class ConfiguredProjectCommand:
|
|
33
|
+
name: str
|
|
34
|
+
description: str | None
|
|
35
|
+
argv: tuple[str, ...] | None
|
|
36
|
+
shell_command: str | None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def discover_project_root_command_bindings(
|
|
40
|
+
*,
|
|
41
|
+
reserved_paths: Sequence[CommandPath] = (),
|
|
42
|
+
project_dir: Path | None = None,
|
|
43
|
+
) -> tuple[ProjectRootCommandBinding, ...]:
|
|
44
|
+
resolved_project_dir = project_dir if project_dir is not None else resolve_cli_project_dir()
|
|
45
|
+
if resolved_project_dir is None:
|
|
46
|
+
return ()
|
|
47
|
+
project_dir = resolved_project_dir.resolve()
|
|
48
|
+
reserved_tokens = {path[0] for path in reserved_paths if path}
|
|
49
|
+
|
|
50
|
+
bindings: list[ProjectRootCommandBinding] = []
|
|
51
|
+
for command in _discover_configured_project_commands(project_dir):
|
|
52
|
+
if command.name in reserved_tokens:
|
|
53
|
+
continue
|
|
54
|
+
bindings.append(
|
|
55
|
+
ProjectRootCommandBinding(
|
|
56
|
+
name=command.name,
|
|
57
|
+
source_kind="project_command",
|
|
58
|
+
target=command.shell_command or shlex.join(command.argv or ()),
|
|
59
|
+
description=command.description,
|
|
60
|
+
handler=RootCommandHandler(
|
|
61
|
+
command_path=(command.name,),
|
|
62
|
+
handler=lambda argv, command=command, project_dir=project_dir: _run_project_command(
|
|
63
|
+
command,
|
|
64
|
+
project_dir=project_dir,
|
|
65
|
+
argv=_strip_root_project_dir_args(argv),
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
reserved_tokens.add(command.name)
|
|
71
|
+
|
|
72
|
+
return tuple(bindings)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def discover_project_root_command_handlers(
|
|
76
|
+
*,
|
|
77
|
+
reserved_paths: Sequence[CommandPath] = (),
|
|
78
|
+
project_dir: Path | None = None,
|
|
79
|
+
) -> dict[CommandPath, RootCommandHandler]:
|
|
80
|
+
return {
|
|
81
|
+
binding.handler.command_path: binding.handler
|
|
82
|
+
for binding in discover_project_root_command_bindings(
|
|
83
|
+
reserved_paths=reserved_paths,
|
|
84
|
+
project_dir=project_dir,
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def render_project_root_command_help(
|
|
90
|
+
*,
|
|
91
|
+
reserved_paths: Sequence[CommandPath] = (),
|
|
92
|
+
project_dir: Path | None = None,
|
|
93
|
+
) -> str:
|
|
94
|
+
bindings = discover_project_root_command_bindings(
|
|
95
|
+
reserved_paths=reserved_paths,
|
|
96
|
+
project_dir=project_dir,
|
|
97
|
+
)
|
|
98
|
+
if not bindings:
|
|
99
|
+
return ""
|
|
100
|
+
lines = ["", "Extensions:"]
|
|
101
|
+
for binding in bindings:
|
|
102
|
+
description = binding.description
|
|
103
|
+
if not description:
|
|
104
|
+
description = f"Project command -> {binding.target}"
|
|
105
|
+
lines.append(f" {binding.name}")
|
|
106
|
+
lines.append(f" {description}")
|
|
107
|
+
return "\n".join(lines) + "\n"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _discover_configured_project_commands(project_dir: Path) -> tuple[ConfiguredProjectCommand, ...]:
|
|
111
|
+
defaults = load_project_default_jsonc_payload()
|
|
112
|
+
commands_payload = _merge_command_payloads(
|
|
113
|
+
defaults.get("commands"),
|
|
114
|
+
_read_project_config(project_dir).get("commands"),
|
|
115
|
+
)
|
|
116
|
+
commands: list[ConfiguredProjectCommand] = []
|
|
117
|
+
for raw_name, raw_spec in sorted(commands_payload.items()):
|
|
118
|
+
name = _normalize_command_name(raw_name)
|
|
119
|
+
if name is None:
|
|
120
|
+
continue
|
|
121
|
+
commands.append(_coerce_project_command(name=name, payload=raw_spec))
|
|
122
|
+
return tuple(commands)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _read_project_config(project_dir: Path) -> dict[str, Any]:
|
|
126
|
+
project_path = project_dir / PROJECT_JSONC_NAME
|
|
127
|
+
if not project_path.is_file():
|
|
128
|
+
return {}
|
|
129
|
+
payload = load_jsonc_file(
|
|
130
|
+
project_path,
|
|
131
|
+
code="PZ_PROJECT_CONFIG_INVALID",
|
|
132
|
+
owner=_OWNER,
|
|
133
|
+
action="load_project_root_commands",
|
|
134
|
+
)
|
|
135
|
+
if not isinstance(payload, dict):
|
|
136
|
+
return {}
|
|
137
|
+
return dict(payload)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _merge_command_payloads(defaults: object, project_payload: object) -> dict[str, Any]:
|
|
141
|
+
merged: dict[str, Any] = {}
|
|
142
|
+
for candidate in (defaults, project_payload):
|
|
143
|
+
if not isinstance(candidate, Mapping):
|
|
144
|
+
continue
|
|
145
|
+
for key, value in candidate.items():
|
|
146
|
+
if isinstance(value, Mapping) and isinstance(merged.get(key), dict):
|
|
147
|
+
merged[key] = _deep_merge_mappings(merged[key], value)
|
|
148
|
+
else:
|
|
149
|
+
merged[str(key)] = value
|
|
150
|
+
return merged
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _deep_merge_mappings(base: Mapping[str, Any], incoming: Mapping[str, Any]) -> dict[str, Any]:
|
|
154
|
+
merged = dict(base)
|
|
155
|
+
for key, value in incoming.items():
|
|
156
|
+
existing = merged.get(key)
|
|
157
|
+
if isinstance(existing, Mapping) and isinstance(value, Mapping):
|
|
158
|
+
merged[str(key)] = _deep_merge_mappings(existing, value)
|
|
159
|
+
continue
|
|
160
|
+
merged[str(key)] = value
|
|
161
|
+
return merged
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _normalize_command_name(raw_name: object) -> str | None:
|
|
165
|
+
if not isinstance(raw_name, str):
|
|
166
|
+
return None
|
|
167
|
+
name = raw_name.strip().lower()
|
|
168
|
+
if not name or not _COMMAND_NAME_RE.match(name):
|
|
169
|
+
return None
|
|
170
|
+
return name
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _coerce_project_command(*, name: str, payload: object) -> ConfiguredProjectCommand:
|
|
174
|
+
if isinstance(payload, str) and payload.strip():
|
|
175
|
+
return ConfiguredProjectCommand(
|
|
176
|
+
name=name,
|
|
177
|
+
description=None,
|
|
178
|
+
argv=None,
|
|
179
|
+
shell_command=payload.strip(),
|
|
180
|
+
)
|
|
181
|
+
if isinstance(payload, Sequence) and not isinstance(payload, (str, bytes)):
|
|
182
|
+
argv = tuple(str(item).strip() for item in payload if str(item).strip())
|
|
183
|
+
if argv:
|
|
184
|
+
return ConfiguredProjectCommand(
|
|
185
|
+
name=name,
|
|
186
|
+
description=None,
|
|
187
|
+
argv=argv,
|
|
188
|
+
shell_command=None,
|
|
189
|
+
)
|
|
190
|
+
if isinstance(payload, Mapping):
|
|
191
|
+
description = str(payload.get("description") or "").strip() or None
|
|
192
|
+
raw_command = payload.get("command")
|
|
193
|
+
if isinstance(raw_command, str) and raw_command.strip():
|
|
194
|
+
return ConfiguredProjectCommand(
|
|
195
|
+
name=name,
|
|
196
|
+
description=description,
|
|
197
|
+
argv=None,
|
|
198
|
+
shell_command=raw_command.strip(),
|
|
199
|
+
)
|
|
200
|
+
raw_argv = payload.get("argv")
|
|
201
|
+
if isinstance(raw_argv, Sequence) and not isinstance(raw_argv, (str, bytes)):
|
|
202
|
+
argv = tuple(str(item).strip() for item in raw_argv if str(item).strip())
|
|
203
|
+
if argv:
|
|
204
|
+
return ConfiguredProjectCommand(
|
|
205
|
+
name=name,
|
|
206
|
+
description=description,
|
|
207
|
+
argv=argv,
|
|
208
|
+
shell_command=None,
|
|
209
|
+
)
|
|
210
|
+
raise ValueError(f"Invalid project root command configuration for `{name}`")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _run_project_command(command: ConfiguredProjectCommand, *, project_dir: Path, argv: Sequence[str]) -> int:
|
|
214
|
+
env = _build_project_command_env(project_dir, command.name)
|
|
215
|
+
if command.shell_command is not None:
|
|
216
|
+
extra = shlex.join([str(item) for item in argv if str(item).strip()])
|
|
217
|
+
shell_command = command.shell_command if not extra else f"{command.shell_command} {extra}"
|
|
218
|
+
completed = subprocess.run(
|
|
219
|
+
shell_command,
|
|
220
|
+
cwd=str(project_dir),
|
|
221
|
+
env=env,
|
|
222
|
+
shell=True,
|
|
223
|
+
check=False,
|
|
224
|
+
)
|
|
225
|
+
return int(completed.returncode)
|
|
226
|
+
execution_argv = [*(command.argv or ()), *[str(item) for item in argv]]
|
|
227
|
+
completed = subprocess.run(
|
|
228
|
+
execution_argv,
|
|
229
|
+
cwd=str(project_dir),
|
|
230
|
+
env=env,
|
|
231
|
+
shell=False,
|
|
232
|
+
check=False,
|
|
233
|
+
)
|
|
234
|
+
return int(completed.returncode)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _build_project_command_env(project_dir: Path, command_name: str) -> dict[str, str]:
|
|
238
|
+
env = dict(os.environ)
|
|
239
|
+
project_dir = project_dir.resolve()
|
|
240
|
+
env["PZ_PROJECT_DIR"] = str(project_dir)
|
|
241
|
+
env["PZ_PROJECT_COMMAND"] = command_name
|
|
242
|
+
env["PZ_PROJECT_COMMAND_DEPTH"] = str(int(env.get("PZ_PROJECT_COMMAND_DEPTH", "0")) + 1)
|
|
243
|
+
path_entries = [str(path) for path in _project_bin_dirs(project_dir)]
|
|
244
|
+
existing_path = env.get("PATH", "")
|
|
245
|
+
env["PATH"] = os.pathsep.join([*path_entries, existing_path]) if existing_path else os.pathsep.join(path_entries)
|
|
246
|
+
return env
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _project_bin_dirs(project_dir: Path) -> tuple[Path, ...]:
|
|
250
|
+
candidates = (
|
|
251
|
+
project_dir / ".venv" / "bin",
|
|
252
|
+
project_dir / ".venv" / "Scripts",
|
|
253
|
+
)
|
|
254
|
+
return tuple(path.resolve() for path in candidates if path.is_dir())
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _strip_root_project_dir_args(argv: Sequence[str]) -> list[str]:
|
|
258
|
+
cleaned: list[str] = []
|
|
259
|
+
skip_next = False
|
|
260
|
+
for index, raw in enumerate(argv):
|
|
261
|
+
if skip_next:
|
|
262
|
+
skip_next = False
|
|
263
|
+
continue
|
|
264
|
+
item = str(raw)
|
|
265
|
+
if item in {"--project-dir", "-d"}:
|
|
266
|
+
skip_next = True
|
|
267
|
+
continue
|
|
268
|
+
if item.startswith("--project-dir="):
|
|
269
|
+
continue
|
|
270
|
+
if item.startswith("-d="):
|
|
271
|
+
continue
|
|
272
|
+
cleaned.append(item)
|
|
273
|
+
return cleaned
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
__all__ = [
|
|
277
|
+
"ConfiguredProjectCommand",
|
|
278
|
+
"ProjectRootCommandBinding",
|
|
279
|
+
"discover_project_root_command_bindings",
|
|
280
|
+
"discover_project_root_command_handlers",
|
|
281
|
+
"render_project_root_command_help",
|
|
282
|
+
]
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
from collections.abc import Mapping, Sequence
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from pz_core.project_sources import (
|
|
12
|
+
resolve_contrib_source_root,
|
|
13
|
+
resolve_runtime_checkout_root,
|
|
14
|
+
resolve_sources_manifest_path,
|
|
15
|
+
)
|
|
16
|
+
from pz_core.runtime.errors import PzError
|
|
17
|
+
from pz_core.utils.project_jsonc import PROJECT_JSONC_NAME
|
|
18
|
+
|
|
19
|
+
PROVIDER_LOCK_ENV_NAME = "PZ_CLI_PROVIDER_LOCK"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def resolve_cli_project_dir(argv: Sequence[str] | None = None) -> Path | None:
|
|
23
|
+
args = list(argv or sys.argv[1:])
|
|
24
|
+
explicit = _parse_project_dir_arg(args)
|
|
25
|
+
if explicit is not None:
|
|
26
|
+
return explicit
|
|
27
|
+
env_project_dir = _read_project_dir_env()
|
|
28
|
+
if env_project_dir is not None:
|
|
29
|
+
return env_project_dir
|
|
30
|
+
return _discover_project_dir_from_cwd()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def resolve_project_runtime_package_root(project_dir: Path) -> Path | None:
|
|
34
|
+
manifest_path = resolve_sources_manifest_path(project_dir)
|
|
35
|
+
if manifest_path.is_file():
|
|
36
|
+
try:
|
|
37
|
+
payload = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
38
|
+
except Exception:
|
|
39
|
+
payload = {}
|
|
40
|
+
runtime = payload.get("runtime")
|
|
41
|
+
if isinstance(runtime, dict):
|
|
42
|
+
runtime_meta = runtime.get("pz")
|
|
43
|
+
if isinstance(runtime_meta, dict):
|
|
44
|
+
raw_path = str(runtime_meta.get("path") or "").strip()
|
|
45
|
+
if raw_path:
|
|
46
|
+
resolved = _resolve_runtime_package_root_candidate(project_dir, raw_path)
|
|
47
|
+
if resolved is not None:
|
|
48
|
+
return resolved
|
|
49
|
+
return _resolve_runtime_package_root_candidate(
|
|
50
|
+
project_dir,
|
|
51
|
+
"apps/.sources/pz/pz_core/pz_core",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def handoff_to_project_runtime(
|
|
56
|
+
argv: Sequence[str] | None = None,
|
|
57
|
+
*,
|
|
58
|
+
current_package_root: Path,
|
|
59
|
+
) -> bool:
|
|
60
|
+
project_dir = resolve_cli_project_dir(argv)
|
|
61
|
+
if project_dir is None:
|
|
62
|
+
return False
|
|
63
|
+
runtime_package_root = resolve_project_runtime_package_root(project_dir)
|
|
64
|
+
if runtime_package_root is None:
|
|
65
|
+
return False
|
|
66
|
+
resolved_current = current_package_root.expanduser().resolve()
|
|
67
|
+
project_python = _resolve_project_python(project_dir, runtime_package_root=runtime_package_root)
|
|
68
|
+
if runtime_package_root.resolve() == resolved_current and _same_python_executable(project_python, sys.executable):
|
|
69
|
+
return False
|
|
70
|
+
env = _build_project_runtime_env(project_dir, runtime_package_root)
|
|
71
|
+
os.execvpe(
|
|
72
|
+
project_python,
|
|
73
|
+
[project_python, "-m", "pz_core", *list(argv or sys.argv[1:])],
|
|
74
|
+
env,
|
|
75
|
+
)
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def run_project_runtime_json_command(
|
|
80
|
+
project_dir: Path,
|
|
81
|
+
argv: Sequence[str],
|
|
82
|
+
*,
|
|
83
|
+
action: str,
|
|
84
|
+
error_code: str,
|
|
85
|
+
error_message: str,
|
|
86
|
+
) -> dict[str, object]:
|
|
87
|
+
runtime_package_root = resolve_project_runtime_package_root(project_dir)
|
|
88
|
+
if runtime_package_root is None:
|
|
89
|
+
raise PzError(
|
|
90
|
+
code=error_code,
|
|
91
|
+
message=error_message,
|
|
92
|
+
stage="cli",
|
|
93
|
+
owner="pz_core.project_runtime",
|
|
94
|
+
action=action,
|
|
95
|
+
detail=f"missing runtime binding for {project_dir}",
|
|
96
|
+
)
|
|
97
|
+
project_python = _resolve_project_python(project_dir, runtime_package_root=runtime_package_root)
|
|
98
|
+
completed = subprocess.run(
|
|
99
|
+
[project_python, "-m", "pz_core", *argv],
|
|
100
|
+
check=False,
|
|
101
|
+
capture_output=True,
|
|
102
|
+
text=True,
|
|
103
|
+
env=_build_project_runtime_env(project_dir, runtime_package_root),
|
|
104
|
+
)
|
|
105
|
+
if completed.returncode != 0:
|
|
106
|
+
detail = (completed.stderr or completed.stdout or "project runtime command failed").strip()
|
|
107
|
+
raise PzError(
|
|
108
|
+
code=error_code,
|
|
109
|
+
message=error_message,
|
|
110
|
+
stage="cli",
|
|
111
|
+
owner="pz_core.project_runtime",
|
|
112
|
+
action=action,
|
|
113
|
+
detail=detail,
|
|
114
|
+
)
|
|
115
|
+
output = (completed.stdout or "").strip()
|
|
116
|
+
try:
|
|
117
|
+
payload = json.loads(output)
|
|
118
|
+
except Exception as exc:
|
|
119
|
+
raise PzError(
|
|
120
|
+
code=error_code,
|
|
121
|
+
message=error_message,
|
|
122
|
+
stage="cli",
|
|
123
|
+
owner="pz_core.project_runtime",
|
|
124
|
+
action=action,
|
|
125
|
+
detail=output or str(exc),
|
|
126
|
+
) from exc
|
|
127
|
+
if not isinstance(payload, dict):
|
|
128
|
+
raise PzError(
|
|
129
|
+
code=error_code,
|
|
130
|
+
message=error_message,
|
|
131
|
+
stage="cli",
|
|
132
|
+
owner="pz_core.project_runtime",
|
|
133
|
+
action=action,
|
|
134
|
+
detail="project runtime command did not return a JSON object.",
|
|
135
|
+
)
|
|
136
|
+
return payload
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def resolve_project_pz_executable(project_dir: Path) -> str:
|
|
140
|
+
venv_root = project_dir / ".venv"
|
|
141
|
+
pz_command = _resolve_venv_pz_command(venv_root)
|
|
142
|
+
if pz_command is not None:
|
|
143
|
+
return str(pz_command)
|
|
144
|
+
resolved = shutil.which("pz")
|
|
145
|
+
if resolved:
|
|
146
|
+
return resolved
|
|
147
|
+
raise PzError(
|
|
148
|
+
code="PZ_PROJECT_RUNTIME_PZ_MISSING",
|
|
149
|
+
message="Formal `pz` launcher is required for project runtime handoff, but no `pz` command was found.",
|
|
150
|
+
stage="cli",
|
|
151
|
+
owner="pz_core.project_runtime",
|
|
152
|
+
action="resolve_project_pz_executable",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def build_project_pz_child_env(
|
|
157
|
+
project_dir: Path,
|
|
158
|
+
*,
|
|
159
|
+
pz_env: str | None = None,
|
|
160
|
+
env_overrides: Mapping[str, str | int | None] | None = None,
|
|
161
|
+
) -> dict[str, str]:
|
|
162
|
+
env = dict(os.environ)
|
|
163
|
+
env["PZ_PROJECT_DIR"] = str(project_dir.resolve())
|
|
164
|
+
inherited_pz_env = str(env.get("PZ_ENV") or "").strip()
|
|
165
|
+
resolved_pz_env = inherited_pz_env or str(pz_env or "").strip()
|
|
166
|
+
if resolved_pz_env:
|
|
167
|
+
env["PZ_ENV"] = resolved_pz_env
|
|
168
|
+
if env_overrides:
|
|
169
|
+
for raw_key, raw_value in env_overrides.items():
|
|
170
|
+
key = str(raw_key or "").strip()
|
|
171
|
+
if not key:
|
|
172
|
+
continue
|
|
173
|
+
if raw_value is None:
|
|
174
|
+
env.pop(key, None)
|
|
175
|
+
continue
|
|
176
|
+
env[key] = str(raw_value)
|
|
177
|
+
return env
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _parse_project_dir_arg(args: list[str]) -> Path | None:
|
|
181
|
+
for index, raw in enumerate(args):
|
|
182
|
+
item = str(raw).strip()
|
|
183
|
+
if not item:
|
|
184
|
+
continue
|
|
185
|
+
if item in {"--project-dir", "-d"} and index + 1 < len(args):
|
|
186
|
+
value = str(args[index + 1]).strip()
|
|
187
|
+
if value:
|
|
188
|
+
return Path(value).expanduser().resolve()
|
|
189
|
+
return None
|
|
190
|
+
prefix = "--project-dir="
|
|
191
|
+
if item.startswith(prefix):
|
|
192
|
+
value = item[len(prefix) :].strip()
|
|
193
|
+
if value:
|
|
194
|
+
return Path(value).expanduser().resolve()
|
|
195
|
+
return None
|
|
196
|
+
short_prefix = "-d="
|
|
197
|
+
if item.startswith(short_prefix):
|
|
198
|
+
value = item[len(short_prefix) :].strip()
|
|
199
|
+
if value:
|
|
200
|
+
return Path(value).expanduser().resolve()
|
|
201
|
+
return None
|
|
202
|
+
return None
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _read_project_dir_env() -> Path | None:
|
|
206
|
+
raw = os.getenv("PZ_PROJECT_DIR")
|
|
207
|
+
if not isinstance(raw, str) or not raw.strip():
|
|
208
|
+
return None
|
|
209
|
+
return Path(raw.strip()).expanduser().resolve()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _discover_project_dir_from_cwd() -> Path | None:
|
|
213
|
+
current = Path.cwd().resolve()
|
|
214
|
+
for candidate in (current, *current.parents):
|
|
215
|
+
if (candidate / PROJECT_JSONC_NAME).is_file():
|
|
216
|
+
return candidate
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _is_runtime_package_root(path: Path) -> bool:
|
|
221
|
+
return (
|
|
222
|
+
path.is_dir()
|
|
223
|
+
and (path / "__init__.py").is_file()
|
|
224
|
+
and (path / "__main__.py").is_file()
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def provider_resolution_locked() -> bool:
|
|
229
|
+
raw = os.getenv(PROVIDER_LOCK_ENV_NAME)
|
|
230
|
+
return isinstance(raw, str) and bool(raw.strip())
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _resolve_runtime_package_root_candidate(project_dir: Path, raw_path: str) -> Path | None:
|
|
234
|
+
candidate = Path(raw_path).expanduser()
|
|
235
|
+
if not candidate.is_absolute():
|
|
236
|
+
candidate = project_dir / candidate
|
|
237
|
+
if _is_runtime_package_root(candidate):
|
|
238
|
+
return candidate.absolute()
|
|
239
|
+
nested = candidate / "pz"
|
|
240
|
+
if _is_runtime_package_root(nested):
|
|
241
|
+
return nested.absolute()
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _build_project_runtime_env(project_dir: Path, runtime_package_root: Path) -> dict[str, str]:
|
|
246
|
+
env = dict(os.environ)
|
|
247
|
+
existing_pythonpath = env.get("PYTHONPATH", "").strip()
|
|
248
|
+
pythonpath_entries = [entry for entry in existing_pythonpath.split(os.pathsep) if entry]
|
|
249
|
+
prepend_entries = [str(project_dir.resolve()), *[str(path) for path in _runtime_import_roots(runtime_package_root)]]
|
|
250
|
+
pythonpath_entries = [entry for entry in pythonpath_entries if entry not in prepend_entries]
|
|
251
|
+
env["PYTHONPATH"] = os.pathsep.join([*prepend_entries, *pythonpath_entries])
|
|
252
|
+
env["PZ_PROJECT_DIR"] = str(project_dir.resolve())
|
|
253
|
+
env["PYTHONNOUSERSITE"] = "1"
|
|
254
|
+
program_name = os.path.basename(str(sys.argv[0] or "")).strip().lower()
|
|
255
|
+
if program_name in {"pz", "pz"}:
|
|
256
|
+
env["PZ_PROGRAM_NAME"] = program_name
|
|
257
|
+
elif not env.get("PZ_PROGRAM_NAME"):
|
|
258
|
+
env["PZ_PROGRAM_NAME"] = "pz"
|
|
259
|
+
return env
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _runtime_import_roots(runtime_package_root: Path) -> tuple[Path, ...]:
|
|
263
|
+
roots: list[Path] = [runtime_package_root.parent.resolve()]
|
|
264
|
+
checkout_root = resolve_runtime_checkout_root(runtime_package_root)
|
|
265
|
+
contrib_root = resolve_contrib_source_root(checkout_root)
|
|
266
|
+
if contrib_root.is_dir():
|
|
267
|
+
for package_root in sorted(contrib_root.iterdir()):
|
|
268
|
+
if not package_root.is_dir():
|
|
269
|
+
continue
|
|
270
|
+
if not (package_root / "pyproject.toml").is_file():
|
|
271
|
+
continue
|
|
272
|
+
roots.append(package_root.resolve())
|
|
273
|
+
return tuple(roots)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _source_project_root(path: Path) -> Path | None:
|
|
277
|
+
absolute = path.expanduser().absolute()
|
|
278
|
+
for candidate in (absolute, *absolute.parents):
|
|
279
|
+
if candidate.name == ".sources" and candidate.parent.name == "apps":
|
|
280
|
+
return candidate.parent.parent.absolute()
|
|
281
|
+
return None
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _target_virtualenv_path(path: Path) -> Path:
|
|
285
|
+
absolute = path.expanduser().absolute()
|
|
286
|
+
project_root = _source_project_root(absolute)
|
|
287
|
+
if project_root is None:
|
|
288
|
+
return absolute.resolve() / ".venv"
|
|
289
|
+
try:
|
|
290
|
+
relative = absolute.relative_to(project_root)
|
|
291
|
+
except ValueError:
|
|
292
|
+
return absolute.resolve() / ".venv"
|
|
293
|
+
return project_root / ".runtime" / "source-venvs" / relative / ".venv"
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _resolve_project_python(project_dir: Path, *, runtime_package_root: Path | None = None) -> str:
|
|
297
|
+
candidates: list[Path] = [
|
|
298
|
+
project_dir / ".venv" / "bin" / "python",
|
|
299
|
+
project_dir / ".venv" / "Scripts" / "python.exe",
|
|
300
|
+
]
|
|
301
|
+
if runtime_package_root is not None:
|
|
302
|
+
runtime_roots = [runtime_package_root.parent.absolute(), runtime_package_root.absolute()]
|
|
303
|
+
for root in runtime_roots:
|
|
304
|
+
candidates.extend(
|
|
305
|
+
(
|
|
306
|
+
_target_virtualenv_path(root) / "bin" / "python",
|
|
307
|
+
_target_virtualenv_path(root) / "Scripts" / "python.exe",
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
for candidate in candidates:
|
|
311
|
+
if candidate.is_file():
|
|
312
|
+
return str(candidate.expanduser().absolute())
|
|
313
|
+
return sys.executable
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _resolve_venv_pz_command(venv_root: Path) -> Path | None:
|
|
317
|
+
candidates = (
|
|
318
|
+
venv_root / "bin" / "pz",
|
|
319
|
+
venv_root / "Scripts" / "pz.exe",
|
|
320
|
+
venv_root / "Scripts" / "pz",
|
|
321
|
+
)
|
|
322
|
+
for candidate in candidates:
|
|
323
|
+
if candidate.is_file():
|
|
324
|
+
return candidate.expanduser().absolute()
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _same_python_executable(left: str, right: str) -> bool:
|
|
329
|
+
try:
|
|
330
|
+
return os.path.abspath(os.path.expanduser(left)) == os.path.abspath(os.path.expanduser(right))
|
|
331
|
+
except Exception:
|
|
332
|
+
return left == right
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
__all__ = [
|
|
336
|
+
"build_project_pz_child_env",
|
|
337
|
+
"PROVIDER_LOCK_ENV_NAME",
|
|
338
|
+
"handoff_to_project_runtime",
|
|
339
|
+
"provider_resolution_locked",
|
|
340
|
+
"resolve_cli_project_dir",
|
|
341
|
+
"resolve_project_pz_executable",
|
|
342
|
+
"resolve_project_runtime_package_root",
|
|
343
|
+
"run_project_runtime_json_command",
|
|
344
|
+
]
|