config_schema

Page actions AI-ready formats and sharing
Open LLM text
Share with AI
Ask Claude Ask ChatGPT Ask Gemini Ask Copilot

Typed config-schema → form-field projection for chirp-ui.

Deliberately modeled onchirp_ui.grid_stateand chirp_ui.route_tabs: stdlib + dataclasses only, no import chirpand noimport kida. Fully unit-testable with plain pytest and …

Typed config-schema → form-field projection for chirp-ui.

Deliberately modeled onchirp_ui.grid_stateand chirp_ui.route_tabs: stdlib + dataclasses only, no import chirpand noimport kida. Fully unit-testable with plain pytest and ty-checkable without a render ("works without Chirp, better with Chirp").

A developer declares a config once as a list ofField. The same list the server validates/persists against is projected byproject_fields() intoProjectedField rows that carry the resolved widget, the currentvalue, and render-ready choices. The config_formmacro reads those props directly and never derives them — so persisted server config and the rendered form cannot drift (thesort_columns() analog for forms).

Example (Chirp route)::

from chirp_ui import Field, Widget, project_fields

MODEL_SETTINGS = [
    Field("model", type="str", label="Model", default="gpt-4o",
          choices=(("gpt-4o", "GPT-4o"), ("claude", "Claude"))),
    Field("temperature", type="float", label="Temperature",
          default=0.7, min=0.0, max=2.0, step=0.1),
    Field("stream", type="bool", label="Stream responses", default=True),
    Field("api_key", type="str", label="API key", secret=True),
    Field("system_prompt", type="str", label="System prompt",
          widget=Widget.TEXTAREA, default=""),
]

fields = project_fields(MODEL_SETTINGS, values=load_settings(user))
# -> template: {{ config_form(fields, action="/settings", method="post") }}

config_schema

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

Widget
class

The render target aProjectedFielddispatches to.

Each value maps to an existing macro informs.html(text_field, textarea_field, select_field, toggle_field, range_field, number_scale, password_field).StrEnum so widget == "select"works in templates.

Field
class

A single config attribute — the developer-authored input.

name is the stable form key (matches the server attribute). typeis the Python type hint as a string ("str"/"int"/"float"/"bool") used for widget inference whenwidget is not set. choicesare (value, label) pairs (static); options_callablesupplies them lazily (e.g. a live model list) and wins overchoices when set. secret=True forces a password widget and never echoes the value back to the client. min/max/stepdrive range/number widgets.

ProjectedField
class

A field projected for rendering. The macro reads these props directly.

widget is the resolved Widgetvalue (a plain str, so the template can{% if pf.widget == "select" %}). choicesis a tuple of {"value", "label"} dicts — exactly the shape select_field/ radio_field / multi_select_fieldalready iterate with opt.get("value") / opt.get("label"). valueis masked (empty) for secrets.

project_fields
function
def project_fields(schema: Sequence[Field | Mapping[str, Any]], values: Mapping[str, Any] | None = None) -> list[ProjectedField]

Projectschema into render-ready ProjectedFieldrows.

Thesort_columns() analog for forms. For each field it resolves the widget (explicitwidget wins, else _infer_widget()), reads the current value fromvalues (falling back to default, masked to empty for secrets), and normalizes choices to{"value","label"}dicts so the existingselect_field/radio_fieldmacros consume them unchanged. The macro never recomputes any of this — the server schema and the rendered control are the same source of truth.

Parameters

Name Type Default Description
schema Sequence[Field | Mapping[str, Any]]
values Mapping[str, Any] | None None

View source · /home/runner/work/chirp-ui/chirp-ui/site/../src/chirp_ui/config_schema.py:1