Skip to content

Commit 7c06d53

Browse files
committed
data: add support of anydata into dict_to_dnode
This patch adds support of anydata within dict_to_dnode. To do that new options were introduced into dict_to_dnode() API Signed-off-by: Stefan Gula <[email protected]>
1 parent 1c6919b commit 7c06d53

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

cffi/cdefs.h

+1
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,7 @@ struct lyd_node_any {
11241124
};
11251125

11261126
LY_ERR lyd_any_value_str(const struct lyd_node *, char **);
1127+
LY_ERR lyd_new_any(struct lyd_node *, const struct lys_module *, const char *, const void *, LYD_ANYDATA_VALUETYPE, uint32_t, struct lyd_node **);
11271128

11281129
#define LYD_MERGE_DEFAULTS ...
11291130
#define LYD_MERGE_DESTRUCT ...

libyang/data.py

+51-1
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
# Copyright (c) 2021 RACOM s.r.o.
33
# SPDX-License-Identifier: MIT
44

5+
import json
56
import logging
67
from typing import IO, Any, Dict, Iterator, Optional, Tuple, Union
78

89
from _libyang import ffi, lib
910
from .keyed_list import KeyedList
1011
from .schema import (
1112
Module,
13+
SAnydata,
1214
SContainer,
1315
SLeaf,
1416
SLeafList,
@@ -107,6 +109,21 @@ def newval_flags(
107109
return flags
108110

109111

112+
# -------------------------------------------------------------------------------------
113+
def anydata_format(fmt_string: str) -> int:
114+
if fmt_string == "datatree":
115+
return lib.LYD_ANYDATA_DATATREE
116+
if fmt_string == "string":
117+
return lib.LYD_ANYDATA_STRING
118+
if fmt_string == "xml":
119+
return lib.LYD_ANYDATA_XML
120+
if fmt_string == "json":
121+
return lib.LYD_ANYDATA_JSON
122+
if fmt_string == "lyb":
123+
return lib.LYD_ANYDATA_LYB
124+
raise ValueError("unknown anydata format: %r" % fmt_string)
125+
126+
110127
# -------------------------------------------------------------------------------------
111128
def parser_flags(
112129
lyb_mod_update: bool = False,
@@ -1199,6 +1216,8 @@ def dict_to_dnode(
11991216
rpcreply: bool = False,
12001217
notification: bool = False,
12011218
store_only: bool = False,
1219+
types: Optional[Tuple[int, ...]] = None,
1220+
anydata_fmt: str = "json",
12021221
) -> Optional[DNode]:
12031222
"""
12041223
Convert a python dictionary to a DNode object given a YANG module object. The return
@@ -1308,6 +1327,34 @@ def _create_list(_parent, module, name, key_values, in_rpc_output=False):
13081327
created.append(n[0])
13091328
return n[0]
13101329

1330+
def _create_anydata(_parent, module, name, value, in_rpc_output=False):
1331+
if value is not None:
1332+
if isinstance(value, dict) and anydata_fmt == "json":
1333+
value = json.dumps(value)
1334+
elif not isinstance(value, str):
1335+
value = str(value)
1336+
1337+
n = ffi.new("struct lyd_node **")
1338+
flags = newval_flags(rpc_output=in_rpc_output, store_only=store_only)
1339+
ret = lib.lyd_new_any(
1340+
_parent,
1341+
module.cdata,
1342+
str2c(name),
1343+
str2c(value),
1344+
anydata_format(anydata_fmt),
1345+
flags,
1346+
n,
1347+
)
1348+
if ret != lib.LY_SUCCESS:
1349+
if _parent:
1350+
parent_path = repr(DNode.new(module.context, _parent).path())
1351+
else:
1352+
parent_path = "module %r" % module.name()
1353+
raise module.context.error(
1354+
"failed to create leaf %r as a child of %s", name, parent_path
1355+
)
1356+
created.append(n[0])
1357+
13111358
schema_cache = {}
13121359

13131360
def _find_schema(schema_parent, name, prefix):
@@ -1324,7 +1371,7 @@ def _find_schema(schema_parent, name, prefix):
13241371
if schema_parent is None:
13251372
# there may not be any input or any output node in the rpc
13261373
return None, None
1327-
for s in schema_parent:
1374+
for s in schema_parent.children(types=types):
13281375
if s.name() != name:
13291376
continue
13301377
mod = s.module()
@@ -1424,6 +1471,9 @@ def _to_dnode(_dic, _schema, _parent=ffi.NULL, in_rpc_output=False):
14241471
n = _create_container(_parent, module, name, in_rpc_output)
14251472
_to_dnode(value, s, n, in_rpc_output)
14261473

1474+
elif isinstance(s, SAnydata):
1475+
_create_anydata(_parent, module, name, value, in_rpc_output)
1476+
14271477
result = None
14281478

14291479
try:

tests/test_data.py

+15
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from _libyang import lib
1212
from libyang import (
1313
Context,
14+
DAnydata,
1415
DAnyxml,
1516
DataType,
1617
DContainer,
@@ -23,6 +24,7 @@
2324
IOType,
2425
LibyangError,
2526
Module,
27+
SNode,
2628
)
2729
from libyang.data import dict_to_dnode
2830

@@ -1112,3 +1114,16 @@ def test_dnode_builtin_plugins_only(self):
11121114
self.assertIsInstance(dnode, DLeaf)
11131115
self.assertEqual(dnode.value(), "test")
11141116
dnode.free()
1117+
1118+
def test_dnode_anydata_dict_to_dnode(self):
1119+
anydata_json = """{
1120+
"yolo-nodetypes:any1": {
1121+
"key1": "val1"
1122+
}
1123+
}"""
1124+
data = json.loads(anydata_json)
1125+
module = self.ctx.load_module("yolo-nodetypes")
1126+
dnode = dict_to_dnode(
1127+
data, module, None, validate=False, types=(SNode.ANYDATA,)
1128+
)
1129+
self.assertIsInstance(dnode, DAnydata)

0 commit comments

Comments
 (0)