Schema composition

Schema inheritance reuses definitions. A derived schema can adjust field properties, copy field definitions, or remove constraints. Inheritance does not create nested input data; that is the role of child schemas.

Inherit field properties

from data_canon import as_dc_instance
from data_schemer.schema_projector import SchemaProjector

definitions = {
    "base": {"variables": {
        "iterations": {
            "type": "Integer", "optional": True, "default": 20,
            "help": "Maximum iteration count",
        },
    }},
    "production": {
        "inherit": ["base"],
        "variables": {"iterations": {"default": 100}},
    },
}

projector = SchemaProjector(definitions, schema_name="production")
projection = projector.get_projection(as_dc_instance({}))
assert projection.data == {"iterations": 100}
assert projector.schema_variables["iterations"]["type"] == "Integer"

The local default replaces the inherited default while type, optional, and help remain inherited. Overrides merge field properties. Each property’s value is replaced as a whole: a new choices list replaces the inherited list, and a new Mapping default replaces the inherited Mapping default.

For inherit: ["first", "second"], the first base wins when both explicitly define the same property. The second base fills properties absent from the first. Local variables properties take precedence over every base. Implicit defaults such as optional: False are added after composition.

Copy a field definition

definitions["production"]["copy_variables"] = {"report_limit": "base@iterations"}
definitions["production"]["variables"]["report_limit"] = {
    "default": 5,
    "help": "Maximum number of reported entries",
}
projector = SchemaProjector(definitions, schema_name="production")
assert projector.get_projection(as_dc_instance({})).data == {
    "iterations": 100, "report_limit": 5,
}

copy_variables maps a destination name to "schema@field". The source field uses its resolved definition, including inheritance. A copy replaces an inherited destination definition, then local properties for the destination override the copied properties.

Same-schema copies can refer to later copy entries. Cyclic copies and cyclic schema inheritance are rejected. Copies run before removals, so a same-schema source may be copied and then removed from the final schema.

Remove properties or fields

definitions["flexible"] = {
    "inherit": ["base"],
    "delete_properties": {"iterations": ["type", "default"]},
}
projector = SchemaProjector(definitions, schema_name="flexible")
assert projector.get_projection(as_dc_instance({})).data == {}
assert projector.get_projection(as_dc_instance({"iterations": "automatic"})).data == {
    "iterations": "automatic",
}

The field remains optional, but its type constraint and default are removed. Use delete_variables: ["iterations"] to remove the whole field definition. Removing an absent field or property is an error, catching misspelled names.

Setting default to None supplies a Null DataCanon Instance (DCI) default. It does not remove a default. Use delete_properties for removal.

Resolution order

For each schema, DataSchemer (DS) composes inherited field properties, applies local overrides and copies, then removes properties and fields. The copied destination always receives its local overrides after the copy. Implicit property defaults and final validation follow composition and removal.

The schema’s original definition dictionaries are not modified by field resolution. A schema_variables property returns a copy of the compiled metadata.

update_variables has been removed. Put property overrides directly under variables. An occurrence of update_variables, including an empty Mapping, raises a migration error.

Other inherited metadata

child_schemas accumulates in base order, followed by locally declared names, with duplicates removed. conflicts includes inherited groups.

print_attribute has its own merge rules for output configuration, including extending lists of choices and exclusions. Those rules are separate from ordinary field-property replacement; see the behavioral reference.