You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SchemaSpec + TemplateSet + a pluggable PresetStore codec — a declarative, self-documenting template-file system (2026-06-27). A new shared layer for "named config/template files a user can model their own after," split into three composable, Qt-free, zero-dependency primitives so the shape and the storage of a template each have one SSoT. SchemaSpec (core_utils/schema_spec.py) is a base for schemas defined as a @dataclass: fields declared via spec_field(help=…, example=…, required=…, nested=…, choices=…, validate=…) carry their own documentation, and from that single definition the base derives — with no per-schema code — validate() (returns a ValidationResult that deliberately splits errors (unknown discriminator, wrong structure, missing required) from warnings (an unrecognised key; _-prefixed keys are reserved for annotations and never warned), so a file that merely carries an extra key keeps working; its raise_or_warn() is the one-call "enforce a validated file" helper every loader shares), skeleton() (a fully-populated example dict to copy, omitting unset optionals), generic from_dict/to_dict (recursing nested schemas), and describe()/to_markdown() (a field-by-field reference, nested schemas rendered as sub-tables — so the doc can never drift from the enforced shape). PresetStore gained an additive codec: Codec parameter (default JSON_CODEC, fully back-compatible — every existing caller and uitk's PresetManager are unaffected): a Codec(ext, load, dump) makes the store format-agnostic, so a caller can back *.yaml files by injecting a YAML codec without pythontk taking a YAML dependency (the caller supplies it). ext is now a property; discovery/path/load/save route through the codec. TemplateSet (core_utils/template_set.py) is the thin glue binding a PresetStore (two-tier built-in + user discovery, shadowing, last-used .active pointer) to a SchemaSpec (shape): names()/source()/user_dir/active, raw() (plain dict) vs load() (parse → validate → deserialise, raising on errors, logging warnings, strict= to raise on warnings too), skeleton(), save()/write_skeleton() (write arbitrary data or the generated skeleton to the user dir), and markdown(). Motivated by — and first consumed by — mayatk's Shot Manifest, whose CSV mapping (JSON) and behavior (YAML) template files were each globbed from inside the installed package with no user tier, no validation, and docstring-only schemas; both now share this one mechanism (see mayatk CHANGELOG 2026-06-27). Root exports: SchemaSpec, spec_field, ValidationResult, SchemaError, FieldDoc, Codec, JSON_CODEC, TemplateSet. Tests: test_schema_spec.py (19: validate errors/warnings/nested/choices/custom-validator, skeleton-is-self-valid, describe/markdown, round-trip), test_template_set.py (10: tiering, load-validates-and-raises, raw-skips-validation, skeleton/write_skeleton, user-shadows-builtin, custom-codec ext+IO), test_preset_store.py (+3 codec: default-is-JSON, custom-ext round-trip, cross-codec invisibility); 45 green pythontk-side, uitk PresetManager suite 74 green (consumer unaffected).