Filesystem route discovery for the pages/ directory.
Walks the pages directory tree and discovers:
_layout.htmlfiles as layout templates_context.pyfiles as context providers.pyroute files as handler modules
Directory names wrapped in\{braces}become path parameters.
page.py maps to the directory URL; other .pyfiles append
their stem to the path.
Modeled on Bengal's ContentDiscovery but for routes instead of content.
pages.discovery
| Name | Type | Default | Description |
|---|---|---|---|
type
|
|
— | |
qualified_name
|
|
— | |
element_type
|
|
— | |
description
|
|
— | |
source_file
|
|
— | |
line_number
|
|
— | |
is_autodoc
|
|
— | |
autodoc_element
|
|
— | |
_autodoc_template
|
|
— | |
_autodoc_url_path
|
|
— | |
_autodoc_page_type
|
|
— | |
title
|
|
— | |
doc_content_hash
|
|
— |
Symbols on this page
Derive a dotted default route name from a URL path.
Parameter braces are stripped and the param name is kept bare:
/contacts/\{contact_id} → "contacts.contact_id"…
Walk a pages directory and discover all routes.
Walk a pages directory and discover routes plus handler-discovery findings.
Same asdiscover_pages() but also returns a list of
PageHandlerFinding objects describing page.py…
Recursively walk a directory, discovering routes and layouts.
Infer route kind from file combination. Informational only.
Read{# target #}and optional shell scope comments from a layout.
Supported annotations::
{# preset: preset_name #} {# target: element_id #} {# domain:…Resolve a named layout preset or raise for unknown names.
Normalize{# outlet_mode: #}token to a known mode.
Load viewmodel() function from _viewmodel.py.
Load @action decorated functions from _actions.py.
Load RouteMeta from a _meta.py file.
Checks for META constant first, then meta() callable. Returns (meta, meta_provider) — one will be set, the other…
Convert a meta dict to a normalizedRouteMeta, filling provided keys.
auth accepts a plain str(back-compatible), a structured
AuthSpec, or a …
Coerce a rawauth value to the canonical AuthSpec | Noneshape.
dict->AuthSpecbuilt frompermissions/mode/policy/scopes…
Return meta withauth canonicalized to AuthSpec | None.
Applied at discovery time (staticMETA) and at request time for dynamic
meta()…
Load a context() function from a _context.py file.
Uses path-based module names (_chirp_ctx_collections, etc.) so sibling directories do not overwrite each other in sys.modules.…
Load a route .py file and extract handler functions.
page.pymaps to the directory URL. Other files append their
stem to the URL path.…
default_route_name
function
def default_route_name(url_path: str) -> str
Derive a dotted default route name from a URL path.
Parameter braces are stripped and the param name is kept bare:
/contacts/\{contact_id} → "contacts.contact_id".
Typed params drop the type:/{id:int} → "id".
The root path/ becomes "index"so every route has a non-empty name.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
url_path
|
str
|
— |
discover_pages
function
def discover_pages(pages_dir: str | Path, *, layout_presets: Mapping[str, LayoutPreset] | None = None) -> list[PageRoute]
Walk a pages directory and discover all routes.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
pages_dir
|
str | Path
|
— | Path to the ``pages/`` directory. |
layout_presets
|
Mapping[str, LayoutPreset] | None
|
None
|
discover_pages_with_findings
function
def discover_pages_with_findings(pages_dir: str | Path, *, layout_presets: Mapping[str, LayoutPreset] | None = None) -> tuple[list[PageRoute], list[PageHandlerFinding]]
Walk a pages directory and discover routes plus handler-discovery findings.
Same asdiscover_pages() but also returns a list of
PageHandlerFinding objects describing page.pyfiles
that have no recognised handler or define handler-shaped typos.
Findings are consumed by thepage_handlerscontract check.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
pages_dir
|
str | Path
|
— | |
layout_presets
|
Mapping[str, LayoutPreset] | None
|
None
|
_walk_directory
function
def _walk_directory(directory: Path, root: Path, *, url_parts: list[str], layouts: list[LayoutInfo], context_providers: list[ContextProvider], depth: int, routes: list[PageRoute], findings: list[PageHandlerFinding], layout_presets: Mapping[str, LayoutPreset]) -> None
Recursively walk a directory, discovering routes and layouts.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
directory
|
Path
|
— | Current directory being walked. |
root
|
Path
|
— | Root pages directory (for computing template paths). |
url_parts
|
list[str]
|
— | URL path segments accumulated so far. |
layouts
|
list[LayoutInfo]
|
— | Layout chain accumulated from parent directories. |
context_providers
|
list[ContextProvider]
|
— | Context providers from parent directories. |
depth
|
int
|
— | Current nesting depth. |
routes
|
list[PageRoute]
|
— | Accumulator for discovered routes. |
findings
|
list[PageHandlerFinding]
|
— | |
layout_presets
|
Mapping[str, LayoutPreset]
|
— |
_infer_route_kind
function
def _infer_route_kind(*, has_template: bool, is_param_dir: bool) -> RouteKind
Infer route kind from file combination. Informational only.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
has_template
|
bool
|
— | |
is_param_dir
|
bool
|
— |
_parse_layout_metadata
function
def _parse_layout_metadata(layout_file: Path, *, layout_presets: Mapping[str, LayoutPreset]) -> dict[str, Any]
Read{# target #}and optional shell scope comments from a layout.
Supported annotations::
{# preset: preset_name #}
{# target: element_id #}
{# domain: navigation_domain #}
{# shell: shell_name #}
{# swap_scope: symbolic_name #}
{# outlet: element_id #}
{# outlet_mode: compose | replace #}
{# frames: id1, id2 #}
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
layout_file
|
Path
|
— | |
layout_presets
|
Mapping[str, LayoutPreset]
|
— |
_resolve_layout_preset
function
def _resolve_layout_preset(layout_file: Path, preset_name: str | None, layout_presets: Mapping[str, LayoutPreset]) -> LayoutPreset | None
Resolve a named layout preset or raise for unknown names.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
layout_file
|
Path
|
— | |
preset_name
|
str | None
|
— | |
layout_presets
|
Mapping[str, LayoutPreset]
|
— |
_normalize_outlet_mode
function
def _normalize_outlet_mode(raw: str | OutletSwapMode | None) -> OutletSwapMode
Normalize{# outlet_mode: #}token to a known mode.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
raw
|
str | OutletSwapMode | None
|
— |
_load_viewmodel
function
def _load_viewmodel(viewmodel_file: Path, root: Path) -> Any
Load viewmodel() function from _viewmodel.py.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
viewmodel_file
|
Path
|
— | |
root
|
Path
|
— |
_load_actions
function
def _load_actions(actions_file: Path, root: Path) -> tuple[ActionInfo, ...]
Load @action decorated functions from _actions.py.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
actions_file
|
Path
|
— | |
root
|
Path
|
— |
_load_meta
function
def _load_meta(meta_file: Path, root: Path) -> tuple[RouteMeta | None, Any]
Load RouteMeta from a _meta.py file.
Checks for META constant first, then meta() callable. Returns (meta, meta_provider) — one will be set, the other None. Raises ValueError if _meta.py has neither META nor meta().
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
meta_file
|
Path
|
— | |
root
|
Path
|
— |
dict_to_route_meta
function
def dict_to_route_meta(d: dict[str, Any]) -> RouteMeta
Convert a meta dict to a normalizedRouteMeta, filling provided keys.
auth accepts a plain str(back-compatible), a structured
AuthSpec, or a dictthat constructs an
AuthSpec (e.g. {"permissions": ["a", "b"], "mode": "any"}). The
result is canonicalized so the request-time gate is allocation-free.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
d
|
dict[str, Any]
|
— |
_coerce_auth
function
def _coerce_auth(value: Any) -> Any
Coerce a rawauth value to the canonical AuthSpec | Noneshape.
dict->AuthSpecbuilt frompermissions/mode/policy/scopes(a dict auth is always a declared gate; anAuthSpecalways requires authentication, so there is norequiredkey).scopesis the machine-token axis, parallel topermissions.str/AuthSpec/None-> normalized via the shared core so the runtime meaning of every legacy string is preserved exactly.
Adict mode other than "all" / "any" raises ValueErrorat
coercion time (discovery for staticMETA, request time for dynamic
meta()) — fail loud rather than silently degrading an invalid mode.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
value
|
Any
|
— |
normalize_route_meta
function
def normalize_route_meta(meta: RouteMeta | None) -> RouteMeta | None
Return meta withauth canonicalized to AuthSpec | None.
Applied at discovery time (staticMETA) and at request time for dynamic
meta()results, so the request-time gate
(enforce_route_meta_auth()) never re-allocates a
spec and reserved-token confusion ("Required" / " required " / "")
surfaces as a startupauth_specissue rather than a silent 403. Returns
meta unchanged whenauthis already canonical (allocation-free).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
meta
|
RouteMeta | None
|
— |
_load_context_provider
function
def _load_context_provider(context_file: Path, root: Path, depth: int) -> ContextProvider | None
Load a context() function from a _context.py file.
Uses path-based module names (_chirp_ctx_collections, etc.) so sibling directories do not overwrite each other in sys.modules.
Returns None if the module doesn't export acontextfunction.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
context_file
|
Path
|
— | |
root
|
Path
|
— | |
depth
|
int
|
— |
_process_route_file
function
def _process_route_file(file: Path, root: Path, *, url_parts: list[str], layout_chain: LayoutChain, context_providers: tuple[ContextProvider, ...], routes: list[PageRoute], findings: list[PageHandlerFinding], route_meta: RouteMeta | None = None, meta_provider: Any = None, actions: tuple[ActionInfo, ...] = (), viewmodel_provider: Any = None) -> None
Load a route .py file and extract handler functions.
page.pymaps to the directory URL. Other files append their
stem to the URL path.
Handler functions are named after HTTP methods:get, post, etc.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
file
|
Path
|
— | |
root
|
Path
|
— | |
url_parts
|
list[str]
|
— | |
layout_chain
|
LayoutChain
|
— | |
context_providers
|
tuple[ContextProvider, ...]
|
— | |
routes
|
list[PageRoute]
|
— | |
findings
|
list[PageHandlerFinding]
|
— | |
route_meta
|
RouteMeta | None
|
None
|
|
meta_provider
|
Any
|
None
|
|
actions
|
tuple[ActionInfo, ...]
|
()
|
|
viewmodel_provider
|
Any
|
None
|
View source · /home/runner/work/chirp/chirp/site/../src/chirp/pages/discovery.py:1