Skip to content

Commit f5b4e7a

Browse files
stewegsamuel-gauthier
authored andcommitted
schema: add Must class
This patches introduces a new Must class that represents a must statement. A new musts method is added to access the must statements of a node. The must_conditions method is updated to use this new class, and factorized in the SNode class. Fixes: #90 Signed-off-by: Stefan Gula <steweg@gmail.com> Signed-off-by: Samuel Gauthier <samuel.gauthier@6wind.com>
1 parent f26b56a commit f5b4e7a

File tree

4 files changed

+41
-29
lines changed

4 files changed

+41
-29
lines changed

libyang/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
IfNotFeature,
7575
IfOrFeatures,
7676
Module,
77+
Must,
7778
Revision,
7879
SContainer,
7980
SLeaf,
@@ -138,6 +139,7 @@
138139
"MandatoryAdded",
139140
"MandatoryRemoved",
140141
"Module",
142+
"Must",
141143
"MustAdded",
142144
"MustRemoved",
143145
"NodeTypeAdded",

libyang/schema.py

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,21 @@ def __str__(self):
10361036
return "(%s OR %s)" % (self.a, self.b)
10371037

10381038

1039+
# -------------------------------------------------------------------------------------
1040+
class Must:
1041+
__slots__ = ("context", "cdata")
1042+
1043+
def __init__(self, context: "libyang.Context", cdata):
1044+
self.context = context
1045+
self.cdata = cdata # C type: "struct lysc_must *"
1046+
1047+
def condition(self) -> str:
1048+
return c2str(lib.lyxp_get_expr(self.cdata.cond))
1049+
1050+
def error_message(self) -> Optional[str]:
1051+
return c2str(self.cdata.emsg) if self.cdata.emsg != ffi.NULL else None
1052+
1053+
10391054
# -------------------------------------------------------------------------------------
10401055
class SNode:
10411056
__slots__ = ("context", "cdata", "cdata_parsed", "__dict__")
@@ -1138,7 +1153,17 @@ def extensions(self) -> Iterator[ExtensionCompiled]:
11381153
yield ExtensionCompiled(self.context, extension)
11391154

11401155
def must_conditions(self) -> Iterator[str]:
1141-
return iter(())
1156+
for must in self.musts():
1157+
yield must.condition()
1158+
1159+
def musts(self) -> Iterator[Must]:
1160+
mc = lib.lysc_node_musts(self.cdata)
1161+
if mc == ffi.NULL:
1162+
return
1163+
for m in ly_array_iter(mc):
1164+
if not m:
1165+
continue
1166+
yield Must(self.context, m)
11421167

11431168
def get_extension(
11441169
self, name: str, prefix: Optional[str] = None, arg_value: Optional[str] = None
@@ -1269,13 +1294,6 @@ def is_key(self) -> bool:
12691294
return True
12701295
return False
12711296

1272-
def must_conditions(self) -> Iterator[str]:
1273-
pdata = self.cdata_leaf_parsed
1274-
if pdata.musts == ffi.NULL:
1275-
return
1276-
for must in ly_array_iter(pdata.musts):
1277-
yield c2str(must.arg.str)
1278-
12791297
def __str__(self):
12801298
return "%s %s" % (self.name(), self.type().name())
12811299

@@ -1324,13 +1342,6 @@ def defaults(self) -> Iterator[Union[None, bool, int, str, float]]:
13241342
else:
13251343
yield val
13261344

1327-
def must_conditions(self) -> Iterator[str]:
1328-
pdata = self.cdata_leaflist_parsed
1329-
if pdata.musts == ffi.NULL:
1330-
return
1331-
for must in ly_array_iter(pdata.musts):
1332-
yield c2str(must.arg.str)
1333-
13341345
def max_elements(self) -> int:
13351346
return (
13361347
self.cdata_leaflist.max
@@ -1363,13 +1374,6 @@ def presence(self) -> Optional[str]:
13631374

13641375
return c2str(self.cdata_container_parsed.presence)
13651376

1366-
def must_conditions(self) -> Iterator[str]:
1367-
pdata = self.cdata_container_parsed
1368-
if pdata.musts == ffi.NULL:
1369-
return
1370-
for must in ly_array_iter(pdata.musts):
1371-
yield c2str(must.arg.str)
1372-
13731377
def __iter__(self) -> Iterator[SNode]:
13741378
return self.children()
13751379

@@ -1425,13 +1429,6 @@ def keys(self) -> Iterator[SNode]:
14251429
yield SLeaf(self.context, node)
14261430
node = node.next
14271431

1428-
def must_conditions(self) -> Iterator[str]:
1429-
pdata = self.cdata_list_parsed
1430-
if pdata.musts == ffi.NULL:
1431-
return
1432-
for must in ly_array_iter(pdata.musts):
1433-
yield c2str(must.arg.str)
1434-
14351432
def uniques(self) -> Iterator[List[SNode]]:
14361433
for unique in ly_array_iter(self.cdata_list.uniques):
14371434
nodes = []

tests/test_schema.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
IOType,
1313
LibyangError,
1414
Module,
15+
Must,
1516
Revision,
1617
SContainer,
1718
SLeaf,
@@ -530,6 +531,15 @@ def tearDown(self):
530531
self.ctx.destroy()
531532
self.ctx = None
532533

534+
def test_must(self):
535+
leaf = next(self.ctx.find_path("/yolo-nodetypes:conf/percentage"))
536+
self.assertIsInstance(leaf, SLeaf)
537+
must = next(leaf.musts(), None)
538+
self.assertIsInstance(must, Must)
539+
self.assertEqual(must.error_message(), "ERROR1")
540+
must = next(leaf.must_conditions(), None)
541+
self.assertIsInstance(must, str)
542+
533543
def test_leaf_default(self):
534544
leaf = next(self.ctx.find_path("/yolo-nodetypes:conf/percentage"))
535545
self.assertIsInstance(leaf.default(), float)

tests/yang/yolo/yolo-nodetypes.yang

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ module yolo-nodetypes {
3131
fraction-digits 2;
3232
}
3333
default 10.2;
34+
must ". = 10.6" {
35+
error-message "ERROR1";
36+
}
3437
}
3538

3639
leaf-list ratios {

0 commit comments

Comments
 (0)