Opinionated Python bindings for the libyang library
Project description
Opinionated Python bindings for the libyang
library
Python bindings and packaging of libyang
.
We're focusing on parsing, validating and accessing YANG-modeled JSON data trees.
Essentially, just enough to get gnpy
going.
Want more?
Patches welcome.
Compared to the CFFI libyang bindings, this wrapper takes care of low-level memory management.
This means no more node.free()
and ctx.destroy()
.
We also produce prebuilt binary wheels to make installation very simple.
Usage
Loading YANG data
import oopt_gnpy_libyang as ly
c = ly.Context('tests/yang', ly.ContextOptions.AllImplemented | ly.ContextOptions.NoYangLibrary)
for m in ('iana-if-type', 'ietf-interfaces', 'ietf-ip'):
c.load_module(m)
blob = '''{
"ietf-interfaces:interfaces": {
"interface": [
{
"name": "lo",
"type": "iana-if-type:softwareLoopback",
"ietf-ip:ipv4": {
"address": [
{
"ip": "127.0.0.1",
"prefix-length": 8
}
]
},
"ietf-ip:ipv6": {
"address": [
{
"ip": "::1",
"prefix-length": 128
}
]
}
},
{
"name": "eth0",
"type": "iana-if-type:ethernetCsmacd"
}
]
}
}'''
data = c.parse_data(blob,
ly.DataFormat.JSON, ly.ParseOptions.Strict | ly.ParseOptions.Ordered,
ly.ValidationOptions.Present | ly.ValidationOptions.NoState)
Working with data
Libyang works with forests (sets of trees), this is how to process all the data:
for x in data.siblings():
print(f'a sibling: {x.path}')
for xx in x.children_dfs():
print(f' {"term " if xx.is_term else "child"}: {xx.path}')
if xx.is_term:
print(f' {xx.as_term()} {" (default)" if xx.as_term().is_default_value else ""}')
Data can be accessed via their known paths, of course. Either as a full, multi-level XPath:
data["interface[name='lo']/ietf-ip:ipv6/address[ip='::1']/prefix-length"].as_term().value == 128
Or individually, one item per index:
data["interface[name='lo']"]["ietf-ip:ipv6"]["address[ip='::1']"]["prefix-length"].as_term().value
Everything is an XPath, so it's possible to take a shortcut and skip specifying keys for single-element lists:
data["interface[name='lo']"]["ietf-ip:ipv6"]["address"]["prefix-length"].as_term().value == 128
The data are provided as native Python types:
type(data["interface[name='lo']"]["ietf-ip:ipv6"]["address"]["prefix-length"]
.as_term().value) == int
Absolute paths and generic XPath expressions can be used to retrieve arbitrary parts of the data forest, and to iterate over them:
for iface in data.find("/ietf-interfaces:interfaces/interface"):
print iface["name"].as_term().value
Relative XPath conditions can be also used at the root level (which is represented as NULL in the C level):
for iface in search_at_root(data)("ietf-interfaces:interfaces/interface"):
print iface["name"].as_term().value
New values can be created; use None
for non-terminals, or str
when a value is needed:
node = ctx.create("/ietf-interfaces:interfaces/interface[name='666']")
another = ctx.create("/ietf-interfaces:interfaces/interface[name='666']/ietf-ip:ipv6/enabled", "true")
data["interface[name='lo']"]["ietf-ip:ipv6"]["address"]["prefix-length"] = "64"
Validation errors
In libyang, if an operation fails, error details are available via context.errors()
:
import json
wrong = json.loads(blob)
wrong["ietf-interfaces:interfaces"]["interface"][0]\
["ietf-ip:ipv6"]["address"][0]["prefix-length"] = 666
try:
data = c.parse_data(json.dumps(wrong),
ly.DataFormat.JSON, ly.ParseOptions.Strict | ly.ParseOptions.Ordered,
ly.ValidationOptions.Present | ly.ValidationOptions.NoState)
assert False
except ly.Error:
for error in c.errors():
assert error.path == "Schema location \"/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address/prefix-length\", data location \"/ietf-ip:address[ip='::1']\", line number 1."
assert error.message == 'Value "666" is out of type uint8 min/max bounds.'
Installing
We're producing wheels for many popular platforms. The installation is as simple as:
$ pip install oopt-gnpy-libyang
Building from source
Since this library is a Python wrapper around a C++ wrapper around a C library, source-based builds are more complex. They require:
- a C++20 compiler (e.g., GCC 10+, clang 10+, MSVC 17.2+)
libyang
and its dependencieslibyang-cpp
and its dependencies- CMake 3.21+
Unlike the wheels already bundle all the required libraries, when building from source, libyang
, libyang-cpp
and all their dependencies will have to be installed first.
Also, in a from-source build these won't be bundled into the resulting package.
For an inspiration, consult our GitHub packaging recipes.
License
Copyright © 2021-2023 Telecom Infra Project and GNPy contributors. Licensed under the 3-clause BSD license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for oopt_gnpy_libyang-0.0.11-cp311-cp311-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 04cf2ee6d966cebbaee33cce92bf565fcefe9ccf9276756f140e3dcadac3a3d1 |
|
MD5 | 4f954d179a24ebcf2edd10435b2a9d7f |
|
BLAKE2b-256 | 0ad4c914f71e6b9ef91c3468936c32ed1b79e8bacba149a0059e48abe98dc46d |
Hashes for oopt_gnpy_libyang-0.0.11-cp311-cp311-manylinux_2_35_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e2558e79bf8c2768162c45be3c3cb0425b4b21dcb337f480042c1f3c2438c0f7 |
|
MD5 | 832647322ef3bb16f53b0b24e1311908 |
|
BLAKE2b-256 | 98b0cf54e2c0cbb12edd31a27a366c84a61a475242770e221448a245534d6e79 |
Hashes for oopt_gnpy_libyang-0.0.11-cp311-cp311-macosx_12_0_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 802bb9ab919cef1a29d675dc3a29ba29efdb3eaf8748bfd95578760f199c326b |
|
MD5 | 802f1b87d17a12c7584a214344a4eb4b |
|
BLAKE2b-256 | f50f3330a5d9f1a978da1ee186dc6dd077482d0a94a14fb467b13a355f385093 |
Hashes for oopt_gnpy_libyang-0.0.11-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6cb57f7d1b565824bc9c74b79c94cce6b2f57325e6ff1b7330ade564c4e7fefb |
|
MD5 | 1c14bba7c9cad3791a6119ed212b2685 |
|
BLAKE2b-256 | ed56b5e3d10d6d6ef14e92def74cdce9d92ecd7f8628e1e5a2da710dd5eb2ab7 |
Hashes for oopt_gnpy_libyang-0.0.11-cp310-cp310-manylinux_2_31_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5f0a305da24d18f6bbe71666bcdd65d0341f92c7e571fcc617f5fd3810eed5d0 |
|
MD5 | 64aa0bb6856d7c0d597472f9cc752dbc |
|
BLAKE2b-256 | fb4914ab48372c768500d6233852a4565023cb9c7749f7674ec0aca572402d72 |
Hashes for oopt_gnpy_libyang-0.0.11-cp310-cp310-macosx_12_0_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b2a1788c8887540cd2679fe7b58a969d7e1ed3b0927af79ef084b87171384ca9 |
|
MD5 | 3ce56ce5b451c68ebb558cd7a8816904 |
|
BLAKE2b-256 | a88bf888a5d4308de0e2a6f2f59e8d5fd868c5750fd64eacdf7bca6397133d4e |
Hashes for oopt_gnpy_libyang-0.0.11-cp39-cp39-manylinux_2_31_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3de155de9197b92996fdce0bbcaebdade96b4f9c5c230aa9658ab6219565b646 |
|
MD5 | f02679fd4b193c0d77fac8772c9f62f7 |
|
BLAKE2b-256 | 17a82c535d85643dd179cb7db1ebf10652a26669bad53f7a8fd6b9df5784e0ba |
Hashes for oopt_gnpy_libyang-0.0.11-cp38-cp38-manylinux_2_31_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d20f7bf8078e2ad540131bfe9cf1b104eafbea3bcf3693610e1ca0514b6f4f39 |
|
MD5 | 65f2c81a2e28d78e78934a4ebaaaec5b |
|
BLAKE2b-256 | 74df81c19ea7141199eb912dfcf3987233ef5dc3f5eefe4325325e779fe51d26 |