Skip to main content

A Python library implementing a subset of YANG features focused on constraint validation

Project description

xYang

YANG models, validated JSON, and JSON Schema—without dragging in a full management stack.

xYang is a pure-Python library and CLI for parsing YANG 1.1-shaped modules, validating instance data against the full set of RFC 7950 built-in types (each checked with the right rules—ranges, length/pattern, base64 binary, bits, union disambiguation, leafref / identityref / instance-identifier resolution, and the rest), plus must, when, if-feature, and structure. It exports a standards-friendly JSON Schema (2020-12) layer augmented with x-yang metadata for round-trip where supported. It is built for real modules (reference design: examples/meta-model.yang), including deep XPath: deref() tied to schema paths, union typing, and current() in list and leaf-list contexts.

  • Zero required runtime dependencies — drop into apps, agents, and pipelines with minimal footprint.
  • Honest scope — not every RFC 7950 statement is modeled; what is implemented is described precisely in FEATURES.md (including import / include, if-feature, anydata / anyxml, and JSON if-features round-trip). Constructs such as rpc, notification, and deviation are recognized and skipped with a log warning so mixed modules still parse.
  • MIT licensed — use it in products and internal tools alike.

Repository: github.com/exergy-connect/xYang · Issues: github.com/exergy-connect/xYang/issues


Features (overview)

The list below is the short version; FEATURES.md is the authoritative, line-by-line feature matrix and documents the YANG.json hybrid format.

  • Module structure: module / submodule, yang-version, namespace, prefix, metadata, revision, import, include, feature
  • Types: All RFC 7950 built-in types (Section 4.2.4) are supported and validated on instance data—string, binary, numeric types, decimal64, boolean, empty, enumeration, bits, union, leafref, identityref, and instance-identifier—with applicable substatements (length, range, pattern, fraction-digits, require-instance, etc.). typedef and imports compose these. Statement-level scope (e.g. skipped rpc / notification) and JSON Schema details: FEATURES.md.
  • Data nodes: container, list + key, leaf, leaf-list, choice / case, anydata / anyxml, grouping / uses / refine, augment (merge when uses expansion is enabled)
  • Constraints: must, when, if-feature, mandatory, default, min-elements / max-elements, pattern, length, range, fraction-digits
  • References: leafref (+ require-instance), instance-identifier, identityref, identity / base, XPath derived-from() / derived-from-or-self()
  • Interop: xyang CLI (parse, validate, convert) and JSON Schema export with x-yang annotations for generator/parser round-trip where supported

Installation

From PyPI (when published):

pip install xyang

From a checkout (editable, for development):

pip install -e .

There are no required runtime dependencies. For xyang validate with .yaml / .yml instance files, install PyYAML (pip install PyYAML or pip install -e ".[dev]").

Requirements: Python ≥ 3.9 (see pyproject.toml).


Usage

Command-line (xyang)

xyang -h                    # help
xyang parse <file.yang>     # print module info
xyang validate <file.yang> [data.json]  # or .yaml/.yml (needs PyYAML); omit file → JSON from stdin
xyang convert <file.yang> [-o path]     # YANG → .yang.json (output path ends with .yang.json)

Without installing the package, from the repo root: PYTHONPATH=src python3 -m xyang -h

Parsing a YANG module

from xyang import parse_yang_file, parse_yang_string

# Parse from file
module = parse_yang_file("examples/meta-model.yang")

# Parse from string
yang_content = """
module example {
  yang-version 1.1;
  namespace "urn:example";
  prefix "ex";
  
  container data {
    leaf name {
      type string;
    }
  }
}
"""
module = parse_yang_string(yang_content)

print(f"Module: {module.name}")
print(f"Namespace: {module.namespace}")
print(f"Prefix: {module.prefix}")

Validating data

from xyang import parse_yang_file, YangValidator

module = parse_yang_file("examples/meta-model.yang")
validator = YangValidator(module)

# Consolidated JSON document: one tree matching your module’s data layout.
# XPath comparisons use schema-aware coercion (e.g. string "true" vs boolean leaves).
data = {
    "data-model": {
        "name": "example",
        "entities": [
            {
                "name": "server",
                "fields": [
                    {"name": "id", "type": "string"}
                ]
            }
        ]
    }
}

is_valid, errors, warnings = validator.validate(data)
if not is_valid:
    for error in errors:
        print(f"Error: {error}")

Optional: anydata subtree validation

An add-on in xyang.ext for optional validation of JSON under anydata per draft-ietf-netmod-yang-anydata-validation. See examples/anydata_validation_usage.py and FEATURES.md.

Working with types

from xyang import TypeConstraint, TypeSystem

type_system = TypeSystem()
constraint = TypeConstraint(
    pattern=r'[a-z_][a-z0-9_]*',
    length="1..64"
)
type_system.register_typedef("entity-name", "string", constraint)

is_valid, error = type_system.validate("server_name", "entity-name")
print(f"Valid: {is_valid}")

Converting YANG → JSON Schema (.yang.json)

Valid JSON Schema for structure and types; YANG-only rules (must, when, leafref paths, if-features, …) ride in x-yang. Details: FEATURES.md — YANG.json hybrid format.

from xyang.parser import YangParser
from xyang.json import schema_to_yang_json

parser = YangParser(expand_uses=False)
module = parser.parse_file("examples/meta-model.yang")
schema_to_yang_json(module, output_path="meta-model.yang.json")

CLI: xyang convert examples/meta-model.yang -o meta-model.yang.json


Project layout

xYang/
├── src/xyang/
│   ├── __init__.py      # Package exports
│   ├── __main__.py      # CLI (parse, validate, convert)
│   ├── parser/          # YANG parser (incl. unsupported-statement skip)
│   ├── json/            # JSON Schema generator + parser
│   ├── validator/       # Document validation
│   ├── xpath/           # XPath for must/when
│   ├── ast.py           # AST nodes
│   ├── types.py         # Type system
│   ├── module.py        # Module model
│   └── errors.py
├── examples/            # meta-model.yang, samples, generated .yang.json
├── tests/
├── benchmarks/
├── FEATURES.md          # Full feature list & format spec
├── pyproject.toml
└── README.md

XPath (schema-aware)

Coverage matches what meta-model.yang needs, evaluated with schema context (not a generic XPath 1.0 engine):

  • Paths: ../field, ../../field, absolute paths such as /data-model/entities
  • Functions: string(), number(), concat(), string-length(), translate(), count(), deref(), current(), not(), true(), false(), boolean(), derived-from(), derived-from-or-self(), …
  • Comparisons & logic: =, !=, <=, >=, <, >, and, or
  • Literal sequences (xYang extension): RHS ('a', 'b') for membership-style equality
  • Predicates & indexing: e.g. [name = current()], [1]
  • String concat: + between strings in expressions

deref() on leafref values follows the leafref’s schema path to resolve the target node; it supports nesting, caching, and cycle detection for the patterns used in production modules here.


When & must (examples)

When — if the condition is false, the node is out of the effective schema; data there is reported as invalid:

container item_type {
  when "../type = 'array'";
  leaf primitive { type string; }
}

Must — XPath must evaluate true or validation fails (with error-message when provided):

leaf minDate {
  type date;
  must "not(../maxDate) or . <= ../maxDate" {
    error-message "minDate must be less than or equal to maxDate";
  }
}

Scope & limitations

  • Single JSON instance — validation is against one consolidated document, not NETCONF/XML fragments or incremental edits.
  • XPath subset — unsupported expressions fail at XPath parse time (UnsupportedXPathError). Extend the evaluator to add features.
  • deref() — fully handled for meta-model-style patterns; it remains schema-coupled by design, not a standalone generic resolver.
  • RFC surface — see FEATURES.md for what is partial, skipped, or out of scope; the parser warns when it skips unsupported top-level-like statements.

Design choices

No mandatory third-party stack — core package dependencies are empty in pyproject.toml; optional PyYAML only for YAML instances on the CLI. That keeps xYang easy to embed and audit.


Development

pip install -e ".[dev]"
pytest
black src/xyang/

License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xyang-0.1.1.tar.gz (144.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xyang-0.1.1-py3-none-any.whl (122.2 kB view details)

Uploaded Python 3

File details

Details for the file xyang-0.1.1.tar.gz.

File metadata

  • Download URL: xyang-0.1.1.tar.gz
  • Upload date:
  • Size: 144.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for xyang-0.1.1.tar.gz
Algorithm Hash digest
SHA256 5a889228624d559dbb8c0853b0e319843f0afb75dcb91ffb8c1a164f9614d210
MD5 785e83e41f8427d8d00718a996d9506b
BLAKE2b-256 a13992bea0636e8c9deb317af97324416f5489782a342dd8ddee3ea612c68271

See more details on using hashes here.

Provenance

The following attestation bundles were made for xyang-0.1.1.tar.gz:

Publisher: publish-pypi.yml on exergy-connect/xYang

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file xyang-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: xyang-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 122.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for xyang-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1526f67a8a0cb238fcc445798466fb512cf2d23caca1c424a02b77c01ec79713
MD5 fd41df73795ced8edc7c0fa5e976e4fa
BLAKE2b-256 d140270dd4891be718778c601ba3bfe2eb5539f6a1be645096f37fdf9773f0b3

See more details on using hashes here.

Provenance

The following attestation bundles were made for xyang-0.1.1-py3-none-any.whl:

Publisher: publish-pypi.yml on exergy-connect/xYang

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page