nodl_schema

nodl_schema is the home of the canonical NoDL schema, plus a Python package that validates NoDL documents and exposes a typed, in-memory data model for working with them.

For what a NoDL document means and what it declares, see NoDL Concepts. For the field-by-field schema reference, see NoDL Schema reference. This page documents the package’s Python surface and how to use it.

What it provides

  • The canonical schema files at nodl_schema/nodl_schema/schemas/nodl.schema.yaml, shipped with the package.

  • A validator that checks plain documents against that schema.

  • A typed data model (pydantic models) so loaded documents are structured objects, not bare dicts.

  • Include resolution for nodl:// ament index resources and local:// relative paths.

Python API

The public API is re-exported from the package root:

from nodl_schema import load_nodl, dump_nodl, load_schema, validate

load_nodl(source, *, resolve=True) -> NodlDocument

Load and validate a NoDL document from a string, bytes, or file-like object, returning a typed NodlDocument. Raises a validation error if the document does not conform to the schema.

If resolve=True, each include reference is resolved and merged in (see Composition), returning a document with the full interface and no include.

from nodl_schema import load_nodl

with open('my_node.nodl.yaml') as f:
    doc = load_nodl(f)

for name, parameter in (doc.parameters or {}).items():
    print(name, parameter.type)

validate(data) -> None

Validate a plain dict against the NoDL JSON schema, raising on the first violation. Use this when you already have parsed data and only need the conformance check, not the typed model.

dump_nodl(doc, *, format='yaml') -> str

Serialize a NodlDocument (or a plain dict) back to a YAML or JSON string. None fields are dropped and enums are unwrapped to their values, so the output round-trips through load_nodl.

load_schema() -> dict

Load and cache the raw NoDL JSON schema as a dict, for tools that want to inspect the schema directly.

Composition: the include key

A document can pull in the interface of other NoDL documents through a top-level include list. Each entry is resolved, validated, and merged into the including document when it is loaded:

nodl_version: 2
include:
  - ref: nodl://sensor_common/imu_driver
publishers:
  - name: /status
    type: std_msgs/msg/String
    qos: {history: SYSTEM_DEFAULT, reliability: SYSTEM_DEFAULT}

ref is a URI whose scheme selects the resolver that fetches the document. nodl://<package>/<name> is the built-in form, resolved through the ament index.

Includes are followed recursively. Double-inclusions of the same reference (including cycles) are rejected. The same entity type with the same name declared twice is an error. Resolution failures raise ResolutionError, and collisions raise MergeError.

Code generation metadata: the codegen key

A document can carry an optional codegen field with opaque metadata for code generation tools. The field is keyed by target language or tool (e.g. cpp, python). Each value is an object whose contents are tool-defined and the NoDL schema does not constrain them:

nodl_version: 2
codegen:
  cpp:
    role: base_class
    header: rclcpp/rclcpp.hpp
    class: rclcpp::Node

publishers:
  - name: /rosout
    type: rcl_interfaces/msg/Log
    qos: {history: KEEP_LAST, depth: 1000, reliability: RELIABLE}

nodl_schema validates that codegen is an object of objects, but does not inspect the contents. Interpretation is left to the consuming code generation tool.

Data model

The typed model lives in nodl_schema/nodl_schema/models.py. NodlDocument is the document root; it holds the node’s parameters and its topic, service, and action endpoints, each as its own model (ParameterDefinition, TopicEndpoint, ServiceEndpoint, ActionEndpoint, QosProfile). The interface concepts these models represent are described in NoDL Concepts.