Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
schema: resolve cross-module prefixes in if-feature expressions
And I have to type stuff here just to make CI happy, even though the
subject oneliner above has all the required info. Oh well.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Jan Kundrát <jan.kundrat@cesnet.cz>
  • Loading branch information
jktjkt and claude committed Sep 23, 2026
commit 887d2ae8021d0697a42adee6ab7a7d3bbf7d4888
21 changes: 19 additions & 2 deletions libyang/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -1097,8 +1097,25 @@ def _get_operands_parsed(self):
}

def get_feature(name):
for feature in self.module_features:
if feature.name() == name:
prefix, _, local_name = name.rpartition(":")
candidates = self.module_features
pmod = self.cdata.mod
if prefix and pmod and pmod.mod and prefix != c2str(pmod.mod.prefix):
imp = next(
(
i
for i in ly_array_iter(pmod.imports)
if c2str(i.prefix) == prefix
),
None,
)
if imp is None:
raise LibyangError(
"Unknown prefix %r in if-feature %r" % (prefix, name)
)
candidates = Module(self.context, imp.module).features()
for feature in candidates:
if feature.name() == local_name:
return feature.cdata
raise LibyangError("No feature %s in module" % name)

Expand Down
7 changes: 7 additions & 0 deletions tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,13 @@ def test_iffeature_str(self):
iff = next(self.leaf.if_features())
self.assertEqual(str(iff), "turbo-boost OR networking")

def test_iffeature_str_cross_module(self):
self.ctx.load_module("yolo-featdep", None, ["*"])
self.ctx.load_module("yolo-featuser")
leaf = next(self.ctx.find_path("/yolo-featuser:gated"))
iff = next(leaf.if_features())
self.assertEqual(str(iff), "remote-feature")

def test_iffeature_dump(self):
iff = next(self.leaf.if_features())
self.assertEqual(
Expand Down
15 changes: 15 additions & 0 deletions tests/yang/yolo/yolo-featdep.yang
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module yolo-featdep {
yang-version 1.1;
namespace "urn:yang:yolo:featdep";
prefix featdep;

revision 2026-09-23 {
description
"Initial version.";
}

feature remote-feature {
description
"Defined here so yolo-featuser can reference it by prefix.";
}
}
25 changes: 25 additions & 0 deletions tests/yang/yolo/yolo-featuser.yang
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module yolo-featuser {
yang-version 1.1;
namespace "urn:yang:yolo:featuser";
prefix featuser;

import yolo-featdep { prefix dep; }

revision 2026-09-23 {
description
"Initial version.";
}

feature local-feature {
description
"Unused by `gated` - only here so this module has a non-empty
feature list of its own.";
}

leaf gated {
type string;
if-feature "dep:remote-feature";
description
"Gated by another module's feature, referenced by prefix.";
}
}
Loading