Getting Started

DataSchemer (DS) validates DataCanon Instances (DCIs) against an application’s schema. A DCI is a value in the DataCanon data model. The same schema can serve a Python interface, configuration files, and SchemaCommandLine (SCL).

Follow the installation instructions first. This example uses DataCanon and NumPy alongside DS.

Define the expected input

Suppose an application needs a matrix, an iteration count, and a tolerance.

schema = {
    "variables": {
        "matrix": {},
        "iterations": {"type": "Integer"},
        "tolerance": {"type": "Float", "optional": True, "default": 1e-8},
    },
}

Fields are required unless marked optional. A type constraint is optional: matrix can be any DCI, while iterations must be an Integer DCI. The application will choose how to turn the matrix data into its preferred numerical container.

Supply a DCI and project it

from data_canon import as_dc_instance
from data_schemer.schema_projector import SchemaProjector

input_dci = as_dc_instance({
    "matrix": [[2, -1], [-1, 2]],
    "iterations": 20,
})

projector = SchemaProjector(schema)
projection = projector.get_projection(input_dci)

assert projection.input_dci is input_dci
assert projection.data_dci == as_dc_instance({
    "matrix": [[2, -1], [-1, 2]],
    "iterations": 20,
    "tolerance": 1e-8,
})

The original input remains available through input_dci. The processed data_dci includes the default tolerance. Unknown fields, missing required fields, and incorrect declared DataCanon Types (DCTs) raise user-facing errors.

Access conventional objects

data = projection.data
print(data)
{'matrix': [[2, -1], [-1, 2]], 'iterations': 20, 'tolerance': 1e-08}

data converts the processed fields to instances of conventional Python types. Here those types are dict, list, int, and float. The authoritative processed DCI remains available separately through data_dci.

Construct the application object

import numpy as np

class Calculation:
    def __init__(self, matrix, iterations, tolerance):
        self.matrix = np.asarray(matrix, dtype=np.float64)
        self.iterations = iterations
        self.tolerance = tolerance

calculation = projection.get_instance(Calculation)

assert calculation.matrix.shape == (2, 2)
assert calculation.matrix.dtype == np.dtype("float64")
assert calculation.iterations == 20
assert calculation.tolerance == 1e-8

DS selects the constructor arguments and converts their DCIs. Calculation chooses its own array representation. A nested List DCI or an Array DCI can therefore serve as the matrix input without a DS-specific matrix type.

Use the same schema with SCL

from data_schemer.schema_command_line import SchemaCommandLine

scl = SchemaCommandLine(
    schema,
    argv=["--matrix", "[[2, -1], [-1, 2]]", "--iterations", "20"],
    target_class=Calculation,
)

assert scl.target_obj.iterations == 20
assert scl.data_dci == projection.data_dci

SCL parses the option values as DataCanon Shorthand before calling the same schema processor. A program normally omits argv to use its actual command line.

Continue