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 (
pydanticmodels) so loaded documents are structured objects, not bare dicts.A
python -m nodl_schema <file>entry point for quick command-line validation.
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, resolver=None) -> 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 the document has an include list, each reference is resolved and merged in (see the Composition section below);
the returned document carries the combined interface and no include. Pass resolve=False to parse the document
exactly as authored, following nothing.
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 a reference that is resolved, validated, and merged into the including document when it is loaded:
nodl_version: 2
include:
- ref: nodl://sensor_common/imu_driver # resolved through the ament index
- ref: common/telemetry.nodl.yaml # a document in this package, relative to this file
publishers:
- name: /status
type: std_msgs/msg/String
qos: {history: SYSTEM_DEFAULT, reliability: SYSTEM_DEFAULT}
Two reference forms are accepted:
nodl://<package>/<name>resolves through the ament index to the document registered byament_nodl_register_nodeas the resourcenodl_nodes/<package>__<name>.A relative path resolves against the directory of the document holding the reference. It names a document in the same package, and is the only form that can reach a document in the package currently being built, since it reads the source tree rather than an installed workspace. Pass
load_nodl(..., base=<path the text came from>)so relative references have something to resolve against; an open file supplies it automatically.
Includes are followed recursively. The merge is strict: a name collision within any single category (two publishers
named /status, two parameters named gain, and so on) across the document and its includes is an error. A publisher
and a subscription may share a name, since they are different categories. Include cycles are detected and rejected.
Relative references do not survive installation: ament_nodl_register_node rewrites them to their nodl:// form, so a
document read back out of the index never contains one. local_references and rewrite_references are the two entry
points it uses, and are exposed for tooling that needs the same information.
Resolution is pluggable. load_nodl(..., resolver=...) accepts anything satisfying the Resolver protocol
(fetch(ref) -> str); the default DefaultResolver handles nodl:// and the file:// references that relative paths
normalize to. A reference is normalized against its document’s origin before it is fetched, so adding a reference form
later means teaching a resolver a new scheme and nothing else. resolve_document(data, resolver) exposes the merge
directly for callers working with plain dicts. Resolution failures and collisions raise CompositionError.
from nodl_schema import load_nodl, resolve_document, DefaultResolver, CompositionError
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.
Command line¶
For one-off validation without writing code:
python -m nodl_schema my_node.nodl.yaml
For validation as part of a ROS 2 workflow, prefer the ros2 nodl validate command from the ros2nodl package.