validate
tit.server.routes.validate ¶
POST /api/validate/{kind} -- field-level config validation, no side effects.
Deserializes config through :func:tit.config_io.deserialize_config for the dataclass that
kind maps to (see :func:cls_for), catching exactly what a config dataclass's own
__post_init__ (or a bad _type/field shape) can raise, and reports it as
{ok, errors: [{path, message}]} -- the UI never re-implements these rules (design rule R1);
this route only surfaces them. Exhaustive-search mask paths are also checked for
accessibility before a plan or costly leadfield load can proceed.
Kind -> config-class resolution¶
Most kinds map to exactly one dataclass in :data:tit.config_io.CONFIG_CLASS_REGISTRY
(:data:SIMPLE_KIND_CLASS). Two kinds do not: stats (GroupComparisonConfig or
CorrelationConfig) and blender (MontageConfig/VectorConfig/RegionConfig/SubcorticalConfig) --
the frozen PipelineConfig union in contracts/openapi.yaml lists all of them under the
same kind/path parameter with no other discriminant on the object itself. This module resolves
the ambiguity with a config["_type"] key (see :data:AMBIGUOUS_KIND_CLASSES), the same
discriminator convention :mod:tit.config_io already uses for union-typed fields (ROIs,
electrodes, montages) -- just applied here to the top-level kind/class choice. _type is not a
field of any of these dataclasses, so :func:~tit.config_io.deserialize_config silently ignores
it (documented behavior: "keys in data that are not fields of cls ... are ignored"), making
this additive rather than a contract change. The tag is read exactly as each runner dispatches:
blender requires it (tit.blender.__main__ has no default), and stats lets the older
mode key win over it (tit.stats.__main__), so the server never plans one class while
the runner runs another. NO_SCHEMA_KINDS is empty as of the runners
lane registering NiftiAverageConfig/NilearnConfig in
:data:~tit.config_io.CONFIG_CLASS_REGISTRY -- kept as a (currently-empty) frozenset rather
than removed outright since contracts/generated/config.schema.json has not been regenerated with these two
$defs yet (a B4/F1b follow-up: docker exec tit-v3-spike simnibs_python
dev/build_schema.py), so the desktop's generated types don't know about them even though
this route already validates/plans them for real.
This is a documented design decision by this track (B3), not something contracts/openapi.yaml
specifies -- flagged in the B3 report for F1a/the orchestrator in case a future contract revision
wants an explicit discriminant instead.
KindNotConfigurable ¶
Bases: ValueError
Raised by :func:cls_for when an ambiguous kind's config names no class it can run.
cls_for ¶
Resolve kind (and, for an ambiguous kind, the config's own tag) to a dataclass.
An ambiguous kind is read the way its runner dispatches it: stats by its mode key
when present (:data:STATS_MODE_CLASSES), else by _type, else
GroupComparisonConfig; blender by _type only.
Parameters¶
kind : str
A :data:ALL_KINDS member (callers should 404 first for anything else).
config_body : dict
The request's raw config object (read for _type -- and, for stats,
mode -- only when kind is ambiguous; never mutated).
Returns¶
type or None
None for a :data:NO_SCHEMA_KINDS member (nothing to validate against yet).
Raises¶
KindNotConfigurable
If kind is ambiguous and _type (or its default) does not name one of its
known classes, a blender config has no _type, or a stats config's
mode is unknown or contradicts its _type.
Source code in tit/server/routes/validate.py
refuse_unknown_keys ¶
Raise :class:ValueError when config has a key /api/validate/{kind} calls unknown.
The submission routes (POST /api/jobs, /api/jobs/groups, rerun, an approved
proposal) read configs leniently, as the runners do, so a misspelled or renamed key used
to be accepted and silently ignored. This applies the validate route's strictness, with the
same envelope (project_dir) and dispatch (stats mode) keys set aside, to that one
rule: a config that is invalid for another reason is left to check_job_config, the
preflight and the runner (the analyzer and source runners still read their older layouts).
Kinds with no config class (tools, project_init) have nothing to check. A pre
key from before the FastSurfer stage (tit.pre.config.LEGACY_KEYS) is not unknown here:
the runner and POST /api/plan/pre translate it (migrate_legacy_keys), and
check_job_config checks the translated config. /api/validate itself still flags it.
Raises¶
ValueError Naming the unknown key(s) and the class's fields.