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,253 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from functools import lru_cache
|
|
6
|
+
from importlib.resources import files
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path, PurePosixPath
|
|
9
|
+
from types import MappingProxyType
|
|
10
|
+
from typing import Literal, cast
|
|
11
|
+
|
|
12
|
+
from pz_core.runtime.errors import PzError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_SOURCES_DIR = ".sources"
|
|
16
|
+
_SOURCES_ROOT = Path("apps") / _SOURCES_DIR
|
|
17
|
+
_MANIFEST_PATH = _SOURCES_ROOT / "manifest.json"
|
|
18
|
+
OFFICIAL_CONTRIB_SOURCE_ROOT = "pz_contrib"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True, slots=True)
|
|
22
|
+
class OfficialDevSourceSpec:
|
|
23
|
+
name: str
|
|
24
|
+
remote_url: str
|
|
25
|
+
workspace_identifier: str
|
|
26
|
+
default_branch: str
|
|
27
|
+
runtime_id: str | None = None
|
|
28
|
+
declared_app: str | None = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
OFFICIAL_RUNTIME_SOURCE = OfficialDevSourceSpec(
|
|
32
|
+
name="pz",
|
|
33
|
+
remote_url="git@github.com:JiXiangTools/pyzza.git",
|
|
34
|
+
workspace_identifier="pz",
|
|
35
|
+
default_branch="develop",
|
|
36
|
+
runtime_id="pz",
|
|
37
|
+
)
|
|
38
|
+
OFFICIAL_SOURCE_ROOTS = (
|
|
39
|
+
OfficialDevSourceSpec(
|
|
40
|
+
name="pz_apps",
|
|
41
|
+
remote_url="git@github.com:JiXiangTools/pyzza_platform.git",
|
|
42
|
+
workspace_identifier="pz-apps-source-root",
|
|
43
|
+
default_branch="develop",
|
|
44
|
+
declared_app="pz_apps",
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
OFFICIAL_TRUTH_SOURCE_REPO_NAMES = (
|
|
48
|
+
OFFICIAL_RUNTIME_SOURCE.name,
|
|
49
|
+
*(item.name for item in OFFICIAL_SOURCE_ROOTS),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True, slots=True)
|
|
54
|
+
class OfficialSourceChild:
|
|
55
|
+
kind: Literal["project", "app"]
|
|
56
|
+
subpath: PurePosixPath
|
|
57
|
+
expected_app_id: str | None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass(frozen=True, slots=True)
|
|
61
|
+
class OfficialSourceRoot:
|
|
62
|
+
repo_key: str
|
|
63
|
+
source: str
|
|
64
|
+
kind: Literal["directory"]
|
|
65
|
+
bootstrap: bool
|
|
66
|
+
children: Mapping[str, OfficialSourceChild]
|
|
67
|
+
|
|
68
|
+
def __post_init__(self) -> None:
|
|
69
|
+
object.__setattr__(self, "children", MappingProxyType(dict(self.children)))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _catalog_invalid(path: str, reason: str) -> PzError:
|
|
73
|
+
return PzError(
|
|
74
|
+
code="PZ_DEV_OFFICIAL_SOURCE_CATALOG_INVALID",
|
|
75
|
+
message=f"{path}: {reason}",
|
|
76
|
+
stage="dev",
|
|
77
|
+
owner="pz_core.project_sources",
|
|
78
|
+
action="load_official_source_catalog",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _require_catalog_object(value: object, path: str) -> dict[str, object]:
|
|
83
|
+
if not isinstance(value, dict) or not all(isinstance(key, str) for key in value):
|
|
84
|
+
raise _catalog_invalid(path, "expected an object")
|
|
85
|
+
return cast(dict[str, object], value)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _require_exact_fields(
|
|
89
|
+
value: object,
|
|
90
|
+
path: str,
|
|
91
|
+
expected: frozenset[str],
|
|
92
|
+
) -> dict[str, object]:
|
|
93
|
+
payload = _require_catalog_object(value, path)
|
|
94
|
+
fields = set(payload)
|
|
95
|
+
if fields != expected:
|
|
96
|
+
missing = sorted(expected - fields)
|
|
97
|
+
unknown = sorted(fields - expected)
|
|
98
|
+
reason = (
|
|
99
|
+
f"missing field {missing[0]!r}"
|
|
100
|
+
if missing
|
|
101
|
+
else f"unknown field {unknown[0]!r}"
|
|
102
|
+
)
|
|
103
|
+
raise _catalog_invalid(path, reason)
|
|
104
|
+
return payload
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _parse_catalog_subpath(value: object, path: str) -> PurePosixPath:
|
|
108
|
+
if not isinstance(value, str) or not value or value != value.strip():
|
|
109
|
+
raise _catalog_invalid(path, "expected a normalized relative POSIX path")
|
|
110
|
+
subpath = PurePosixPath(value)
|
|
111
|
+
if (
|
|
112
|
+
subpath.is_absolute()
|
|
113
|
+
or ".." in subpath.parts
|
|
114
|
+
or subpath.as_posix() != value
|
|
115
|
+
):
|
|
116
|
+
raise _catalog_invalid(path, "expected a normalized relative POSIX path")
|
|
117
|
+
return subpath
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _parse_official_child(key: str, value: object, path: str) -> OfficialSourceChild:
|
|
121
|
+
payload = _require_exact_fields(
|
|
122
|
+
value,
|
|
123
|
+
path,
|
|
124
|
+
frozenset({"kind", "subpath", "expected_app_id"}),
|
|
125
|
+
)
|
|
126
|
+
kind = payload["kind"]
|
|
127
|
+
if kind not in {"project", "app"}:
|
|
128
|
+
raise _catalog_invalid(f"{path}.kind", "expected 'project' or 'app'")
|
|
129
|
+
expected_app_id = payload["expected_app_id"]
|
|
130
|
+
if kind == "project":
|
|
131
|
+
if expected_app_id is not None:
|
|
132
|
+
raise _catalog_invalid(
|
|
133
|
+
f"{path}.expected_app_id",
|
|
134
|
+
"project metadata cannot expose an app id",
|
|
135
|
+
)
|
|
136
|
+
elif expected_app_id != key.replace("-", "_"):
|
|
137
|
+
raise _catalog_invalid(
|
|
138
|
+
f"{path}.expected_app_id",
|
|
139
|
+
"app metadata must match the normalized child key",
|
|
140
|
+
)
|
|
141
|
+
subpath = _parse_catalog_subpath(payload["subpath"], f"{path}.subpath")
|
|
142
|
+
if kind == "app" and subpath == PurePosixPath("."):
|
|
143
|
+
raise _catalog_invalid(
|
|
144
|
+
f"{path}.subpath",
|
|
145
|
+
"app metadata must resolve below its source root",
|
|
146
|
+
)
|
|
147
|
+
return OfficialSourceChild(
|
|
148
|
+
kind=cast(Literal["project", "app"], kind),
|
|
149
|
+
subpath=subpath,
|
|
150
|
+
expected_app_id=cast(str | None, expected_app_id),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _parse_official_root(
|
|
155
|
+
repo_key: str,
|
|
156
|
+
value: object,
|
|
157
|
+
path: str,
|
|
158
|
+
) -> OfficialSourceRoot:
|
|
159
|
+
payload = _require_exact_fields(
|
|
160
|
+
value,
|
|
161
|
+
path,
|
|
162
|
+
frozenset({"source", "kind", "bootstrap", "children"}),
|
|
163
|
+
)
|
|
164
|
+
source = payload["source"]
|
|
165
|
+
if not isinstance(source, str) or not source.strip() or source != source.strip():
|
|
166
|
+
raise _catalog_invalid(f"{path}.source", "expected a normalized source URL")
|
|
167
|
+
if payload["kind"] != "directory":
|
|
168
|
+
raise _catalog_invalid(f"{path}.kind", "expected 'directory'")
|
|
169
|
+
bootstrap = payload["bootstrap"]
|
|
170
|
+
if type(bootstrap) is not bool:
|
|
171
|
+
raise _catalog_invalid(f"{path}.bootstrap", "expected a boolean")
|
|
172
|
+
raw_children = _require_catalog_object(payload["children"], f"{path}.children")
|
|
173
|
+
children = {
|
|
174
|
+
key: _parse_official_child(key, child, f"{path}.children.{key}")
|
|
175
|
+
for key, child in raw_children.items()
|
|
176
|
+
}
|
|
177
|
+
return OfficialSourceRoot(
|
|
178
|
+
repo_key=repo_key,
|
|
179
|
+
source=source,
|
|
180
|
+
kind="directory",
|
|
181
|
+
bootstrap=bootstrap,
|
|
182
|
+
children=children,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@lru_cache(maxsize=1)
|
|
187
|
+
def load_official_source_catalog() -> Mapping[str, OfficialSourceRoot]:
|
|
188
|
+
resource = files("pz_core.authoring").joinpath("official_sources.json")
|
|
189
|
+
try:
|
|
190
|
+
raw = json.loads(resource.read_text(encoding="utf-8"))
|
|
191
|
+
except (OSError, UnicodeError, json.JSONDecodeError) as exc:
|
|
192
|
+
raise _catalog_invalid("$", f"cannot read catalog JSON: {exc}") from exc
|
|
193
|
+
payload = _require_catalog_object(raw, "$")
|
|
194
|
+
if set(payload) != {"pz", "pz_apps"}:
|
|
195
|
+
raise _catalog_invalid("$", "expected exactly the pz and pz_apps roots")
|
|
196
|
+
catalog = {
|
|
197
|
+
key: _parse_official_root(key, value, f"$.{key}")
|
|
198
|
+
for key, value in payload.items()
|
|
199
|
+
}
|
|
200
|
+
if catalog["pz"].bootstrap is not True:
|
|
201
|
+
raise _catalog_invalid("$.pz.bootstrap", "pz must be the bootstrap root")
|
|
202
|
+
if catalog["pz_apps"].bootstrap is not False:
|
|
203
|
+
raise _catalog_invalid(
|
|
204
|
+
"$.pz_apps.bootstrap",
|
|
205
|
+
"pz_apps cannot be a bootstrap root",
|
|
206
|
+
)
|
|
207
|
+
return MappingProxyType(catalog)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def resolve_sources_root(project_dir: Path) -> Path:
|
|
211
|
+
return project_dir / _SOURCES_ROOT
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def resolve_sources_manifest_path(project_dir: Path) -> Path:
|
|
215
|
+
return project_dir / _MANIFEST_PATH
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def resolve_sources_repo_checkout_root(project_dir: Path, repo_key: str) -> Path:
|
|
219
|
+
return resolve_sources_root(project_dir) / repo_key
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def resolve_known_sources_roots(project_dir: Path) -> tuple[Path, ...]:
|
|
223
|
+
return (resolve_sources_root(project_dir),)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def resolve_runtime_checkout_root(runtime_package_root: Path) -> Path:
|
|
227
|
+
distribution_root = runtime_package_root.expanduser().resolve().parent
|
|
228
|
+
for candidate in (distribution_root, distribution_root.parent.resolve()):
|
|
229
|
+
if resolve_contrib_source_root(candidate).is_dir():
|
|
230
|
+
return candidate
|
|
231
|
+
return distribution_root
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def resolve_contrib_source_root(checkout_root: Path) -> Path:
|
|
235
|
+
return checkout_root.expanduser().resolve() / OFFICIAL_CONTRIB_SOURCE_ROOT
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
__all__ = [
|
|
239
|
+
"OFFICIAL_CONTRIB_SOURCE_ROOT",
|
|
240
|
+
"OFFICIAL_RUNTIME_SOURCE",
|
|
241
|
+
"OFFICIAL_SOURCE_ROOTS",
|
|
242
|
+
"OFFICIAL_TRUTH_SOURCE_REPO_NAMES",
|
|
243
|
+
"OfficialDevSourceSpec",
|
|
244
|
+
"OfficialSourceChild",
|
|
245
|
+
"OfficialSourceRoot",
|
|
246
|
+
"load_official_source_catalog",
|
|
247
|
+
"resolve_contrib_source_root",
|
|
248
|
+
"resolve_known_sources_roots",
|
|
249
|
+
"resolve_runtime_checkout_root",
|
|
250
|
+
"resolve_sources_manifest_path",
|
|
251
|
+
"resolve_sources_repo_checkout_root",
|
|
252
|
+
"resolve_sources_root",
|
|
253
|
+
]
|
pz_core/pz_launcher.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from pz_core.project_runtime_cli import (
|
|
10
|
+
PROVIDER_LOCK_ENV_NAME,
|
|
11
|
+
_build_project_runtime_env,
|
|
12
|
+
_target_virtualenv_path,
|
|
13
|
+
provider_resolution_locked,
|
|
14
|
+
resolve_cli_project_dir,
|
|
15
|
+
resolve_project_runtime_package_root,
|
|
16
|
+
)
|
|
17
|
+
from pz_core.runtime.environment_integrity import validate_current_environment
|
|
18
|
+
from pz_core.runtime.errors import PzError
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
22
|
+
try:
|
|
23
|
+
validate_current_environment(os.environ)
|
|
24
|
+
except PzError as exc:
|
|
25
|
+
sys.stderr.write(f"{exc}\n")
|
|
26
|
+
return 2
|
|
27
|
+
args = list(argv or sys.argv[1:])
|
|
28
|
+
if not provider_resolution_locked():
|
|
29
|
+
if handoff_to_preferred_pz_provider(args, current_package_root=Path(__file__).resolve().parent):
|
|
30
|
+
return 0
|
|
31
|
+
return _run_current_cli(args)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def handoff_to_preferred_pz_provider(
|
|
35
|
+
argv: Sequence[str] | None = None,
|
|
36
|
+
*,
|
|
37
|
+
current_package_root: Path,
|
|
38
|
+
) -> bool:
|
|
39
|
+
project_dir = resolve_cli_project_dir(argv)
|
|
40
|
+
if project_dir is None:
|
|
41
|
+
return False
|
|
42
|
+
if _handoff_to_project_venv(argv, project_dir=project_dir, current_package_root=current_package_root):
|
|
43
|
+
return True
|
|
44
|
+
if _handoff_to_project_source(argv, project_dir=project_dir, current_package_root=current_package_root):
|
|
45
|
+
return True
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _run_current_cli(argv: Sequence[str]) -> int:
|
|
50
|
+
try:
|
|
51
|
+
from pz_core.cli import main as cli_main
|
|
52
|
+
except Exception:
|
|
53
|
+
if not provider_resolution_locked() and _handoff_to_uv_tool(argv):
|
|
54
|
+
return 0
|
|
55
|
+
raise
|
|
56
|
+
return cli_main(list(argv))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _handoff_to_project_venv(
|
|
60
|
+
argv: Sequence[str] | None,
|
|
61
|
+
*,
|
|
62
|
+
project_dir: Path,
|
|
63
|
+
current_package_root: Path,
|
|
64
|
+
) -> bool:
|
|
65
|
+
venv_root = project_dir / ".venv"
|
|
66
|
+
if not venv_root.is_dir():
|
|
67
|
+
return False
|
|
68
|
+
venv_python = _resolve_venv_python(venv_root)
|
|
69
|
+
if venv_python is None:
|
|
70
|
+
return False
|
|
71
|
+
current_in_project_venv = _same_python_executable(str(venv_python), sys.executable) and any(
|
|
72
|
+
_path_is_relative_to(current_package_root, site_packages_root)
|
|
73
|
+
for site_packages_root in _site_packages_roots(venv_root)
|
|
74
|
+
)
|
|
75
|
+
if current_in_project_venv:
|
|
76
|
+
return False
|
|
77
|
+
env = dict(os.environ)
|
|
78
|
+
env[PROVIDER_LOCK_ENV_NAME] = "project-venv"
|
|
79
|
+
env["PZ_PROJECT_DIR"] = str(project_dir.resolve())
|
|
80
|
+
pz_command = _resolve_venv_pz_command(venv_root)
|
|
81
|
+
if pz_command is not None:
|
|
82
|
+
os.execvpe(str(pz_command), [str(pz_command), *list(argv or sys.argv[1:])], env)
|
|
83
|
+
return True
|
|
84
|
+
if not _venv_contains_pz(venv_root):
|
|
85
|
+
return False
|
|
86
|
+
os.execvpe(
|
|
87
|
+
str(venv_python),
|
|
88
|
+
[str(venv_python), "-m", "pz_core", *list(argv or sys.argv[1:])],
|
|
89
|
+
env,
|
|
90
|
+
)
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _handoff_to_project_source(
|
|
95
|
+
argv: Sequence[str] | None,
|
|
96
|
+
*,
|
|
97
|
+
project_dir: Path,
|
|
98
|
+
current_package_root: Path,
|
|
99
|
+
) -> bool:
|
|
100
|
+
runtime_package_root = resolve_project_runtime_package_root(project_dir)
|
|
101
|
+
if runtime_package_root is None:
|
|
102
|
+
return False
|
|
103
|
+
project_python = _resolve_source_python(runtime_package_root)
|
|
104
|
+
if runtime_package_root.resolve() == current_package_root.expanduser().resolve() and _same_python_executable(
|
|
105
|
+
project_python,
|
|
106
|
+
sys.executable,
|
|
107
|
+
):
|
|
108
|
+
return False
|
|
109
|
+
env = _build_project_runtime_env(project_dir, runtime_package_root)
|
|
110
|
+
env[PROVIDER_LOCK_ENV_NAME] = "project-source"
|
|
111
|
+
os.execvpe(
|
|
112
|
+
project_python,
|
|
113
|
+
[project_python, "-m", "pz_core", *list(argv or sys.argv[1:])],
|
|
114
|
+
env,
|
|
115
|
+
)
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _handoff_to_uv_tool(argv: Sequence[str]) -> bool:
|
|
120
|
+
uv_binary = shutil.which("uv")
|
|
121
|
+
if not uv_binary:
|
|
122
|
+
return False
|
|
123
|
+
env = dict(os.environ)
|
|
124
|
+
env[PROVIDER_LOCK_ENV_NAME] = "uv-tool"
|
|
125
|
+
os.execvpe(
|
|
126
|
+
uv_binary,
|
|
127
|
+
[uv_binary, "tool", "run", "--from", "pz-cli", "pz", *list(argv)],
|
|
128
|
+
env,
|
|
129
|
+
)
|
|
130
|
+
return True
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _resolve_venv_pz_command(venv_root: Path) -> Path | None:
|
|
134
|
+
candidates = (
|
|
135
|
+
venv_root / "bin" / "pz",
|
|
136
|
+
venv_root / "Scripts" / "pz.exe",
|
|
137
|
+
venv_root / "Scripts" / "pz",
|
|
138
|
+
)
|
|
139
|
+
for candidate in candidates:
|
|
140
|
+
if candidate.is_file():
|
|
141
|
+
return candidate.absolute()
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _resolve_venv_python(venv_root: Path) -> Path | None:
|
|
146
|
+
candidates = (
|
|
147
|
+
venv_root / "bin" / "python",
|
|
148
|
+
venv_root / "Scripts" / "python.exe",
|
|
149
|
+
)
|
|
150
|
+
for candidate in candidates:
|
|
151
|
+
if candidate.is_file():
|
|
152
|
+
return candidate.absolute()
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _site_packages_roots(venv_root: Path) -> tuple[Path, ...]:
|
|
157
|
+
roots: list[Path] = []
|
|
158
|
+
lib_root = venv_root / "lib"
|
|
159
|
+
if lib_root.is_dir():
|
|
160
|
+
for candidate in sorted(lib_root.glob("python*/site-packages")):
|
|
161
|
+
if candidate.is_dir():
|
|
162
|
+
roots.append(candidate.resolve())
|
|
163
|
+
windows_root = venv_root / "Lib" / "site-packages"
|
|
164
|
+
if windows_root.is_dir():
|
|
165
|
+
roots.append(windows_root.resolve())
|
|
166
|
+
return tuple(roots)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _venv_contains_pz(venv_root: Path) -> bool:
|
|
170
|
+
for site_packages_root in _site_packages_roots(venv_root):
|
|
171
|
+
if (site_packages_root / "pz" / "__init__.py").is_file():
|
|
172
|
+
return True
|
|
173
|
+
if any(site_packages_root.glob("pz-*.dist-info")):
|
|
174
|
+
return True
|
|
175
|
+
if any(site_packages_root.glob("__editable__.pz*.pth")):
|
|
176
|
+
return True
|
|
177
|
+
if any(site_packages_root.glob("__editable___pz*.py")):
|
|
178
|
+
return True
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _path_is_relative_to(path: Path, parent: Path) -> bool:
|
|
183
|
+
try:
|
|
184
|
+
path.expanduser().resolve().relative_to(parent.expanduser().resolve())
|
|
185
|
+
return True
|
|
186
|
+
except ValueError:
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _resolve_source_python(runtime_package_root: Path) -> str:
|
|
191
|
+
for source_root in (runtime_package_root.parent.absolute(), runtime_package_root.absolute()):
|
|
192
|
+
source_venv = _target_virtualenv_path(source_root)
|
|
193
|
+
source_python = source_venv / "bin" / "python"
|
|
194
|
+
if source_python.is_file():
|
|
195
|
+
return str(source_python.absolute())
|
|
196
|
+
source_python_windows = source_venv / "Scripts" / "python.exe"
|
|
197
|
+
if source_python_windows.is_file():
|
|
198
|
+
return str(source_python_windows.absolute())
|
|
199
|
+
return sys.executable
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _same_python_executable(left: str, right: str) -> bool:
|
|
203
|
+
try:
|
|
204
|
+
return os.path.abspath(os.path.expanduser(left)) == os.path.abspath(os.path.expanduser(right))
|
|
205
|
+
except Exception:
|
|
206
|
+
return left == right
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
__all__ = ["handoff_to_preferred_pz_provider", "main"]
|
pz_core/root_cli.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from importlib.metadata import entry_points
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
ROOT_CLI_PROVIDER_GROUP = "pz.root_cli"
|
|
9
|
+
CommandPath = tuple[str, ...]
|
|
10
|
+
RootCommandCallable = Callable[[Sequence[str]], int]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class RootCommandHandler:
|
|
15
|
+
command_path: CommandPath
|
|
16
|
+
handler: RootCommandCallable
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def normalize_command_path(parts: Sequence[str]) -> CommandPath:
|
|
20
|
+
normalized = tuple(str(part).strip().lower() for part in parts if str(part).strip())
|
|
21
|
+
if not normalized:
|
|
22
|
+
raise ValueError("root CLI command path must not be empty")
|
|
23
|
+
return normalized
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def coerce_root_command_handlers(payload: object) -> tuple[RootCommandHandler, ...]:
|
|
27
|
+
if isinstance(payload, RootCommandHandler):
|
|
28
|
+
handlers = (payload,)
|
|
29
|
+
elif isinstance(payload, Iterable) and not isinstance(payload, (str, bytes)):
|
|
30
|
+
handlers = tuple(payload)
|
|
31
|
+
else:
|
|
32
|
+
raise TypeError("root CLI provider must return RootCommandHandler or iterable[RootCommandHandler]")
|
|
33
|
+
if not handlers:
|
|
34
|
+
raise ValueError("root CLI provider returned no handlers")
|
|
35
|
+
normalized_handlers: list[RootCommandHandler] = []
|
|
36
|
+
for item in handlers:
|
|
37
|
+
if not isinstance(item, RootCommandHandler):
|
|
38
|
+
raise TypeError("root CLI provider returned a non-RootCommandHandler item")
|
|
39
|
+
normalized_handlers.append(
|
|
40
|
+
RootCommandHandler(command_path=normalize_command_path(item.command_path), handler=item.handler)
|
|
41
|
+
)
|
|
42
|
+
return tuple(normalized_handlers)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def discover_root_command_handlers() -> dict[CommandPath, RootCommandHandler]:
|
|
46
|
+
discovered: dict[CommandPath, RootCommandHandler] = {}
|
|
47
|
+
for registered in entry_points(group=ROOT_CLI_PROVIDER_GROUP):
|
|
48
|
+
provider = registered.load()
|
|
49
|
+
handlers = coerce_root_command_handlers(provider())
|
|
50
|
+
for handler in handlers:
|
|
51
|
+
existing = discovered.get(handler.command_path)
|
|
52
|
+
if existing is not None:
|
|
53
|
+
command_text = " ".join(handler.command_path)
|
|
54
|
+
raise RuntimeError(
|
|
55
|
+
f"Duplicate root CLI provider for `{command_text}`: "
|
|
56
|
+
f"`{registered.value}` conflicts with an already-registered provider."
|
|
57
|
+
)
|
|
58
|
+
discovered[handler.command_path] = handler
|
|
59
|
+
return discovered
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
__all__ = [
|
|
63
|
+
"CommandPath",
|
|
64
|
+
"ROOT_CLI_PROVIDER_GROUP",
|
|
65
|
+
"RootCommandCallable",
|
|
66
|
+
"RootCommandHandler",
|
|
67
|
+
"coerce_root_command_handlers",
|
|
68
|
+
"discover_root_command_handlers",
|
|
69
|
+
"normalize_command_path",
|
|
70
|
+
]
|