Skip to content

Commit

Permalink
data: add leafref_nodes and leafref_link_node_tree
Browse files Browse the repository at this point in the history
This patch adds API, which allows user to:
 - determine if DNode is being referenced by some other leafref DNodes.
 - trigger process for creating cross-references between leafref DNodes
   and target DNodes.

Closes: #108
Signed-off-by: Stefan Gula <[email protected]>
Signed-off-by: Samuel Gauthier <[email protected]>
  • Loading branch information
steweg authored and samuel-gauthier committed Aug 2, 2024
1 parent 47b0f09 commit f14116c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 1 deletion.
9 changes: 9 additions & 0 deletions cffi/cdefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1248,5 +1248,14 @@ struct lyd_attr {
LY_ERR lyd_new_attr(struct lyd_node *, const char *, const char *, const char *, struct lyd_attr **);
void lyd_free_attr_single(const struct ly_ctx *ctx, struct lyd_attr *attr);

struct lyd_leafref_links_rec {
const struct lyd_node_term *node;
const struct lyd_node_term **leafref_nodes;
const struct lyd_node_term **target_nodes;
};

LY_ERR lyd_leafref_get_links(const struct lyd_node_term *e, const struct lyd_leafref_links_rec **);
LY_ERR lyd_leafref_link_node_tree(struct lyd_node *);

/* from libc, needed to free allocated strings */
void free(void *);
24 changes: 23 additions & 1 deletion libyang/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
SRpc,
Type,
)
from .util import DataType, IOType, LibyangError, c2str, str2c
from .util import DataType, IOType, LibyangError, c2str, ly_array_iter, str2c


LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -991,6 +991,28 @@ def free(self, with_siblings: bool = True) -> None:
finally:
self.cdata = ffi.NULL

def leafref_link_node_tree(self) -> None:
"""
Traverse through data tree including root node siblings and adds
leafrefs links to the given nodes.
Requires leafref_linking to be set on the libyang context.
"""
lib.lyd_leafref_link_node_tree(self.cdata)

def leafref_nodes(self) -> Iterator["DNode"]:
"""
Gets the leafref links record for given node.
Requires leafref_linking to be set on the libyang context.
"""
term_node = ffi.cast("struct lyd_node_term *", self.cdata)
out = ffi.new("const struct lyd_leafref_links_rec **")
if lib.lyd_leafref_get_links(term_node, out) != lib.LY_SUCCESS:
return
for n in ly_array_iter(out[0].leafref_nodes):
yield DNode.new(self.context, n)

def __repr__(self):
cls = self.__class__
return "<%s.%s: %s>" % (cls.__module__, cls.__name__, str(self))
Expand Down
26 changes: 26 additions & 0 deletions tests/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
DRpc,
IOType,
LibyangError,
Module,
)
from libyang.data import dict_to_dnode

Expand Down Expand Up @@ -1066,3 +1067,28 @@ def test_dnode_attrs_set_and_remove_multiple(self):

attrs.remove("ietf-netconf:operation")
self.assertEqual(len(attrs), 0)

def test_dnode_leafref_linking(self):
MAIN = """{
"yolo-leafref-extended:list1": [{
"leaf1": "val1",
"leaflist2": ["val2", "val3"]
}],
"yolo-leafref-extended:ref1": "val1"
}"""
self.ctx.destroy()
self.ctx = Context(YANG_DIR, leafref_extended=True, leafref_linking=True)
mod = self.ctx.load_module("yolo-leafref-extended")
self.assertIsInstance(mod, Module)
dnode1 = self.ctx.parse_data_mem(MAIN, "json", parse_only=True)
self.assertIsInstance(dnode1, DList)
dnode2 = next(dnode1.siblings(include_self=False))
self.assertIsInstance(dnode2, DLeaf)
dnode3 = next(dnode1.children())
self.assertIsInstance(dnode3, DLeaf)
self.assertIsNone(next(dnode3.leafref_nodes(), None))
dnode2.leafref_link_node_tree()
dnode4 = next(dnode3.leafref_nodes())
self.assertIsInstance(dnode4, DLeaf)
self.assertEqual(dnode4.cdata, dnode2.cdata)
dnode1.free()

0 comments on commit f14116c

Please sign in to comment.