{"id":26989930,"url":"https://github.com/telecominfraproject/oopt-gnpy-libyang","last_synced_at":"2025-04-03T21:22:55.605Z","repository":{"id":40256795,"uuid":"439142970","full_name":"Telecominfraproject/oopt-gnpy-libyang","owner":"Telecominfraproject","description":"Opinionated Python bindings for the libyang library","archived":false,"fork":false,"pushed_at":"2025-04-02T18:57:30.000Z","size":118,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":24,"default_branch":"main","last_synced_at":"2025-04-02T19:28:12.593Z","etag":null,"topics":["python","python-3","yang"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Telecominfraproject.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-16T22:25:20.000Z","updated_at":"2024-10-08T03:46:51.000Z","dependencies_parsed_at":"2023-02-18T20:15:33.897Z","dependency_job_id":"ba94bdce-012f-4de0-bf0e-ac6543434763","html_url":"https://github.com/Telecominfraproject/oopt-gnpy-libyang","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Telecominfraproject%2Foopt-gnpy-libyang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Telecominfraproject%2Foopt-gnpy-libyang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Telecominfraproject%2Foopt-gnpy-libyang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Telecominfraproject%2Foopt-gnpy-libyang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Telecominfraproject","download_url":"https://codeload.github.com/Telecominfraproject/oopt-gnpy-libyang/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247079609,"owners_count":20880078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["python","python-3","yang"],"created_at":"2025-04-03T21:22:54.947Z","updated_at":"2025-04-03T21:22:55.599Z","avatar_url":"https://github.com/Telecominfraproject.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Opinionated Python bindings for the `libyang` library\n\n[![Install via pip](https://img.shields.io/pypi/v/oopt-gnpy-libyang)](https://pypi.org/project/oopt-gnpy-libyang/)\n[![Python versions](https://img.shields.io/pypi/pyversions/oopt-gnpy-libyang)](https://pypi.org/project/oopt-gnpy-libyang/)\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Telecominfraproject/oopt-gnpy-libyang/ci.yaml)](https://github.com/Telecominfraproject/oopt-gnpy-libyang/actions/workflows/ci.yaml)\n\nPython bindings and packaging of [`libyang`](https://github.com/CESNET/libyang).\nWe're focusing on parsing, validating and accessing YANG-modeled JSON data trees.\nEssentially, just enough to get [`gnpy`](https://github.com/Telecominfraproject/oopt-gnpy) going.\nWant more?\nPatches welcome.\n\nCompared to the [CFFI libyang bindings](https://github.com/CESNET/libyang-python), this wrapper takes care of low-level memory management.\nThis means no more `node.free()` and `ctx.destroy()`.\nWe also produce prebuilt binary [wheels](https://realpython.com/python-wheels/) to make installation very simple.\n\n## Usage\n\n### Loading YANG data\n\n```python\nimport oopt_gnpy_libyang as ly\n\nc = ly.Context('tests/yang', ly.ContextOptions.AllImplemented | ly.ContextOptions.NoYangLibrary)\nfor m in ('iana-if-type', 'ietf-interfaces', 'ietf-ip'):\n    c.load_module(m)\nblob = '''{\n  \"ietf-interfaces:interfaces\": {\n    \"interface\": [\n      {\n        \"name\": \"lo\",\n        \"type\": \"iana-if-type:softwareLoopback\",\n        \"ietf-ip:ipv4\": {\n          \"address\": [\n            {\n              \"ip\": \"127.0.0.1\",\n              \"prefix-length\": 8\n            }\n          ]\n        },\n        \"ietf-ip:ipv6\": {\n          \"address\": [\n            {\n              \"ip\": \"::1\",\n              \"prefix-length\": 128\n            }\n          ]\n        }\n      },\n      {\n        \"name\": \"eth0\",\n        \"type\": \"iana-if-type:ethernetCsmacd\"\n      }\n    ]\n  }\n}'''\n\ndata = c.parse_data(blob,\n    ly.DataFormat.JSON, ly.ParseOptions.Strict | ly.ParseOptions.Ordered,\n    ly.ValidationOptions.Present | ly.ValidationOptions.NoState)\n```\n### Working with data\n\nLibyang works with forests (sets of trees), this is how to process all the data:\n```python\nfor x in data.siblings():\n    print(f'a sibling: {x.path}')\n    for xx in x.children_dfs():\n        print(f' {\"term \" if xx.is_term else \"child\"}: {xx.path}')\n        if xx.is_term:\n            print(f'  {xx.as_term()} {\" (default)\" if xx.as_term().is_default_value else \"\"}')\n```\nData can be accessed via their known paths, of course. Either as a full, multi-level XPath:\n\n```python\ndata[\"interface[name='lo']/ietf-ip:ipv6/address[ip='::1']/prefix-length\"].as_term().value == 128\n```\nOr individually, one item per index:\n```python\ndata[\"interface[name='lo']\"][\"ietf-ip:ipv6\"][\"address[ip='::1']\"][\"prefix-length\"].as_term().value\n```\nEverything is an XPath, so it's possible to take a shortcut and skip specifying keys for single-element lists:\n```python\ndata[\"interface[name='lo']\"][\"ietf-ip:ipv6\"][\"address\"][\"prefix-length\"].as_term().value == 128\n```\nThe data are provided as native Python types:\n```python\ntype(data[\"interface[name='lo']\"][\"ietf-ip:ipv6\"][\"address\"][\"prefix-length\"]\n    .as_term().value) == int\n```\nAbsolute paths and generic XPath expressions can be used to retrieve arbitrary parts of the data forest, and to iterate over them:\n```python\nfor iface in data.find(\"/ietf-interfaces:interfaces/interface\"):\n    print iface[\"name\"].as_term().value\n```\nRelative XPath conditions can be also used at the root level (which is represented as NULL in the C level):\n```python\nfor iface in search_at_root(data)(\"ietf-interfaces:interfaces/interface\"):\n    print iface[\"name\"].as_term().value\n```\nNew values can be created; use `None` for non-terminals, or `str` when a value is needed:\n```python\nnode = ctx.create(\"/ietf-interfaces:interfaces/interface[name='666']\")\nanother = ctx.create(\"/ietf-interfaces:interfaces/interface[name='666']/ietf-ip:ipv6/enabled\", \"true\")\ndata[\"interface[name='lo']\"][\"ietf-ip:ipv6\"][\"address\"][\"prefix-length\"] = \"64\"\n```\n\n### Validation errors\nIn libyang, if an operation fails, error details are available via `context.errors()`:\n```python\nimport json\nwrong = json.loads(blob)\nwrong[\"ietf-interfaces:interfaces\"][\"interface\"][0]\\\n    [\"ietf-ip:ipv6\"][\"address\"][0][\"prefix-length\"] = 666\ntry:\n    data = c.parse_data(json.dumps(wrong),\n        ly.DataFormat.JSON, ly.ParseOptions.Strict | ly.ParseOptions.Ordered,\n        ly.ValidationOptions.Present | ly.ValidationOptions.NoState)\n    assert False\nexcept ly.Error:\n    for error in c.errors():\n        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.\"\n        assert error.message == 'Value \"666\" is out of type uint8 min/max bounds.'\n```\n\n## Installing\n\nWe're producing wheels for many popular platforms.\nThe installation is as simple as:\n```console-session\n$ pip install oopt-gnpy-libyang\n```\n\n### Building from source\n\nSince this library is a Python wrapper around a C++ wrapper around a C library, source-based builds are more complex.\nThey require:\n\n- a C++20 compiler (e.g., GCC 10+, clang 10+, MSVC 17.2+)\n- [`libyang`](https://github.com/CESNET/libyang) and its dependencies\n- [`libyang-cpp`](https://github.com/CESNET/libyang-cpp/) and its dependencies\n- [CMake](https://cmake.org/) 3.21+\n\nUnlike 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.\nAlso, in a from-source build these won't be bundled into the resulting package.\nFor an inspiration, consult our [GitHub packaging recipes](./.github/workflows/ci.yaml).\n\n## License\n\nCopyright © 2021-2023 Telecom Infra Project and GNPy contributors.\nLicensed under the [3-clause BSD license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftelecominfraproject%2Foopt-gnpy-libyang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftelecominfraproject%2Foopt-gnpy-libyang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftelecominfraproject%2Foopt-gnpy-libyang/lists"}