zcbor - CDDL Code Generation and Data Validation
zcbor is a Python library for code generation and data validation based on CDDL (Concise Data Definition Language) schemas. It enables developers to generate Python code for encoding and decoding CBOR (Concise Binary Object Representation) data, ensuring compliance with specified CDDL schemas. The library is currently at version 0.9.1 and receives updates periodically, with significant releases often including migration guides for breaking changes.
Warnings
- breaking The library was renamed from `cddl-gen` to `zcbor` starting with version 0.4.0. Users upgrading from `cddl-gen` will need to update their `pip install` commands and import paths.
- breaking In version 0.8.0, the order of command-line arguments for `zcbor.main` was swapped. Previously (pre-0.8.0), it expected `output_path` then `input_path` (CDDL file). It now expects `input_path` (CDDL file) then `output_path`.
- breaking As of version 0.9.0, the names of the generated encode/decode functions in the output Python files have changed from `CamelCaseEncode`/`CamelCaseDecode` to `snake_case_encode`/`snake_case_decode`.
- breaking Starting from version 0.9.0, the `any` type in CDDL schemas is explicitly unsupported and will cause compilation errors. This change improves type safety and generated code quality.
Install
-
pip install zcbor
Imports
- cli
from zcbor.main import cli
- encode, decode
from zcbor.zcbor import encode, decode
Quickstart
import os
import subprocess
import sys
import shutil
# 1. Define a simple CDDL schema in a temporary file
cddl_schema_content = """
my_map = {
? "label" => tstr,
? "value" => int,
}
"""
schema_file = "my_schema.cddl"
with open(schema_file, "w") as f:
f.write(cddl_schema_content)
output_dir = "generated_code"
# Clean up previous runs if any
if os.path.exists(output_dir):
shutil.rmtree(output_dir)
os.makedirs(output_dir, exist_ok=True)
print(f"Generating code from {schema_file} into {output_dir}...")
# 2. Run zcbor to generate Python code using the command-line interface
try:
# Use sys.executable to ensure the correct Python environment's zcbor is used
result = subprocess.run(
[sys.executable, "-m", "zcbor.main", schema_file, output_dir],
capture_output=True,
check=True,
text=True
)
print("Code generation successful.")
except subprocess.CalledProcessError as e:
print(f"Error during code generation: {e}")
print("STDERR:", e.stderr)
sys.exit(1)
# Add the output directory to the Python path to import generated modules
sys.path.insert(0, output_dir)
try:
# 3. Import from the generated code and use encode/decode
# The generated module name will typically be the CDDL filename without extension, lowercased.
# Function names are snake_case from v0.9.0 onwards.
from my_schema import my_map_encode, my_map_decode
data = {"label": "test", "value": 123}
print(f"Original data: {data}")
encoded_cbor = my_map_encode(data)
print(f"Encoded CBOR (hex): {encoded_cbor.hex()}")
decoded_data, _ = my_map_decode(encoded_cbor) # decode returns (data, remaining_bytes)
print(f"Decoded data: {decoded_data}")
assert data == decoded_data
print("Encoding and decoding successful and data matches.")
except ImportError as e:
print(f"Could not import generated module: {e}")
print("Ensure zcbor.main successfully generated 'my_schema.py' in the 'generated_code' directory.")
except Exception as e:
print(f"An error occurred during encoding/decoding: {e}")
finally:
# Clean up temporary files and directories
if os.path.exists(schema_file):
os.remove(schema_file)
if os.path.exists(output_dir):
shutil.rmtree(output_dir)
# Remove from sys.path
if output_dir in sys.path:
sys.path.remove(output_dir)