Child schemas
A schema can declare child schemas to validate nested input Mappings. Each child schema is a free-standing definition with its own fields and constraints.
Child schemas describe nested data. Schema inheritance reuses definitions. A child schema need not inherit from its parent, and a derived schema need not be used as a child schema.
Declare and supply child data
from data_canon import as_dc_instance
from data_schemer.schema_projector import SchemaProjector
definitions = {
"run": {
"variables": {"name": {"type": "String"}},
"child_schemas": ["solver", "report"],
},
"solver": {"variables": {
"iterations": {"type": "Integer", "optional": True, "default": 20},
}},
"report": {"variables": {
"filename": {"type": "String"},
}},
}
projector = SchemaProjector(definitions, schema_name="run")
projection = projector.get_projection(as_dc_instance({
"name": "example", "solver": {},
}))
assert projection.data == {"name": "example"}
assert projection.child_projections["solver"].data == {"iterations": 20}
assert projection.data_tree == {"name": "example", "solver": {"iterations": 20}}
assert "report" not in projection.child_projections
The supplied empty Mapping for solver receives defaults and validation.
The absent report entry remains absent; its required filename is not checked
until report data is supplied.
Presence is explicit
| Input child entry | Projection behavior |
|---|---|
| Absent | Leave it absent |
| Empty Mapping DataCanon Instance (DCI) | Apply defaults, then validate and project |
| Nonempty Mapping DCI | Apply defaults to absent fields, then validate and project |
| Null or another non-Mapping DCI | Reject |
A supplied Mapping can still fail because a required field has no value. Supplying a parent child Mapping does not activate absent entries for that schema’s children. The presence rule applies independently at every level.
child_schema_mode has no effect on projection. It controls only SchemaCommandLine (SCL) command
navigation. Selecting a child command supplies its Mapping even without options,
which requests the same default processing as an explicitly empty input Mapping.
Nest child schemas
definitions["solver"]["child_schemas"] = ["advanced"]
definitions["advanced"] = {"variables": {
"threshold": {"type": "Float", "optional": True, "default": 0.01},
}}
projection = SchemaProjector(definitions, schema_name="run").get_projection(
as_dc_instance({"name": "example", "solver": {"advanced": {}}})
)
advanced = projection.child_projections["solver"].child_projections["advanced"]
assert advanced.data == {"threshold": 0.01}
Validation stays local to each schema. An error for a nested DataCanon Type (DCT) mismatch
includes its full data path, such as solver.advanced.threshold.
Inspect definitions and results separately
projection.child_projections contains per-input results for supplied children.
Use a child projection’s data_dci, data_tree_dci, or get_instance() to work
with that particular input.
projector.child_projectors contains reusable compiled child projectors.
Compilation can happen during projection or through compile_child(name).
Compiling a child does not supply input or activate it in later projections.
projector = SchemaProjector(definitions, schema_name="run")
projector.compile_child("solver").compile_child("advanced")
matches = projector.find_projectors_with_paths("advanced")
assert [path for path, compiled in matches] == [("solver", "advanced")]
The search covers already compiled projectors. It preserves distinct paths when a schema definition is reused in different branches, and does not fetch external content or convert DCIs to conventional objects.
SCL places an additional restriction on command definitions: a child schema cannot be directly declared by multiple parents. Standalone projection can reuse definitions across branches; SCL rejects ambiguous command ownership.
Structural restrictions
Every declared child name must identify an existing schema. A field name
cannot also be a child-schema name at the same level. Child-schema cycles are
rejected. A schema used as a child cannot declare non-None required_file
metadata; required positional files belong to the SCL root.
The complete processed tree preserves the order of supplied child entries. For constructing objects from children, see Application construction.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.