Skip to content

Commit 58ac09c

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 ae31525 commit 58ac09c

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
@@ -990,6 +990,7 @@ struct lyd_node_any {
990990
};
991991

992992
LY_ERR lyd_any_value_str(const struct lyd_node *, char **);
993+
LY_ERR lyd_new_any(struct lyd_node *, const struct lys_module *, const char *, const void *, LYD_ANYDATA_VALUETYPE, uint32_t, struct lyd_node **);
993994

994995
#define LYD_MERGE_DEFAULTS ...
995996
#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,
@@ -1147,6 +1164,8 @@ def dict_to_dnode(
11471164
rpc: bool = False,
11481165
rpcreply: bool = False,
11491166
notification: bool = False,
1167+
types: Optional[Tuple[int, ...]] = None,
1168+
anydata_fmt: str = "json",
11501169
) -> Optional[DNode]:
11511170
"""
11521171
Convert a python dictionary to a DNode object given a YANG module object. The return
@@ -1254,6 +1273,34 @@ def _create_list(_parent, module, name, key_values, in_rpc_output=False):
12541273
created.append(n[0])
12551274
return n[0]
12561275

1276+
def _create_anydata(_parent, module, name, value, in_rpc_output=False):
1277+
if value is not None:
1278+
if isinstance(value, dict) and anydata_fmt == "json":
1279+
value = json.dumps(value)
1280+
elif not isinstance(value, str):
1281+
value = str(value)
1282+
1283+
n = ffi.new("struct lyd_node **")
1284+
flags = newval_flags(rpc_output=in_rpc_output, store_only=store_only)
1285+
ret = lib.lyd_new_any(
1286+
_parent,
1287+
module.cdata,
1288+
str2c(name),
1289+
str2c(value),
1290+
anydata_format(anydata_fmt),
1291+
flags,
1292+
n,
1293+
)
1294+
if ret != lib.LY_SUCCESS:
1295+
if _parent:
1296+
parent_path = repr(DNode.new(module.context, _parent).path())
1297+
else:
1298+
parent_path = "module %r" % module.name()
1299+
raise module.context.error(
1300+
"failed to create leaf %r as a child of %s", name, parent_path
1301+
)
1302+
created.append(n[0])
1303+
12571304
schema_cache = {}
12581305

12591306
def _find_schema(schema_parent, name, prefix):
@@ -1270,7 +1317,7 @@ def _find_schema(schema_parent, name, prefix):
12701317
if schema_parent is None:
12711318
# there may not be any input or any output node in the rpc
12721319
return None, None
1273-
for s in schema_parent:
1320+
for s in schema_parent.children(types=types):
12741321
if s.name() != name:
12751322
continue
12761323
mod = s.module()
@@ -1370,6 +1417,9 @@ def _to_dnode(_dic, _schema, _parent=ffi.NULL, in_rpc_output=False):
13701417
n = _create_container(_parent, module, name, in_rpc_output)
13711418
_to_dnode(value, s, n, in_rpc_output)
13721419

1420+
elif isinstance(s, SAnydata):
1421+
_create_anydata(_parent, module, name, value, in_rpc_output)
1422+
13731423
result = None
13741424

13751425
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,
@@ -21,6 +22,7 @@
2122
DRpc,
2223
IOType,
2324
LibyangError,
25+
SNode,
2426
)
2527
from libyang.data import dict_to_dnode
2628

@@ -1036,3 +1038,16 @@ def test_dnode_attrs_set_and_remove_multiple(self):
10361038

10371039
attrs.remove("ietf-netconf:operation")
10381040
self.assertEqual(len(attrs), 0)
1041+
1042+
def test_dnode_anydata_dict_to_dnode(self):
1043+
anydata_json = """{
1044+
"yolo-nodetypes:any1": {
1045+
"key1": "val1"
1046+
}
1047+
}"""
1048+
data = json.loads(anydata_json)
1049+
module = self.ctx.load_module("yolo-nodetypes")
1050+
dnode = dict_to_dnode(
1051+
data, module, None, validate=False, types=(SNode.ANYDATA,)
1052+
)
1053+
self.assertIsInstance(dnode, DAnydata)

0 commit comments

Comments
 (0)