Skip to content

Commit 60d7307

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 f14116c commit 60d7307

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
@@ -1118,6 +1118,7 @@ struct lyd_node_any {
11181118
};
11191119

11201120
LY_ERR lyd_any_value_str(const struct lyd_node *, char **);
1121+
LY_ERR lyd_new_any(struct lyd_node *, const struct lys_module *, const char *, const void *, LYD_ANYDATA_VALUETYPE, uint32_t, struct lyd_node **);
11211122

11221123
#define LYD_MERGE_DEFAULTS ...
11231124
#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,
@@ -104,6 +106,21 @@ def newval_flags(
104106
return flags
105107

106108

109+
# -------------------------------------------------------------------------------------
110+
def anydata_format(fmt_string: str) -> int:
111+
if fmt_string == "datatree":
112+
return lib.LYD_ANYDATA_DATATREE
113+
if fmt_string == "string":
114+
return lib.LYD_ANYDATA_STRING
115+
if fmt_string == "xml":
116+
return lib.LYD_ANYDATA_XML
117+
if fmt_string == "json":
118+
return lib.LYD_ANYDATA_JSON
119+
if fmt_string == "lyb":
120+
return lib.LYD_ANYDATA_LYB
121+
raise ValueError("unknown anydata format: %r" % fmt_string)
122+
123+
107124
# -------------------------------------------------------------------------------------
108125
def parser_flags(
109126
lyb_mod_update: bool = False,
@@ -1188,6 +1205,8 @@ def dict_to_dnode(
11881205
rpc: bool = False,
11891206
rpcreply: bool = False,
11901207
notification: bool = False,
1208+
types: Optional[Tuple[int, ...]] = None,
1209+
anydata_fmt: str = "json",
11911210
) -> Optional[DNode]:
11921211
"""
11931212
Convert a python dictionary to a DNode object given a YANG module object. The return
@@ -1295,6 +1314,34 @@ def _create_list(_parent, module, name, key_values, in_rpc_output=False):
12951314
created.append(n[0])
12961315
return n[0]
12971316

1317+
def _create_anydata(_parent, module, name, value, in_rpc_output=False):
1318+
if value is not None:
1319+
if isinstance(value, dict) and anydata_fmt == "json":
1320+
value = json.dumps(value)
1321+
elif not isinstance(value, str):
1322+
value = str(value)
1323+
1324+
n = ffi.new("struct lyd_node **")
1325+
flags = newval_flags(rpc_output=in_rpc_output, store_only=store_only)
1326+
ret = lib.lyd_new_any(
1327+
_parent,
1328+
module.cdata,
1329+
str2c(name),
1330+
str2c(value),
1331+
anydata_format(anydata_fmt),
1332+
flags,
1333+
n,
1334+
)
1335+
if ret != lib.LY_SUCCESS:
1336+
if _parent:
1337+
parent_path = repr(DNode.new(module.context, _parent).path())
1338+
else:
1339+
parent_path = "module %r" % module.name()
1340+
raise module.context.error(
1341+
"failed to create leaf %r as a child of %s", name, parent_path
1342+
)
1343+
created.append(n[0])
1344+
12981345
schema_cache = {}
12991346

13001347
def _find_schema(schema_parent, name, prefix):
@@ -1311,7 +1358,7 @@ def _find_schema(schema_parent, name, prefix):
13111358
if schema_parent is None:
13121359
# there may not be any input or any output node in the rpc
13131360
return None, None
1314-
for s in schema_parent:
1361+
for s in schema_parent.children(types=types):
13151362
if s.name() != name:
13161363
continue
13171364
mod = s.module()
@@ -1411,6 +1458,9 @@ def _to_dnode(_dic, _schema, _parent=ffi.NULL, in_rpc_output=False):
14111458
n = _create_container(_parent, module, name, in_rpc_output)
14121459
_to_dnode(value, s, n, in_rpc_output)
14131460

1461+
elif isinstance(s, SAnydata):
1462+
_create_anydata(_parent, module, name, value, in_rpc_output)
1463+
14141464
result = None
14151465

14161466
try:

tests/test_data.py

+15
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from _libyang import lib
1111
from libyang import (
1212
Context,
13+
DAnydata,
1314
DAnyxml,
1415
DataType,
1516
DContainer,
@@ -22,6 +23,7 @@
2223
IOType,
2324
LibyangError,
2425
Module,
26+
SNode,
2527
)
2628
from libyang.data import dict_to_dnode
2729

@@ -1092,3 +1094,16 @@ def test_dnode_leafref_linking(self):
10921094
self.assertIsInstance(dnode4, DLeaf)
10931095
self.assertEqual(dnode4.cdata, dnode2.cdata)
10941096
dnode1.free()
1097+
1098+
def test_dnode_anydata_dict_to_dnode(self):
1099+
anydata_json = """{
1100+
"yolo-nodetypes:any1": {
1101+
"key1": "val1"
1102+
}
1103+
}"""
1104+
data = json.loads(anydata_json)
1105+
module = self.ctx.load_module("yolo-nodetypes")
1106+
dnode = dict_to_dnode(
1107+
data, module, None, validate=False, types=(SNode.ANYDATA,)
1108+
)
1109+
self.assertIsInstance(dnode, DAnydata)

0 commit comments

Comments
 (0)