exlab_wizard.template.manifest#

Typed, round-trippable model of a Copier copier.yml manifest.

This module owns the two primitives the GUI authoring form and the wizard consume questions through:

  • TemplateQuestion – one Copier question normalised to the widget family the wizard renders (str / int / float / bool / choice).

  • template_questions() – parse the operator-answerable questions out of a raw copier.yml body (both Copier long- and short-form).

These two used to live in exlab_wizard.ui.pages.templates. They were moved here so the (non-UI) TemplateManifest model can reuse them without importing a NiceGUI page module (an import cycle). ui.pages.templates re-exports them so existing callers keep working.

TemplateManifest mirrors the _exlab_* metadata keys plus the parsed questions and round-trips copier.yml so the structured authoring form never hand-writes YAML: TemplateManifest.from_yaml(m.to_yaml()) == m holds for manifests built from every supported question kind.

Functions

template_questions(raw_manifest)

Parse the operator-answerable questions out of a copier.yml body.

Classes

TemplateManifest(exlab_type, exlab_version)

A typed, round-trippable model of a Copier copier.yml.

TemplateQuestion(key, kind[, default, ...])

One Copier question parsed from a template's copier.yml.

class exlab_wizard.template.manifest.TemplateManifest(exlab_type, exlab_version, exlab_run_scope=None, description='', plugins=<factory>, readme_fields=<factory>, questions=<factory>, min_copier_version='9.0', answers_file='.exlab-answers.yml')[source]#

Bases: object

A typed, round-trippable model of a Copier copier.yml.

Mirrors the _exlab_* metadata keys plus the parsed TemplateQuestion list. Built so the structured authoring form never hand-writes YAML: from_yaml() parses a manifest (string or already-parsed dict) and to_yaml() emits a deterministic, long-form copier.yml such that TemplateManifest.from_yaml(m.to_yaml()) == m.

exlab_type#

One of "project" / "equipment" / "run" (_exlab_type). Not validated here – see exlab_wizard.template.lint.

exlab_version#

The required _exlab_version string (§5.7).

exlab_run_scope#

_exlab_run_scope for run templates; None otherwise (and then never emitted by to_yaml()).

description#

_exlab_description free-form text.

plugins#

Ordered _exlab_plugins slug list (§6.2.3); emitted only when non-empty.

readme_fields#

_exlab_readme.fields field-extension list (§10.3), each a free-form dict.

questions#

Parsed operator-answerable questions, emitted in long form.

min_copier_version#

_min_copier_version (defaults "9.0").

answers_file#

_answers_file (defaults ".exlab-answers.yml").

Parameters:
answers_file: str = '.exlab-answers.yml'#
description: str = ''#
exlab_run_scope: str | None = None#
exlab_type: str#
exlab_version: str#
classmethod from_yaml(raw)[source]#

Build a TemplateManifest from a manifest body.

Parameters:

raw (str | dict[str, Any]) – Either a raw copier.yml string (parsed with yaml.safe_load()) or an already-parsed mapping.

Return type:

TemplateManifest

Returns:

A TemplateManifest. Missing _exlab_* / _* keys fall back to the dataclass defaults; questions are parsed via template_questions().

min_copier_version: str = '9.0'#
plugins: list[str]#
questions: list[TemplateQuestion]#
readme_fields: list[dict[str, Any]]#
to_yaml()[source]#

Emit a deterministic, long-form copier.yml string.

Keys are emitted in a fixed order (Copier metadata first, then each question in long form) with sort_keys=False so the ordering is preserved. _exlab_run_scope is emitted only when not None and _exlab_plugins only when non-empty. Each question emits {type, help, default, choices, secret} with empty / None sub-keys omitted, so from_yaml() reconstructs the identical model.

Return type:

str

class exlab_wizard.template.manifest.TemplateQuestion(key, kind, default=None, choices=(), help='', secret=False)[source]#

Bases: object

One Copier question parsed from a template’s copier.yml.

kind is normalised to the widget family the wizard renders: str / int / float / bool / choice. choices is populated only for choice questions. secret flags a password-style str input.

Parameters:
choices: tuple[Any, ...] = ()#
default: Any = None#
help: str = ''#
key: str#
kind: str#
secret: bool = False#
exlab_wizard.template.manifest.template_questions(raw_manifest)[source]#

Parse the operator-answerable questions out of a copier.yml body.

Handles both Copier question forms:

  • long formkey: {type: ..., default: ..., choices: ...}

  • short formkey: <scalar> (the scalar is the default; the type is inferred from it)

_-prefixed keys (Copier / _exlab_* metadata) are skipped. Questions carrying a when clause are still returned – the wizard renders them unconditionally for v1.

Parameters:

raw_manifest (dict[str, Any])

Return type:

list[TemplateQuestion]