Skip to content

Commit

Permalink
Fix presence with SplitClassDir option, and containing Groups (#339)
Browse files Browse the repository at this point in the history
* When unsetting a PresenceContainer, set no changes.
* If splitting, add local imports for presenceContainers.
* Add UnitTests for Presence Set/Unset.
* Fix for Presence Containers that use Groupings
  • Loading branch information
JoseIgnacioTamayo authored Feb 13, 2024
1 parent f078462 commit cf4c3bd
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 42 deletions.
4 changes: 3 additions & 1 deletion pyangbind/lib/yangtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ def __init__(self, *args, **kwargs):
except TypeError:
super(YANGBaseClass, self).__init__()
except Exception:
six.reraise()
raise

def _changed(self):
return self._mchanged
Expand Down Expand Up @@ -1205,6 +1205,8 @@ def _set_present(self, present=True):
self._cpresent = present
if present is True:
self._set()
if present is False:
self._mchanged = False

def _present(self):
if not self._is_container == "container":
Expand Down
26 changes: 7 additions & 19 deletions pyangbind/plugin/pybind.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,7 @@

import pyangbind.helpers.misc as misc_help
from pyangbind.helpers.identity import IdentityStore
from pyangbind.lib.yangtypes import (
RestrictedClassType,
YANGBool,
safe_name,
YANGBinary,
YANGBitsType,
)
from pyangbind.lib.yangtypes import RestrictedClassType, YANGBool, safe_name, YANGBinary, YANGBitsType

# Python3 support
if six.PY3:
Expand Down Expand Up @@ -741,9 +735,6 @@ def get_children(ctx, fd, i_children, module, parent, path=str(), parent_cfg=Tru
import_req = []

for ch in i_children:
children_tmp = getattr(ch, "i_children", None)
if children_tmp is not None:
children_tmp = [i.arg for i in children_tmp]
if ch.keyword == "choice":
for choice_ch in ch.i_children:
# these are case statements
Expand Down Expand Up @@ -774,9 +765,10 @@ def get_children(ctx, fd, i_children, module, parent, path=str(), parent_cfg=Tru
choice=choice,
register_paths=register_paths,
)

if ctx.opts.split_class_dir:
if hasattr(ch, "i_children") and len(ch.i_children):
if (hasattr(ch, "i_children") and len(ch.i_children)) or (
ctx.opts.generate_presence and ch.search_one("presence")
):
import_req.append(ch.arg)

# Write out the import statements if needed.
Expand Down Expand Up @@ -1478,16 +1470,12 @@ def get_element(ctx, fd, element, module, parent, path, parent_cfg=True, choice=
npath = path

# Create an element for a container.
if element.i_children or ctx.opts.generate_presence:
chs = element.i_children
has_presence = True if element.search_one("presence") is not None else False
if has_presence is False and len(chs) == 0:
return []

has_presence = True if element.search_one("presence") is not None else False
if element.i_children or (ctx.opts.generate_presence and has_presence):
get_children(
ctx,
fd,
chs,
element.i_children,
module,
element,
npath,
Expand Down
16 changes: 13 additions & 3 deletions tests/presence/presence.yang
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ module presence {
reference "fooled-you";
}

grouping a-grouping {
leaf s {
type string;
}
}

container empty-container {
presence "something implied implicity";
}
Expand All @@ -23,19 +29,23 @@ module presence {
}

container np-container {
description
"np container";

leaf s {
type string;
}
}

container pp {
container p-container {
presence "implicit";

leaf s {
type string;
}
}

container p-container-grouping {
presence "implicit";

uses a-grouping;
}
}
80 changes: 61 additions & 19 deletions tests/presence/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ def setUp(self):
self.instance = self.bindings.presence()

def test_001_check_containers(self):
for attr in ["empty-container", "parent", ["parent", "child"]]:
for attr in [
"empty-container",
"parent",
["parent", "child"],
"np_container",
"p_container",
"p_container_grouping",
]:
with self.subTest(attr=attr):
if isinstance(attr, list):
parent = self.instance
Expand All @@ -27,53 +34,68 @@ def test_001_check_containers(self):
elem = getattr(self.instance, safe_name(attr), None)
self.assertIsNot(elem, None)

def test_002_check_presence(self):
def test_002_check_leafs(self):
for attr in [
("np_container", "s"),
("p_container", "s"),
("p_container_grouping", "s"),
]:
with self.subTest(attr=attr):
container, leaf = attr
cont_elem = getattr(self.instance, container, None)
leaf_elem = getattr(cont_elem, leaf, None)
self.assertIsNotNone(leaf_elem, "Missing leaf %s in container %s" % (leaf, container))

def test_003_check_presence(self):
self.assertIs(self.instance.empty_container._presence, True)
self.assertIs(self.instance.empty_container._cpresent, False)
self.assertIs(self.instance.empty_container._present(), False)

def test_003_check_set_present(self):
def test_004_check_set_present(self):
smt = getattr(self.instance.empty_container, "_set_present", None)
self.assertIsNot(smt, None)
smt()
self.assertIs(self.instance.empty_container._cpresent, True)
self.assertIs(self.instance.empty_container._present(), True)

def test_004_check_np(self):
def test_005_check_np(self):
self.assertIs(self.instance.parent._presence, False)
self.assertIs(self.instance.np_container._presence, False)
self.assertIs(self.instance.np_container.s._presence, None)

def test_005_check_hierarchy(self):
self.assertIs(self.instance.pp._presence, True)
self.assertIs(self.instance.pp._present(), False)
self.assertIs(self.instance.pp._changed(), False)
self.instance.pp.s = "teststring"
self.assertIs(self.instance.pp._present(), True)
self.assertIs(self.instance.pp._changed(), True)
def test_006_check_hierarchy(self):
self.assertIs(self.instance.p_container._presence, True)
self.assertIs(self.instance.p_container._present(), False)
self.assertIs(self.instance.p_container._changed(), False)
self.instance.p_container.s = "teststring"
self.assertIs(self.instance.p_container._present(), True)
self.assertIs(self.instance.p_container._changed(), True)

def test_006_check_invalid_hierarchy(self):
def test_007_check_invalid_hierarchy(self):
self.assertIs(self.instance.parent._presence, False)
self.assertIs(self.instance.parent.child._presence, True)
self.assertIs(self.instance.parent.child._present(), False)
self.instance.parent.child._set_present()
self.assertIs(self.instance.parent.child._present(), True)
self.assertIs(self.instance.parent._present(), None)

def test_007_set_not_present(self):
def test_008_set_not_present(self):
self.instance.parent.child._set_present()
self.assertIs(self.instance.parent.child._present(), True)
self.instance.parent.child._set_present(present=False)
self.assertIs(self.instance.parent.child._present(), False)

def test_008_presence_get(self):
self.instance.parent.child._set_present()
def test_009_presence_get(self):
self.instance.parent.child._set_present(True)
self.assertIs(self.instance.empty_container._present(), False)
self.assertIs(self.instance.parent.child._present(), True)
self.assertIs(self.instance.pp._present(), False)
self.assertIs(self.instance.p_container._present(), False)
self.assertEqual(self.instance.get(filter=True), {"parent": {"child": {}}})
self.instance.parent.child._set_present(False)
self.assertIs(self.instance.parent.child._present(), False)
self.assertEqual(self.instance.get(filter=True), {})

def test_009_presence_serialise(self):
def test_010_presence_serialise(self):
self.instance.parent.child._set_present()
expectedJ = """
{
Expand All @@ -82,8 +104,24 @@ def test_009_presence_serialise(self):
}
}"""
self.assertEqual(json.loads(pbJ.dumps(self.instance)), json.loads(expectedJ))
self.instance.parent.child._set_present(False)
expectedJ = "{}"
self.assertEqual(json.loads(pbJ.dumps(self.instance)), json.loads(expectedJ))

def test_011_presence_serialise_ietf(self):
self.instance.parent.child._set_present()
expectedJ = """
{
"presence:parent": {
"child": {}
}
}"""
self.assertEqual(json.loads(pbJ.dumps(self.instance, mode="ietf")), json.loads(expectedJ))
self.instance.parent.child._set_present(False)
expectedJ = "{}"
self.assertEqual(json.loads(pbJ.dumps(self.instance, mode="ietf")), json.loads(expectedJ))

def test_010_presence_deserialise(self):
def test_012_presence_deserialise(self):
inputJ = """
{
"parent": {
Expand All @@ -93,7 +131,7 @@ def test_010_presence_deserialise(self):
x = pbJ.loads(inputJ, self.bindings, "presence")
self.assertIs(x.parent.child._present(), True)

def test_011_presence_deserialise(self):
def test_013_presence_deserialise(self):
inputJ = """
{
"presence:parent": {
Expand All @@ -104,5 +142,9 @@ def test_011_presence_deserialise(self):
self.assertIs(x.parent.child._present(), True)


class SplitClassesPresenceTests(PresenceTests):
split_class_dir = True


if __name__ == "__main__":
unittest.main()

0 comments on commit cf4c3bd

Please sign in to comment.