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,843 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable, Mapping
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from itertools import product
|
|
6
|
+
import inspect
|
|
7
|
+
from typing import Any, Callable, get_type_hints
|
|
8
|
+
|
|
9
|
+
from fastapi import APIRouter
|
|
10
|
+
|
|
11
|
+
from .exports import IncludedUrls, create_lazy_mount_router
|
|
12
|
+
from .loaders import DeclaredUrlSpec
|
|
13
|
+
from .utils import _join_path_prefix
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
RoutePathProjectionProvider = Callable[[Any], Iterable[Mapping[str, Any]]]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True, slots=True)
|
|
20
|
+
class RuntimeRouteBinding:
|
|
21
|
+
path: str | Callable[[Any], str]
|
|
22
|
+
handler_attr: str
|
|
23
|
+
methods: tuple[str, ...] = ("GET",)
|
|
24
|
+
response_class: object | None = None
|
|
25
|
+
name: str | None = None
|
|
26
|
+
include_in_schema: bool = True
|
|
27
|
+
enabled_when: str | None = None
|
|
28
|
+
enumerate_params: tuple[tuple[str, Any], ...] | dict[str, Any] = ()
|
|
29
|
+
path_projections: RoutePathProjectionProvider | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True, slots=True)
|
|
33
|
+
class DeclaredEndpointBinding:
|
|
34
|
+
path: str
|
|
35
|
+
endpoint: Callable[..., Any]
|
|
36
|
+
methods: tuple[str, ...] = ("GET",)
|
|
37
|
+
response_class: object | None = None
|
|
38
|
+
name: str | None = None
|
|
39
|
+
include_in_schema: bool = True
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(frozen=True, slots=True)
|
|
43
|
+
class LazyMountUrlBinding:
|
|
44
|
+
namespace: str
|
|
45
|
+
path: str
|
|
46
|
+
app_factory: Callable[[], Any]
|
|
47
|
+
name: str | None = None
|
|
48
|
+
dependencies: tuple[object, ...] = ()
|
|
49
|
+
replace_target: str = ""
|
|
50
|
+
route_hints: tuple[str, ...] = ()
|
|
51
|
+
conflict_policy: str = "fail"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(frozen=True, slots=True)
|
|
55
|
+
class UrlPathPattern:
|
|
56
|
+
path: str
|
|
57
|
+
view: Callable[..., Any]
|
|
58
|
+
methods: tuple[str, ...] = ("GET",)
|
|
59
|
+
response_class: object | None = None
|
|
60
|
+
name: str | None = None
|
|
61
|
+
include_in_schema: bool = True
|
|
62
|
+
enabled_when: str | Callable[..., object] | None = None
|
|
63
|
+
dependencies: tuple[object, ...] = ()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True, slots=True)
|
|
67
|
+
class MountedUrlPattern:
|
|
68
|
+
path: str
|
|
69
|
+
app: Callable[[], Any]
|
|
70
|
+
namespace: str
|
|
71
|
+
name: str | None = None
|
|
72
|
+
dependencies: tuple[object, ...] = ()
|
|
73
|
+
replace_target: str = ""
|
|
74
|
+
route_hints: tuple[str, ...] = ()
|
|
75
|
+
conflict_policy: str = "fail"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def path(
|
|
79
|
+
path_value: str,
|
|
80
|
+
view: Callable[..., Any] | IncludedUrls,
|
|
81
|
+
*,
|
|
82
|
+
methods: tuple[str, ...] = ("GET",),
|
|
83
|
+
response_class: object | None = None,
|
|
84
|
+
name: str | None = None,
|
|
85
|
+
include_in_schema: bool = True,
|
|
86
|
+
enabled_when: str | Callable[..., object] | None = None,
|
|
87
|
+
dependencies: tuple[object, ...] = (),
|
|
88
|
+
) -> UrlPathPattern | IncludedUrls:
|
|
89
|
+
if isinstance(view, IncludedUrls):
|
|
90
|
+
normalized_path_value = str(path_value or "").strip()
|
|
91
|
+
if normalized_path_value == "/":
|
|
92
|
+
normalized_path_value = ""
|
|
93
|
+
if normalized_path_value:
|
|
94
|
+
return IncludedUrls(
|
|
95
|
+
module_name=view.module_name,
|
|
96
|
+
path_prefix=normalized_path_value,
|
|
97
|
+
namespace=view.namespace,
|
|
98
|
+
)
|
|
99
|
+
return view
|
|
100
|
+
if not callable(view):
|
|
101
|
+
raise RuntimeError("path(...) requires a callable view function; string handler names are no longer supported.")
|
|
102
|
+
return UrlPathPattern(
|
|
103
|
+
path=str(path_value),
|
|
104
|
+
view=view,
|
|
105
|
+
methods=tuple(methods or ("GET",)),
|
|
106
|
+
response_class=response_class,
|
|
107
|
+
name=name,
|
|
108
|
+
include_in_schema=bool(include_in_schema),
|
|
109
|
+
enabled_when=enabled_when if callable(enabled_when) else (str(enabled_when or "").strip() or None),
|
|
110
|
+
dependencies=tuple(dependencies or ()),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def mount(
|
|
115
|
+
path_value: str,
|
|
116
|
+
*,
|
|
117
|
+
app: Callable[[], Any],
|
|
118
|
+
namespace: str,
|
|
119
|
+
name: str | None = None,
|
|
120
|
+
dependencies: tuple[object, ...] = (),
|
|
121
|
+
replace_target: str = "",
|
|
122
|
+
route_hints: tuple[str, ...] = (),
|
|
123
|
+
conflict_policy: str = "fail",
|
|
124
|
+
) -> MountedUrlPattern:
|
|
125
|
+
return MountedUrlPattern(
|
|
126
|
+
path=str(path_value),
|
|
127
|
+
app=app,
|
|
128
|
+
namespace=str(namespace),
|
|
129
|
+
name=name,
|
|
130
|
+
dependencies=tuple(dependencies or ()),
|
|
131
|
+
replace_target=str(replace_target or ""),
|
|
132
|
+
route_hints=tuple(route_hints or ()),
|
|
133
|
+
conflict_policy=str(conflict_policy or "fail"),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def create_runtime_route_bindings(
|
|
138
|
+
definitions: tuple[RuntimeRouteBinding | dict[str, Any], ...] | list[RuntimeRouteBinding | dict[str, Any]],
|
|
139
|
+
) -> tuple[RuntimeRouteBinding, ...]:
|
|
140
|
+
bindings: list[RuntimeRouteBinding] = []
|
|
141
|
+
for item in definitions:
|
|
142
|
+
if isinstance(item, RuntimeRouteBinding):
|
|
143
|
+
bindings.append(item)
|
|
144
|
+
continue
|
|
145
|
+
bindings.append(RuntimeRouteBinding(**dict(item)))
|
|
146
|
+
return tuple(bindings)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def create_lazy_mount_url_bindings(
|
|
150
|
+
definitions: tuple[LazyMountUrlBinding | dict[str, Any], ...] | list[LazyMountUrlBinding | dict[str, Any]],
|
|
151
|
+
) -> tuple[LazyMountUrlBinding, ...]:
|
|
152
|
+
bindings: list[LazyMountUrlBinding] = []
|
|
153
|
+
for item in definitions:
|
|
154
|
+
if isinstance(item, LazyMountUrlBinding):
|
|
155
|
+
bindings.append(item)
|
|
156
|
+
continue
|
|
157
|
+
bindings.append(LazyMountUrlBinding(**dict(item)))
|
|
158
|
+
return tuple(bindings)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _resolve_binding_path(binding: RuntimeRouteBinding, runtime: Any) -> str:
|
|
162
|
+
if callable(binding.path):
|
|
163
|
+
path = binding.path(runtime)
|
|
164
|
+
else:
|
|
165
|
+
path = binding.path
|
|
166
|
+
return str(path)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _resolve_binding_endpoint(binding: RuntimeRouteBinding, runtime: Any) -> Any:
|
|
170
|
+
handlers = getattr(runtime, "handlers", None)
|
|
171
|
+
if handlers is None or not hasattr(handlers, binding.handler_attr):
|
|
172
|
+
raise RuntimeError(f"runtime.handlers must expose {binding.handler_attr!r}.")
|
|
173
|
+
return getattr(handlers, binding.handler_attr)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _parse_template_path_param(segment: str) -> tuple[str, str] | None:
|
|
177
|
+
if not segment.startswith("{") or not segment.endswith("}"):
|
|
178
|
+
return None
|
|
179
|
+
body = segment[1:-1].strip()
|
|
180
|
+
if not body:
|
|
181
|
+
return None
|
|
182
|
+
if ":" in body:
|
|
183
|
+
name, convertor = body.split(":", 1)
|
|
184
|
+
else:
|
|
185
|
+
name, convertor = body, ""
|
|
186
|
+
name = name.strip()
|
|
187
|
+
if not name:
|
|
188
|
+
return None
|
|
189
|
+
return name, convertor.strip()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _path_param_names(path_value: str) -> tuple[str, ...]:
|
|
193
|
+
names: list[str] = []
|
|
194
|
+
for segment in (item for item in str(path_value or "").strip("/").split("/") if item):
|
|
195
|
+
parsed = _parse_template_path_param(segment)
|
|
196
|
+
if parsed is not None:
|
|
197
|
+
names.append(parsed[0])
|
|
198
|
+
return tuple(names)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _iter_enumerate_param_specs(binding: RuntimeRouteBinding) -> tuple[tuple[str, Any], ...]:
|
|
202
|
+
raw = binding.enumerate_params
|
|
203
|
+
if isinstance(raw, dict):
|
|
204
|
+
return tuple((str(name), values) for name, values in raw.items())
|
|
205
|
+
return tuple((str(name), values) for name, values in tuple(raw or ()))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _resolve_enumerated_param_values(name: str, values: Any, runtime: Any) -> tuple[str, ...]:
|
|
209
|
+
raw_values = values(runtime) if callable(values) else values
|
|
210
|
+
if isinstance(raw_values, str):
|
|
211
|
+
raw_values = (raw_values,)
|
|
212
|
+
normalized: list[str] = []
|
|
213
|
+
seen: set[str] = set()
|
|
214
|
+
for item in tuple(raw_values or ()):
|
|
215
|
+
value = str(item or "").strip()
|
|
216
|
+
if not value or value in seen:
|
|
217
|
+
continue
|
|
218
|
+
if "/" in value or "{" in value or "}" in value:
|
|
219
|
+
raise RuntimeError(f"enumerated route param {name!r} contains an invalid path segment {value!r}.")
|
|
220
|
+
seen.add(value)
|
|
221
|
+
normalized.append(value)
|
|
222
|
+
if not normalized:
|
|
223
|
+
raise RuntimeError(f"enumerated route param {name!r} requires at least one value.")
|
|
224
|
+
return tuple(normalized)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _normalize_path_projection_path(path_value: Any, *, index: int) -> str:
|
|
228
|
+
path_text = str(path_value or "").strip()
|
|
229
|
+
if not path_text:
|
|
230
|
+
raise RuntimeError(f"runtime route path projection #{index} requires a non-empty path.")
|
|
231
|
+
if not path_text.startswith("/"):
|
|
232
|
+
raise RuntimeError(f"runtime route path projection #{index} path must start with '/': {path_text!r}.")
|
|
233
|
+
stripped = path_text.strip("/")
|
|
234
|
+
if not stripped:
|
|
235
|
+
return path_text
|
|
236
|
+
for segment in stripped.split("/"):
|
|
237
|
+
if not segment:
|
|
238
|
+
raise RuntimeError(
|
|
239
|
+
f"runtime route path projection #{index} contains an empty path segment: {path_text!r}."
|
|
240
|
+
)
|
|
241
|
+
parsed = _parse_template_path_param(segment)
|
|
242
|
+
if ("{" in segment or "}" in segment) and parsed is None:
|
|
243
|
+
raise RuntimeError(
|
|
244
|
+
f"runtime route path projection #{index} contains an invalid path parameter segment {segment!r}."
|
|
245
|
+
)
|
|
246
|
+
return path_text
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _normalize_path_projection_constants(constants_value: Any, *, index: int) -> dict[str, Any]:
|
|
250
|
+
if not isinstance(constants_value, Mapping):
|
|
251
|
+
raise RuntimeError(f"runtime route path projection #{index} constants must be a mapping.")
|
|
252
|
+
constants: dict[str, Any] = {}
|
|
253
|
+
for raw_name, value in constants_value.items():
|
|
254
|
+
name = str(raw_name or "").strip()
|
|
255
|
+
if not name:
|
|
256
|
+
raise RuntimeError(f"runtime route path projection #{index} constants must declare non-empty names.")
|
|
257
|
+
if name in constants:
|
|
258
|
+
raise RuntimeError(f"runtime route path projection #{index} declares duplicate constant {name!r}.")
|
|
259
|
+
constants[name] = value
|
|
260
|
+
return constants
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _iter_path_projection_specs(
|
|
264
|
+
*,
|
|
265
|
+
binding: RuntimeRouteBinding,
|
|
266
|
+
runtime: Any,
|
|
267
|
+
path_value: str,
|
|
268
|
+
) -> tuple[tuple[str, dict[str, Any]], ...]:
|
|
269
|
+
provider = binding.path_projections
|
|
270
|
+
if provider is None:
|
|
271
|
+
return ((str(path_value), {}),)
|
|
272
|
+
if not callable(provider):
|
|
273
|
+
raise RuntimeError("RuntimeRouteBinding.path_projections must be callable.")
|
|
274
|
+
|
|
275
|
+
raw_projections = provider(runtime)
|
|
276
|
+
if raw_projections is None:
|
|
277
|
+
raw_items: tuple[Any, ...] = ()
|
|
278
|
+
elif isinstance(raw_projections, Mapping):
|
|
279
|
+
raise RuntimeError("RuntimeRouteBinding.path_projections must return an iterable of projection mappings.")
|
|
280
|
+
else:
|
|
281
|
+
try:
|
|
282
|
+
raw_items = tuple(raw_projections)
|
|
283
|
+
except TypeError as exc:
|
|
284
|
+
raise RuntimeError(
|
|
285
|
+
"RuntimeRouteBinding.path_projections must return an iterable of projection mappings."
|
|
286
|
+
) from exc
|
|
287
|
+
|
|
288
|
+
projections: list[tuple[str, dict[str, Any]]] = []
|
|
289
|
+
for index, projection in enumerate(raw_items, start=1):
|
|
290
|
+
if not isinstance(projection, Mapping):
|
|
291
|
+
raise RuntimeError(f"runtime route path projection #{index} must be a mapping.")
|
|
292
|
+
if "path" not in projection:
|
|
293
|
+
raise RuntimeError(f"runtime route path projection #{index} must declare a path.")
|
|
294
|
+
if "constants" not in projection:
|
|
295
|
+
raise RuntimeError(f"runtime route path projection #{index} must declare constants.")
|
|
296
|
+
|
|
297
|
+
projected_path = _normalize_path_projection_path(projection["path"], index=index)
|
|
298
|
+
constants = _normalize_path_projection_constants(projection["constants"], index=index)
|
|
299
|
+
path_constant_names = set(_path_param_names(projected_path)).intersection(constants)
|
|
300
|
+
if path_constant_names:
|
|
301
|
+
formatted_names = ", ".join(sorted(path_constant_names))
|
|
302
|
+
raise RuntimeError(
|
|
303
|
+
"runtime route path projection constants must not overlap dynamic path params: "
|
|
304
|
+
f"{formatted_names}."
|
|
305
|
+
)
|
|
306
|
+
projections.append((projected_path, constants))
|
|
307
|
+
|
|
308
|
+
if not projections:
|
|
309
|
+
raise RuntimeError("RuntimeRouteBinding.path_projections requires at least one projection.")
|
|
310
|
+
return tuple(projections)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _materialize_enumerated_path(path_value: str, constants: dict[str, str]) -> str:
|
|
314
|
+
path_text = str(path_value or "")
|
|
315
|
+
if path_text == "/":
|
|
316
|
+
return "/"
|
|
317
|
+
trailing_slash = path_text.endswith("/")
|
|
318
|
+
segments: list[str] = []
|
|
319
|
+
for segment in (item for item in path_text.strip("/").split("/") if item):
|
|
320
|
+
parsed = _parse_template_path_param(segment)
|
|
321
|
+
if parsed is not None and parsed[0] in constants:
|
|
322
|
+
segments.append(constants[parsed[0]])
|
|
323
|
+
continue
|
|
324
|
+
segments.append(segment)
|
|
325
|
+
materialized = "/" + "/".join(segments)
|
|
326
|
+
if trailing_slash and materialized != "/":
|
|
327
|
+
materialized += "/"
|
|
328
|
+
return materialized
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _bind_enumerated_endpoint(endpoint: Any, constants: Mapping[str, Any]) -> Any:
|
|
332
|
+
if not constants:
|
|
333
|
+
return endpoint
|
|
334
|
+
|
|
335
|
+
async def _endpoint(**kwargs):
|
|
336
|
+
call_kwargs = dict(kwargs)
|
|
337
|
+
call_kwargs.update(constants)
|
|
338
|
+
result = endpoint(**call_kwargs)
|
|
339
|
+
if inspect.isawaitable(result):
|
|
340
|
+
return await result
|
|
341
|
+
return result
|
|
342
|
+
|
|
343
|
+
_endpoint.__name__ = str(getattr(endpoint, "__name__", "_runtime_route_endpoint") or "_runtime_route_endpoint")
|
|
344
|
+
_endpoint.__module__ = str(getattr(endpoint, "__module__", __name__) or __name__)
|
|
345
|
+
try:
|
|
346
|
+
signature = inspect.signature(endpoint)
|
|
347
|
+
try:
|
|
348
|
+
type_hints = get_type_hints(endpoint)
|
|
349
|
+
except Exception:
|
|
350
|
+
type_hints = {}
|
|
351
|
+
parameters = [
|
|
352
|
+
parameter.replace(annotation=type_hints.get(parameter.name, parameter.annotation))
|
|
353
|
+
for parameter in signature.parameters.values()
|
|
354
|
+
if parameter.name not in constants
|
|
355
|
+
]
|
|
356
|
+
_endpoint.__signature__ = signature.replace(
|
|
357
|
+
parameters=parameters,
|
|
358
|
+
return_annotation=type_hints.get("return", signature.return_annotation),
|
|
359
|
+
)
|
|
360
|
+
except (TypeError, ValueError):
|
|
361
|
+
pass
|
|
362
|
+
return _endpoint
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _iter_materialized_projected_runtime_bindings(
|
|
366
|
+
*,
|
|
367
|
+
path_value: str,
|
|
368
|
+
endpoint: Any,
|
|
369
|
+
binding: RuntimeRouteBinding,
|
|
370
|
+
runtime: Any,
|
|
371
|
+
projection_constants: Mapping[str, Any],
|
|
372
|
+
) -> tuple[tuple[str, Any], ...]:
|
|
373
|
+
enum_specs = _iter_enumerate_param_specs(binding)
|
|
374
|
+
if not enum_specs:
|
|
375
|
+
return ((str(path_value), _bind_enumerated_endpoint(endpoint, projection_constants)),)
|
|
376
|
+
|
|
377
|
+
path_param_names = set(_path_param_names(path_value))
|
|
378
|
+
resolved_specs: list[tuple[str, tuple[str, ...]]] = []
|
|
379
|
+
for name, values in enum_specs:
|
|
380
|
+
if not name:
|
|
381
|
+
raise RuntimeError("enumerated route params must declare non-empty names.")
|
|
382
|
+
if name not in path_param_names:
|
|
383
|
+
raise RuntimeError(f"enumerated route param {name!r} is not present in route path {path_value!r}.")
|
|
384
|
+
resolved_specs.append((name, _resolve_enumerated_param_values(name, values, runtime)))
|
|
385
|
+
|
|
386
|
+
materialized: list[tuple[str, Any]] = []
|
|
387
|
+
names = tuple(name for name, _values in resolved_specs)
|
|
388
|
+
value_sets = tuple(values for _name, values in resolved_specs)
|
|
389
|
+
for values in product(*value_sets):
|
|
390
|
+
enumerated_constants = dict(zip(names, values, strict=True))
|
|
391
|
+
duplicated_names = set(projection_constants).intersection(enumerated_constants)
|
|
392
|
+
if duplicated_names:
|
|
393
|
+
formatted_names = ", ".join(sorted(duplicated_names))
|
|
394
|
+
raise RuntimeError(f"runtime route constants are declared more than once: {formatted_names}.")
|
|
395
|
+
constants = dict(projection_constants)
|
|
396
|
+
constants.update(enumerated_constants)
|
|
397
|
+
materialized.append(
|
|
398
|
+
(
|
|
399
|
+
_materialize_enumerated_path(path_value, enumerated_constants),
|
|
400
|
+
_bind_enumerated_endpoint(endpoint, constants),
|
|
401
|
+
)
|
|
402
|
+
)
|
|
403
|
+
return tuple(materialized)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _iter_materialized_runtime_bindings(
|
|
407
|
+
*,
|
|
408
|
+
path_value: str,
|
|
409
|
+
endpoint: Any,
|
|
410
|
+
binding: RuntimeRouteBinding,
|
|
411
|
+
runtime: Any,
|
|
412
|
+
) -> tuple[tuple[str, Any], ...]:
|
|
413
|
+
materialized: list[tuple[str, Any]] = []
|
|
414
|
+
seen_paths: set[str] = set()
|
|
415
|
+
for projected_path, projection_constants in _iter_path_projection_specs(
|
|
416
|
+
binding=binding,
|
|
417
|
+
runtime=runtime,
|
|
418
|
+
path_value=path_value,
|
|
419
|
+
):
|
|
420
|
+
for materialized_path, materialized_endpoint in _iter_materialized_projected_runtime_bindings(
|
|
421
|
+
path_value=projected_path,
|
|
422
|
+
endpoint=endpoint,
|
|
423
|
+
binding=binding,
|
|
424
|
+
runtime=runtime,
|
|
425
|
+
projection_constants=projection_constants,
|
|
426
|
+
):
|
|
427
|
+
if materialized_path in seen_paths:
|
|
428
|
+
raise RuntimeError(f"runtime route path projection produced duplicate path {materialized_path!r}.")
|
|
429
|
+
seen_paths.add(materialized_path)
|
|
430
|
+
materialized.append((materialized_path, materialized_endpoint))
|
|
431
|
+
return tuple(materialized)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _resolve_pattern_path(pattern: UrlPathPattern, runtime: Any | None) -> str:
|
|
435
|
+
return str(pattern.path)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def _resolve_pattern_endpoint(pattern: UrlPathPattern, runtime: Any | None) -> Any:
|
|
439
|
+
if runtime is not None:
|
|
440
|
+
handlers = getattr(runtime, "handlers", None)
|
|
441
|
+
handler_name = str(getattr(pattern.view, "__name__", "") or "").strip()
|
|
442
|
+
if handlers is not None and handler_name and hasattr(handlers, handler_name):
|
|
443
|
+
return getattr(handlers, handler_name)
|
|
444
|
+
return pattern.view
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def _resolve_enabled_when(enabled_when: str | Callable[..., object] | None, runtime: Any | None) -> bool:
|
|
448
|
+
if enabled_when is None:
|
|
449
|
+
return True
|
|
450
|
+
if callable(enabled_when):
|
|
451
|
+
try:
|
|
452
|
+
return bool(enabled_when(runtime))
|
|
453
|
+
except TypeError:
|
|
454
|
+
return bool(enabled_when())
|
|
455
|
+
return bool(getattr(runtime, enabled_when, False))
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _binding_route_kwargs(
|
|
459
|
+
*,
|
|
460
|
+
methods: tuple[str, ...],
|
|
461
|
+
response_class: object | None,
|
|
462
|
+
name: str | None,
|
|
463
|
+
include_in_schema: bool,
|
|
464
|
+
dependencies: tuple[object, ...] = (),
|
|
465
|
+
) -> dict[str, Any]:
|
|
466
|
+
kwargs: dict[str, Any] = {
|
|
467
|
+
"methods": list(methods),
|
|
468
|
+
"name": name,
|
|
469
|
+
"include_in_schema": include_in_schema,
|
|
470
|
+
}
|
|
471
|
+
if dependencies:
|
|
472
|
+
kwargs["dependencies"] = list(dependencies)
|
|
473
|
+
if response_class is not None:
|
|
474
|
+
kwargs["response_class"] = response_class
|
|
475
|
+
return kwargs
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def build_runtime_router(
|
|
479
|
+
*,
|
|
480
|
+
runtime_factory: Callable[[], Any | None],
|
|
481
|
+
bindings: tuple[RuntimeRouteBinding, ...],
|
|
482
|
+
) -> APIRouter:
|
|
483
|
+
router = APIRouter()
|
|
484
|
+
runtime = runtime_factory()
|
|
485
|
+
if runtime is None:
|
|
486
|
+
return router
|
|
487
|
+
for binding in bindings:
|
|
488
|
+
if binding.enabled_when and not bool(getattr(runtime, binding.enabled_when, False)):
|
|
489
|
+
continue
|
|
490
|
+
path_value = _resolve_binding_path(binding, runtime)
|
|
491
|
+
endpoint = _resolve_binding_endpoint(binding, runtime)
|
|
492
|
+
for materialized_path, materialized_endpoint in _iter_materialized_runtime_bindings(
|
|
493
|
+
path_value=path_value,
|
|
494
|
+
endpoint=endpoint,
|
|
495
|
+
binding=binding,
|
|
496
|
+
runtime=runtime,
|
|
497
|
+
):
|
|
498
|
+
router.add_api_route(
|
|
499
|
+
materialized_path,
|
|
500
|
+
materialized_endpoint,
|
|
501
|
+
**_binding_route_kwargs(
|
|
502
|
+
methods=binding.methods,
|
|
503
|
+
response_class=binding.response_class,
|
|
504
|
+
name=binding.name,
|
|
505
|
+
include_in_schema=binding.include_in_schema,
|
|
506
|
+
),
|
|
507
|
+
)
|
|
508
|
+
return router
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def build_router_from_urlpatterns(
|
|
512
|
+
*,
|
|
513
|
+
urlpatterns: tuple[UrlPathPattern | IncludedUrls | MountedUrlPattern, ...],
|
|
514
|
+
runtime_factory: Callable[[], Any | None] | None = None,
|
|
515
|
+
) -> APIRouter:
|
|
516
|
+
router = APIRouter()
|
|
517
|
+
runtime_required = any(
|
|
518
|
+
isinstance(item, UrlPathPattern) and isinstance(item.enabled_when, str)
|
|
519
|
+
for item in urlpatterns
|
|
520
|
+
)
|
|
521
|
+
runtime = None
|
|
522
|
+
if runtime_factory is not None:
|
|
523
|
+
runtime = runtime_factory()
|
|
524
|
+
if runtime is None:
|
|
525
|
+
return router
|
|
526
|
+
elif runtime_required:
|
|
527
|
+
raise RuntimeError("urlpatterns with conditional flags must declare runtime_factory.")
|
|
528
|
+
for item in urlpatterns:
|
|
529
|
+
if not isinstance(item, UrlPathPattern):
|
|
530
|
+
continue
|
|
531
|
+
if not _resolve_enabled_when(item.enabled_when, runtime):
|
|
532
|
+
continue
|
|
533
|
+
router.add_api_route(
|
|
534
|
+
_resolve_pattern_path(item, runtime),
|
|
535
|
+
_resolve_pattern_endpoint(item, runtime),
|
|
536
|
+
**_binding_route_kwargs(
|
|
537
|
+
methods=item.methods,
|
|
538
|
+
response_class=item.response_class,
|
|
539
|
+
name=item.name,
|
|
540
|
+
include_in_schema=item.include_in_schema,
|
|
541
|
+
dependencies=item.dependencies,
|
|
542
|
+
),
|
|
543
|
+
)
|
|
544
|
+
return router
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def build_declared_router(
|
|
548
|
+
*,
|
|
549
|
+
bindings: tuple[DeclaredEndpointBinding, ...],
|
|
550
|
+
) -> APIRouter:
|
|
551
|
+
router = APIRouter()
|
|
552
|
+
for binding in bindings:
|
|
553
|
+
router.add_api_route(
|
|
554
|
+
str(binding.path),
|
|
555
|
+
binding.endpoint,
|
|
556
|
+
**_binding_route_kwargs(
|
|
557
|
+
methods=binding.methods,
|
|
558
|
+
response_class=binding.response_class,
|
|
559
|
+
name=binding.name,
|
|
560
|
+
include_in_schema=binding.include_in_schema,
|
|
561
|
+
),
|
|
562
|
+
)
|
|
563
|
+
return router
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def create_declared_router_url_spec(
|
|
567
|
+
*,
|
|
568
|
+
namespace: str,
|
|
569
|
+
bindings: tuple[DeclaredEndpointBinding, ...],
|
|
570
|
+
path_prefix: str = "",
|
|
571
|
+
dependencies: tuple[object, ...] = (),
|
|
572
|
+
replace_target: str = "",
|
|
573
|
+
route_hints: tuple[str, ...] = (),
|
|
574
|
+
conflict_policy: str = "fail",
|
|
575
|
+
) -> DeclaredUrlSpec:
|
|
576
|
+
return DeclaredUrlSpec(
|
|
577
|
+
router=build_declared_router(bindings=bindings),
|
|
578
|
+
path_prefix=path_prefix,
|
|
579
|
+
namespace=namespace,
|
|
580
|
+
dependencies=dependencies,
|
|
581
|
+
replace_target=replace_target,
|
|
582
|
+
route_hints=route_hints,
|
|
583
|
+
conflict_policy=conflict_policy,
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def create_runtime_router_url_spec(
|
|
588
|
+
*,
|
|
589
|
+
namespace: str,
|
|
590
|
+
runtime_factory: Callable[[], Any | None],
|
|
591
|
+
bindings: tuple[RuntimeRouteBinding, ...],
|
|
592
|
+
path_prefix: str = "",
|
|
593
|
+
dependencies: tuple[object, ...] = (),
|
|
594
|
+
replace_target: str = "",
|
|
595
|
+
route_hints: tuple[str, ...] = (),
|
|
596
|
+
conflict_policy: str = "fail",
|
|
597
|
+
) -> DeclaredUrlSpec:
|
|
598
|
+
return DeclaredUrlSpec(
|
|
599
|
+
router=build_runtime_router(
|
|
600
|
+
runtime_factory=runtime_factory,
|
|
601
|
+
bindings=bindings,
|
|
602
|
+
),
|
|
603
|
+
path_prefix=path_prefix,
|
|
604
|
+
namespace=namespace,
|
|
605
|
+
dependencies=dependencies,
|
|
606
|
+
replace_target=replace_target,
|
|
607
|
+
route_hints=route_hints,
|
|
608
|
+
conflict_policy=conflict_policy,
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
def build_runtime_router_from_spec(
|
|
613
|
+
*,
|
|
614
|
+
runtime_factory: Callable[[], Any | None],
|
|
615
|
+
bindings: tuple[RuntimeRouteBinding, ...],
|
|
616
|
+
) -> APIRouter:
|
|
617
|
+
return build_runtime_router(
|
|
618
|
+
runtime_factory=runtime_factory,
|
|
619
|
+
bindings=bindings,
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
def create_lazy_mount_url_spec(
|
|
624
|
+
*,
|
|
625
|
+
namespace: str,
|
|
626
|
+
path: str,
|
|
627
|
+
app_factory: Callable[[], Any],
|
|
628
|
+
name: str | None = None,
|
|
629
|
+
dependencies: tuple[object, ...] = (),
|
|
630
|
+
replace_target: str = "",
|
|
631
|
+
route_hints: tuple[str, ...] = (),
|
|
632
|
+
conflict_policy: str = "fail",
|
|
633
|
+
) -> DeclaredUrlSpec:
|
|
634
|
+
return DeclaredUrlSpec(
|
|
635
|
+
router=create_lazy_mount_router(
|
|
636
|
+
path_prefix=path,
|
|
637
|
+
app_factory=app_factory,
|
|
638
|
+
name=name,
|
|
639
|
+
),
|
|
640
|
+
namespace=namespace,
|
|
641
|
+
dependencies=dependencies,
|
|
642
|
+
replace_target=replace_target,
|
|
643
|
+
route_hints=route_hints,
|
|
644
|
+
conflict_policy=conflict_policy,
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
def create_lazy_mount_url_specs(
|
|
649
|
+
bindings: tuple[LazyMountUrlBinding, ...] | list[LazyMountUrlBinding],
|
|
650
|
+
) -> tuple[DeclaredUrlSpec, ...]:
|
|
651
|
+
return tuple(
|
|
652
|
+
create_lazy_mount_url_spec(
|
|
653
|
+
namespace=binding.namespace,
|
|
654
|
+
path=binding.path,
|
|
655
|
+
app_factory=binding.app_factory,
|
|
656
|
+
name=binding.name,
|
|
657
|
+
dependencies=tuple(binding.dependencies),
|
|
658
|
+
replace_target=binding.replace_target,
|
|
659
|
+
route_hints=tuple(binding.route_hints),
|
|
660
|
+
conflict_policy=binding.conflict_policy,
|
|
661
|
+
)
|
|
662
|
+
for binding in bindings
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def _clone_declared_url_spec_with_prefix(
|
|
667
|
+
spec: DeclaredUrlSpec,
|
|
668
|
+
*,
|
|
669
|
+
path_prefix: str = "",
|
|
670
|
+
namespace_prefix: str = "",
|
|
671
|
+
) -> DeclaredUrlSpec:
|
|
672
|
+
return DeclaredUrlSpec(
|
|
673
|
+
router=spec.router,
|
|
674
|
+
path_prefix=_join_path_prefix(path_prefix, spec.path_prefix),
|
|
675
|
+
namespace=f"{namespace_prefix}.{spec.namespace}" if namespace_prefix else spec.namespace,
|
|
676
|
+
dependencies=tuple(spec.dependencies),
|
|
677
|
+
replace_target=spec.replace_target,
|
|
678
|
+
route_hints=tuple(spec.route_hints),
|
|
679
|
+
conflict_policy=spec.conflict_policy,
|
|
680
|
+
)
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
def _coerce_declared_url_spec(item: object) -> DeclaredUrlSpec | None:
|
|
684
|
+
if isinstance(item, DeclaredUrlSpec):
|
|
685
|
+
return item
|
|
686
|
+
router = getattr(item, "router", None)
|
|
687
|
+
if not isinstance(router, APIRouter):
|
|
688
|
+
return None
|
|
689
|
+
if not hasattr(item, "namespace"):
|
|
690
|
+
return None
|
|
691
|
+
return DeclaredUrlSpec(
|
|
692
|
+
router=router,
|
|
693
|
+
path_prefix=getattr(item, "path_prefix", ""),
|
|
694
|
+
namespace=getattr(item, "namespace", ""),
|
|
695
|
+
dependencies=tuple(getattr(item, "dependencies", ()) or ()),
|
|
696
|
+
replace_target=getattr(item, "replace_target", ""),
|
|
697
|
+
route_hints=tuple(getattr(item, "route_hints", ()) or ()),
|
|
698
|
+
conflict_policy=getattr(item, "conflict_policy", "fail"),
|
|
699
|
+
)
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
def _coerce_url_path_pattern(item: object) -> UrlPathPattern | None:
|
|
703
|
+
if isinstance(item, UrlPathPattern):
|
|
704
|
+
return item
|
|
705
|
+
if not hasattr(item, "view") or not hasattr(item, "path"):
|
|
706
|
+
return None
|
|
707
|
+
return UrlPathPattern(
|
|
708
|
+
path=getattr(item, "path"),
|
|
709
|
+
view=getattr(item, "view"),
|
|
710
|
+
methods=tuple(getattr(item, "methods", ("GET",)) or ("GET",)),
|
|
711
|
+
response_class=getattr(item, "response_class", None),
|
|
712
|
+
name=getattr(item, "name", None),
|
|
713
|
+
include_in_schema=bool(getattr(item, "include_in_schema", True)),
|
|
714
|
+
enabled_when=getattr(item, "enabled_when", None),
|
|
715
|
+
dependencies=tuple(getattr(item, "dependencies", ()) or ()),
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def _coerce_mounted_url_pattern(item: object) -> MountedUrlPattern | None:
|
|
720
|
+
if isinstance(item, MountedUrlPattern):
|
|
721
|
+
return item
|
|
722
|
+
if not hasattr(item, "app") or not hasattr(item, "path") or not hasattr(item, "namespace"):
|
|
723
|
+
return None
|
|
724
|
+
return MountedUrlPattern(
|
|
725
|
+
path=getattr(item, "path"),
|
|
726
|
+
app=getattr(item, "app"),
|
|
727
|
+
namespace=getattr(item, "namespace"),
|
|
728
|
+
name=getattr(item, "name", None),
|
|
729
|
+
dependencies=tuple(getattr(item, "dependencies", ()) or ()),
|
|
730
|
+
replace_target=getattr(item, "replace_target", ""),
|
|
731
|
+
route_hints=tuple(getattr(item, "route_hints", ()) or ()),
|
|
732
|
+
conflict_policy=getattr(item, "conflict_policy", "fail"),
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
def _coerce_included_urls(item: object) -> IncludedUrls | None:
|
|
737
|
+
if isinstance(item, IncludedUrls):
|
|
738
|
+
return item
|
|
739
|
+
if not hasattr(item, "module_name"):
|
|
740
|
+
return None
|
|
741
|
+
return IncludedUrls(
|
|
742
|
+
module_name=getattr(item, "module_name"),
|
|
743
|
+
path_prefix=getattr(item, "path_prefix", ""),
|
|
744
|
+
namespace=getattr(item, "namespace", ""),
|
|
745
|
+
)
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
def compile_urlpatterns(
|
|
749
|
+
*,
|
|
750
|
+
urlpatterns: tuple[DeclaredUrlSpec | UrlPathPattern | MountedUrlPattern | IncludedUrls, ...]
|
|
751
|
+
| list[DeclaredUrlSpec | UrlPathPattern | MountedUrlPattern | IncludedUrls],
|
|
752
|
+
app_name: str = "",
|
|
753
|
+
runtime_factory: Callable[[], Any | None] | None = None,
|
|
754
|
+
route_hints: tuple[str, ...] = (),
|
|
755
|
+
) -> tuple[DeclaredUrlSpec, ...]:
|
|
756
|
+
specs: list[DeclaredUrlSpec] = []
|
|
757
|
+
pending_path_patterns: list[UrlPathPattern] = []
|
|
758
|
+
|
|
759
|
+
def _flush_path_patterns() -> None:
|
|
760
|
+
nonlocal pending_path_patterns
|
|
761
|
+
if not pending_path_patterns:
|
|
762
|
+
return
|
|
763
|
+
if not str(app_name or "").strip():
|
|
764
|
+
raise RuntimeError("urlpatterns with path(...) entries must declare app_name.")
|
|
765
|
+
specs.append(
|
|
766
|
+
DeclaredUrlSpec(
|
|
767
|
+
router=build_router_from_urlpatterns(
|
|
768
|
+
urlpatterns=tuple(pending_path_patterns),
|
|
769
|
+
runtime_factory=runtime_factory,
|
|
770
|
+
),
|
|
771
|
+
namespace=str(app_name),
|
|
772
|
+
route_hints=tuple(route_hints or ()),
|
|
773
|
+
),
|
|
774
|
+
)
|
|
775
|
+
pending_path_patterns = []
|
|
776
|
+
|
|
777
|
+
for item in urlpatterns:
|
|
778
|
+
declared_spec = _coerce_declared_url_spec(item)
|
|
779
|
+
if declared_spec is not None:
|
|
780
|
+
_flush_path_patterns()
|
|
781
|
+
specs.append(declared_spec)
|
|
782
|
+
continue
|
|
783
|
+
url_path_pattern = _coerce_url_path_pattern(item)
|
|
784
|
+
if url_path_pattern is not None:
|
|
785
|
+
pending_path_patterns.append(url_path_pattern)
|
|
786
|
+
continue
|
|
787
|
+
mounted_url_pattern = _coerce_mounted_url_pattern(item)
|
|
788
|
+
if mounted_url_pattern is not None:
|
|
789
|
+
_flush_path_patterns()
|
|
790
|
+
specs.append(
|
|
791
|
+
create_lazy_mount_url_spec(
|
|
792
|
+
namespace=mounted_url_pattern.namespace,
|
|
793
|
+
path=mounted_url_pattern.path,
|
|
794
|
+
app_factory=mounted_url_pattern.app,
|
|
795
|
+
name=mounted_url_pattern.name,
|
|
796
|
+
dependencies=tuple(mounted_url_pattern.dependencies),
|
|
797
|
+
replace_target=mounted_url_pattern.replace_target,
|
|
798
|
+
route_hints=tuple(mounted_url_pattern.route_hints),
|
|
799
|
+
conflict_policy=mounted_url_pattern.conflict_policy,
|
|
800
|
+
)
|
|
801
|
+
)
|
|
802
|
+
continue
|
|
803
|
+
included_urls = _coerce_included_urls(item)
|
|
804
|
+
if included_urls is not None:
|
|
805
|
+
_flush_path_patterns()
|
|
806
|
+
from .loaders import load_url_module_specs
|
|
807
|
+
|
|
808
|
+
for spec in load_url_module_specs(included_urls.module_name):
|
|
809
|
+
specs.append(
|
|
810
|
+
_clone_declared_url_spec_with_prefix(
|
|
811
|
+
spec,
|
|
812
|
+
path_prefix=included_urls.path_prefix,
|
|
813
|
+
namespace_prefix=included_urls.namespace,
|
|
814
|
+
)
|
|
815
|
+
)
|
|
816
|
+
continue
|
|
817
|
+
raise RuntimeError(
|
|
818
|
+
"urlpatterns must contain only path(...), mount(...), include(...), or DeclaredUrlSpec entries."
|
|
819
|
+
)
|
|
820
|
+
_flush_path_patterns()
|
|
821
|
+
return tuple(specs)
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
__all__ = [
|
|
825
|
+
"DeclaredEndpointBinding",
|
|
826
|
+
"MountedUrlPattern",
|
|
827
|
+
"LazyMountUrlBinding",
|
|
828
|
+
"build_declared_router",
|
|
829
|
+
"build_router_from_urlpatterns",
|
|
830
|
+
"create_lazy_mount_url_bindings",
|
|
831
|
+
"create_declared_router_url_spec",
|
|
832
|
+
"compile_urlpatterns",
|
|
833
|
+
"mount",
|
|
834
|
+
"path",
|
|
835
|
+
"RuntimeRouteBinding",
|
|
836
|
+
"build_runtime_router",
|
|
837
|
+
"build_runtime_router_from_spec",
|
|
838
|
+
"create_runtime_route_bindings",
|
|
839
|
+
"create_lazy_mount_url_spec",
|
|
840
|
+
"create_lazy_mount_url_specs",
|
|
841
|
+
"create_runtime_router_url_spec",
|
|
842
|
+
"UrlPathPattern",
|
|
843
|
+
]
|