Skip to content

Commit

Permalink
subscription: return parent node to oper_state callback
Browse files Browse the repository at this point in the history
The only way to differentiate two calls when there is a subscription
on an internal element of a list is by using the parent node. Moreover,
in these cases, it is on this parent node that the data structure to
be returned must be built.
  • Loading branch information
avazquezrd committed Jan 24, 2023
1 parent 5a81607 commit fd65512
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 5 deletions.
6 changes: 5 additions & 1 deletion sysrepo/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,13 +372,17 @@ def subscribe_module_change(

self.subscriptions.append(sub)

OperDataCallbackType = Callable[[str, Any], Optional[Dict]]
OperDataCallbackType = Callable[[str, Optional[libyang.DNode], Any], Optional[Dict]]
"""
Callback to be called when the operational data are requested.
:arg xpath:
The XPath requested by a client. Can be None if the client requested for all the
module operational data.
:arg parent:
Pointer to an existing parent of the requested nodes. It is None for top-level
nodes. Caller is supposed to append the requested nodes to this data subtree
and return either the original parent or a top-level node.
:arg private_data:
Private context opaque to sysrepo used when subscribing.
:arg kwargs (optional):
Expand Down
9 changes: 7 additions & 2 deletions sysrepo/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,12 +360,17 @@ def oper_data_callback(session, sub_id, module, xpath, req_xpath, req_id, parent
else:
extra_info = {}

parent_node = None
if parent[0]:
with session.get_ly_ctx() as ly_ctx:
parent_node = DNode.new(ly_ctx, parent[0])

if is_async_func(callback):
task_id = req_id

if task_id not in subscription.tasks:
task = subscription.loop.create_task(
callback(req_xpath, private_data, **extra_info)
callback(req_xpath, parent_node, private_data, **extra_info)
)
task.add_done_callback(
functools.partial(subscription.task_done, task_id, "oper")
Expand All @@ -382,7 +387,7 @@ def oper_data_callback(session, sub_id, module, xpath, req_xpath, req_id, parent
oper_data = task.result()

else:
oper_data = callback(req_xpath, private_data, **extra_info)
oper_data = callback(req_xpath, parent_node, private_data, **extra_info)

if isinstance(oper_data, dict):
# convert oper_data to a libyang.DNode object
Expand Down
6 changes: 4 additions & 2 deletions tests/test_subs_oper.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ def test_oper_sub(self):
priv = object()
state = None

def oper_data_cb(xpath, private_data):
def oper_data_cb(xpath, path, private_data):
self.assertEqual(xpath, "/sysrepo-example:state")
self.assertIsNone(path)
self.assertEqual(private_data, priv)
return state

Expand Down Expand Up @@ -77,8 +78,9 @@ def test_oper_sub_with_extra_info(self):
priv = object()
calls = []

def oper_data_cb(xpath, private_data, **kwargs):
def oper_data_cb(xpath, path, private_data, **kwargs):
self.assertEqual(xpath, "/sysrepo-example:state")
self.assertIsNone(path)
self.assertEqual(private_data, priv)
self.assertIn("user", kwargs)
self.assertEqual(getpass.getuser(), kwargs["user"])
Expand Down

0 comments on commit fd65512

Please sign in to comment.