Upgrade python-libyang to support libyang4

This commit is contained in:
Mattias Walström
2025-12-16 08:06:38 +01:00
parent 7fcbc88105
commit 0ea3380349
3 changed files with 879 additions and 3 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
# md5, sha256 from https://pypi.org/pypi/libyang/json
md5 46332891cac852441b523f7e71a507f7 libyang-3.0.1.tar.gz
sha256 57f8b234131fb073518313351288194e535d74cc8fdff7f0ff7e31c0ab33e663 libyang-3.0.1.tar.gz
sha256 97da2c908a8a3607ac834f2acec224ea53a4b9e9770c13e5598513641decf637 libyang-3.3.0.tar.gz
# Locally computed sha256 checksums
sha256 c8d554f918d32b1467f35829e1cfb753764dd683c6edcecc877a4d7e9f05b2a7 LICENSE
+2 -2
View File
@@ -4,9 +4,9 @@
#
################################################################################
PYTHON_LIBYANG_VERSION = 3.0.1
PYTHON_LIBYANG_VERSION = 3.3.0
PYTHON_LIBYANG_SOURCE = libyang-$(PYTHON_LIBYANG_VERSION).tar.gz
PYTHON_LIBYANG_SITE = https://files.pythonhosted.org/packages/91/2e/ff13ee16c874d232d5d3fdff83f629cbc9ac47f9aaf2b59256b6a1bdbc16
PYTHON_LIBYANG_SITE = https://files.pythonhosted.org/packages/34/d8/ebe9de6d29eaf62a684b34d30118294e48a05d7fbd1bb0af002b7627140d
PYTHON_LIBYANG_SETUP_TYPE = setuptools
PYTHON_LIBYANG_LICENSE = MIT
PYTHON_LIBYANG_LICENSE_FILES = LICENSE
@@ -0,0 +1,876 @@
From 8c246567c03471e20cd9574f9c95a179712c3e3f Mon Sep 17 00:00:00 2001
From: Stefan Gula <steweg@gmail.com>
Date: Sun, 2 Nov 2025 21:26:55 +0100
Subject: [PATCH] cffi: allows to usage of libyang v4.2.2
This patch adjust cffi definitions and also all associated functions
based on libyang v4.2.2.
Signed-off-by: Stefan Gula <steweg@gmail.com>
---
cffi/cdefs.h | 61 ++++++++++++++++++++++-----------------
cffi/source.c | 4 +--
libyang/context.py | 25 ++++++++++------
libyang/data.py | 7 ++---
libyang/extension.py | 24 +++++++++++-----
libyang/schema.py | 66 +++++++++++++++++++++++++++++++++---------
tests/test_context.py | 6 +++-
tests/test_data.py | 67 ++++++++++++++++++++++++-------------------
tests/test_diff.py | 4 ++-
tests/test_schema.py | 4 +--
10 files changed, 172 insertions(+), 96 deletions(-)
diff --git a/cffi/cdefs.h b/cffi/cdefs.h
index 8b6d426..82ec974 100644
--- a/cffi/cdefs.h
+++ b/cffi/cdefs.h
@@ -17,6 +17,7 @@ struct ly_ctx;
#define LY_CTX_LEAFREF_EXTENDED ...
#define LY_CTX_LEAFREF_LINKING ...
#define LY_CTX_BUILTIN_PLUGINS_ONLY ...
+#define LY_CTX_COMPILE_OBSOLETE ...
typedef enum {
@@ -304,20 +305,19 @@ enum lyd_type {
LYD_TYPE_REPLY_RESTCONF
};
-#define LYD_PRINT_KEEPEMPTYCONT ...
#define LYD_PRINT_SHRINK ...
+#define LYD_PRINT_EMPTY_CONT ...
#define LYD_PRINT_WD_ALL ...
#define LYD_PRINT_WD_ALL_TAG ...
#define LYD_PRINT_WD_EXPLICIT ...
#define LYD_PRINT_WD_IMPL_TAG ...
#define LYD_PRINT_WD_MASK ...
-#define LYD_PRINT_WITHSIBLINGS ...
+#define LYD_PRINT_SIBLINGS ...
#define LYD_PRINT_WD_TRIM ...
LY_ERR lyd_print_mem(char **, const struct lyd_node *, LYD_FORMAT, uint32_t);
LY_ERR lyd_print_tree(struct ly_out *, const struct lyd_node *, LYD_FORMAT, uint32_t);
LY_ERR lyd_print_all(struct ly_out *, const struct lyd_node *, LYD_FORMAT, uint32_t);
-#define LYD_PARSE_LYB_MOD_UPDATE ...
#define LYD_PARSE_NO_STATE ...
#define LYD_PARSE_STORE_ONLY ...
#define LYD_PARSE_JSON_NULL ...
@@ -351,7 +351,7 @@ LY_ERR ly_out_new_file(FILE *, struct ly_out **);
LY_ERR ly_out_new_fd(int, struct ly_out **);
LY_ERR lyd_parse_data(const struct ly_ctx *, struct lyd_node *, struct ly_in *, LYD_FORMAT, uint32_t, uint32_t, struct lyd_node **);
-LY_ERR lyd_parse_op(const struct ly_ctx *, struct lyd_node *, struct ly_in *, LYD_FORMAT, enum lyd_type, struct lyd_node **, struct lyd_node **);
+LY_ERR lyd_parse_op(const struct ly_ctx *, struct lyd_node *, struct ly_in *, LYD_FORMAT, enum lyd_type, uint32_t, struct lyd_node **, struct lyd_node **);
typedef enum {
LYS_OUT_UNKNOWN,
@@ -369,6 +369,7 @@ LY_ERR lys_print_module(struct ly_out *, const struct lys_module *, LYS_OUTFORMA
struct lysc_module {
struct lys_module *mod;
+ const char **features;
struct lysc_node *data;
struct lysc_node_action *rpcs;
struct lysc_node_notif *notifs;
@@ -388,13 +389,15 @@ struct lys_module {
const char *ref;
struct lysp_module *parsed;
struct lysc_module *compiled;
+ struct lysc_ext *extensions;
struct lysc_ident *identities;
+ struct lysc_submodule *submodules;
struct lys_module **augmented_by;
struct lys_module **deviated_by;
ly_bool implemented;
ly_bool to_compile;
- uint8_t latest_revision;
- ...;
+ uint8_t version : 2;
+ uint8_t latest_revision : 4;
};
struct lysp_module {
@@ -467,12 +470,11 @@ struct lysp_ext_instance {
const char *argument;
LY_VALUE_FORMAT format;
void *prefix_data;
- struct lysp_ext *def;
+ uintptr_t plugin_ref;
void *parent;
enum ly_stmt parent_stmt;
uint64_t parent_stmt_index;
uint16_t flags;
- const struct lyplg_ext_record *record;
struct lysp_ext_substmt *substmts;
void *parsed;
struct lysp_stmt *child;
@@ -610,6 +612,11 @@ struct lysp_node_container {
...;
};
+struct lysc_value {
+ const char *str;
+ struct lysc_prefix *prefixes;
+};
+
struct lysc_node_leaf {
union {
struct lysc_node node;
@@ -623,7 +630,7 @@ struct lysc_node_leaf {
struct lysc_when **when;
struct lysc_type *type;
const char *units;
- struct lyd_value *dflt;
+ struct lysc_value dflt;
...;
};
@@ -653,7 +660,7 @@ struct lysc_node_leaflist {
struct lysc_when **when;
struct lysc_type *type;
const char *units;
- struct lyd_value **dflts;
+ struct lysc_value *dflts;
uint32_t min;
uint32_t max;
...;
@@ -783,7 +790,7 @@ struct lysp_node_augment {
struct lysc_type {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
};
@@ -859,7 +866,7 @@ struct lysc_ext {
const char *name;
const char *argname;
struct lysc_ext_instance *exts;
- struct lyplg_ext *plugin;
+ uintptr_t plugin_ref;
struct lys_module *module;
uint16_t flags;
};
@@ -982,7 +989,6 @@ typedef struct pcre2_real_code pcre2_code;
struct lysc_pattern {
const char *expr;
- pcre2_code *code;
const char *dsc;
const char *ref;
const char *emsg;
@@ -1017,7 +1023,7 @@ struct lysc_ident {
struct lysc_type_num {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
struct lysc_range *range;
@@ -1026,7 +1032,7 @@ struct lysc_type_num {
struct lysc_type_dec {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
uint8_t fraction_digits;
@@ -1036,7 +1042,7 @@ struct lysc_type_dec {
struct lysc_type_str {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
struct lysc_range *length;
@@ -1058,7 +1064,7 @@ struct lysc_type_bitenum_item {
struct lysc_type_enum {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
struct lysc_type_bitenum_item *enums;
@@ -1067,7 +1073,7 @@ struct lysc_type_enum {
struct lysc_type_bits {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
struct lysc_type_bitenum_item *bits;
@@ -1076,7 +1082,7 @@ struct lysc_type_bits {
struct lysc_type_leafref {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
struct lyxp_expr *path;
@@ -1088,7 +1094,7 @@ struct lysc_type_leafref {
struct lysc_type_identityref {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
struct lysc_ident **bases;
@@ -1097,7 +1103,7 @@ struct lysc_type_identityref {
struct lysc_type_instanceid {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
uint8_t require_instance;
@@ -1106,7 +1112,7 @@ struct lysc_type_instanceid {
struct lysc_type_union {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
struct lysc_type **types;
@@ -1115,7 +1121,7 @@ struct lysc_type_union {
struct lysc_type_bin {
const char *name;
struct lysc_ext_instance *exts;
- struct lyplg_type *plugin;
+ uintptr_t plugin_ref;
LY_DATA_TYPE basetype;
uint32_t refcount;
struct lysc_range *length;
@@ -1159,8 +1165,7 @@ typedef enum {
LYD_ANYDATA_DATATREE,
LYD_ANYDATA_STRING,
LYD_ANYDATA_XML,
- LYD_ANYDATA_JSON,
- LYD_ANYDATA_LYB
+ LYD_ANYDATA_JSON
} LYD_ANYDATA_VALUETYPE;
union lyd_any_value {
@@ -1168,7 +1173,6 @@ union lyd_any_value {
const char *str;
const char *xml;
const char *json;
- char *mem;
};
struct lyd_node_any {
@@ -1320,6 +1324,8 @@ 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);
+LY_ERR lyd_value_validate_dflt(const struct lysc_node *, const char *, struct lysc_prefix *, const struct lyd_node *, const struct lysc_type **, const char **);
+
struct lyd_leafref_links_rec {
const struct lyd_node_term *node;
const struct lyd_node_term **leafref_nodes;
@@ -1328,13 +1334,14 @@ struct lyd_leafref_links_rec {
LY_ERR lyd_leafref_get_links(const struct lyd_node_term *, const struct lyd_leafref_links_rec **);
LY_ERR lyd_leafref_link_node_tree(struct lyd_node *);
+struct lyplg_ext *lysc_get_ext_plugin(uintptr_t);
const char *lyplg_ext_stmt2str(enum ly_stmt stmt);
const struct lysp_module *lyplg_ext_parse_get_cur_pmod(const struct lysp_ctx *);
struct ly_ctx *lyplg_ext_compile_get_ctx(const struct lysc_ctx *);
void lyplg_ext_parse_log(const struct lysp_ctx *, const struct lysp_ext_instance *, LY_LOG_LEVEL, LY_ERR, const char *, ...);
void lyplg_ext_compile_log(const struct lysc_ctx *, const struct lysc_ext_instance *, LY_LOG_LEVEL, LY_ERR, const char *, ...);
LY_ERR lyplg_ext_parse_extension_instance(struct lysp_ctx *, struct lysp_ext_instance *);
-LY_ERR lyplg_ext_compile_extension_instance(struct lysc_ctx *, const struct lysp_ext_instance *, struct lysc_ext_instance *);
+LY_ERR lyplg_ext_compile_extension_instance(struct lysc_ctx *, const struct lysp_ext_instance *, struct lysc_ext_instance *, struct lysc_node *);
void lyplg_ext_pfree_instance_substatements(const struct ly_ctx *ctx, struct lysp_ext_substmt *substmts);
void lyplg_ext_cfree_instance_substatements(const struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
typedef LY_ERR (*lyplg_ext_parse_clb)(struct lysp_ctx *, struct lysp_ext_instance *);
diff --git a/cffi/source.c b/cffi/source.c
index 34e18b0..3c76e98 100644
--- a/cffi/source.c
+++ b/cffi/source.c
@@ -6,6 +6,6 @@
#include <libyang/libyang.h>
#include <libyang/version.h>
-#if LY_VERSION_MAJOR * 10000 + LY_VERSION_MINOR * 100 + LY_VERSION_MICRO < 30801
-#error "This version of libyang bindings only works with libyang soversion 3.8.1+"
+#if LY_VERSION_MAJOR * 10000 + LY_VERSION_MINOR * 100 + LY_VERSION_MICRO < 40202
+#error "This version of libyang bindings only works with libyang soversion 4.2.2+"
#endif
diff --git a/libyang/context.py b/libyang/context.py
index 4489680..21db162 100644
--- a/libyang/context.py
+++ b/libyang/context.py
@@ -205,6 +205,7 @@ def __init__(
builtin_plugins_only: bool = False,
all_implemented: bool = False,
enable_imp_features: bool = False,
+ compile_obsolete: bool = False,
yanglib_path: Optional[str] = None,
yanglib_fmt: str = "json",
cdata=None, # C type: "struct ly_ctx *"
@@ -231,6 +232,8 @@ def __init__(
options |= lib.LY_CTX_ALL_IMPLEMENTED
if enable_imp_features:
options |= lib.LY_CTX_ENABLE_IMP_FEATURES
+ if compile_obsolete:
+ options |= lib.LY_CTX_COMPILE_OBSOLETE
# force priv parsed
options |= lib.LY_CTX_SET_PRIV_PARSED
@@ -259,6 +262,7 @@ def __init__(
fmt = lib.LYD_JSON
else:
fmt = lib.LYD_XML
+ print("steweg", search_path, yanglib_path, yanglib_fmt, options)
ret = lib.ly_ctx_new_ylpath(
str2c(search_path), str2c(yanglib_path), fmt, options, ctx
)
@@ -542,6 +546,8 @@ def parse_op(
in_data: Union[IO, str],
dtype: DataType,
parent: DNode = None,
+ opaq: bool = False,
+ strict: bool = False,
) -> DNode:
fmt = data_format(fmt)
data = ffi.new("struct ly_in **")
@@ -551,13 +557,14 @@ def parse_op(
if ret != lib.LY_SUCCESS:
raise self.error("failed to read input data")
+ flags = parser_flags(opaq=opaq, strict=strict)
tree = ffi.new("struct lyd_node **", ffi.NULL)
op = ffi.new("struct lyd_node **", ffi.NULL)
par = ffi.new("struct lyd_node **", ffi.NULL)
if parent is not None:
par[0] = parent.cdata
- ret = lib.lyd_parse_op(self.cdata, par[0], data[0], fmt, dtype, tree, op)
+ ret = lib.lyd_parse_op(self.cdata, par[0], data[0], fmt, dtype, flags, tree, op)
lib.ly_in_free(data[0], 0)
if ret != lib.LY_SUCCESS:
raise self.error("failed to parse input data")
@@ -570,9 +577,17 @@ def parse_op_mem(
data: str,
dtype: DataType = DataType.DATA_YANG,
parent: DNode = None,
+ opaq: bool = False,
+ strict: bool = False,
):
return self.parse_op(
- fmt, in_type=IOType.MEMORY, in_data=data, dtype=dtype, parent=parent
+ fmt,
+ in_type=IOType.MEMORY,
+ in_data=data,
+ dtype=dtype,
+ parent=parent,
+ opaq=opaq,
+ strict=strict,
)
def parse_data(
@@ -581,7 +596,6 @@ def parse_data(
in_type: IOType,
in_data: Union[str, bytes, IO],
parent: DNode = None,
- lyb_mod_update: bool = False,
no_state: bool = False,
parse_only: bool = False,
opaq: bool = False,
@@ -596,7 +610,6 @@ def parse_data(
if self.cdata is None:
raise RuntimeError("context already destroyed")
parser_flgs = parser_flags(
- lyb_mod_update=lyb_mod_update,
no_state=no_state,
parse_only=parse_only,
opaq=opaq,
@@ -640,7 +653,6 @@ def parse_data_mem(
data: Union[str, bytes],
fmt: str,
parent: DNode = None,
- lyb_mod_update: bool = False,
no_state: bool = False,
parse_only: bool = False,
opaq: bool = False,
@@ -657,7 +669,6 @@ def parse_data_mem(
in_type=IOType.MEMORY,
in_data=data,
parent=parent,
- lyb_mod_update=lyb_mod_update,
no_state=no_state,
parse_only=parse_only,
opaq=opaq,
@@ -675,7 +686,6 @@ def parse_data_file(
fileobj: IO,
fmt: str,
parent: DNode = None,
- lyb_mod_update: bool = False,
no_state: bool = False,
parse_only: bool = False,
opaq: bool = False,
@@ -692,7 +702,6 @@ def parse_data_file(
in_type=IOType.FD,
in_data=fileobj,
parent=parent,
- lyb_mod_update=lyb_mod_update,
no_state=no_state,
parse_only=parse_only,
opaq=opaq,
diff --git a/libyang/data.py b/libyang/data.py
index 7a5887b..230c51a 100644
--- a/libyang/data.py
+++ b/libyang/data.py
@@ -53,11 +53,11 @@ def printer_flags(
) -> int:
flags = 0
if with_siblings:
- flags |= lib.LYD_PRINT_WITHSIBLINGS
+ flags |= lib.LYD_PRINT_SIBLINGS
if not pretty:
flags |= lib.LYD_PRINT_SHRINK
if keep_empty_containers:
- flags |= lib.LYD_PRINT_KEEPEMPTYCONT
+ flags |= lib.LYD_PRINT_EMPTY_CONT
if trim_default_values:
flags |= lib.LYD_PRINT_WD_TRIM
if include_implicit_defaults:
@@ -109,7 +109,6 @@ def newval_flags(
# -------------------------------------------------------------------------------------
def parser_flags(
- lyb_mod_update: bool = False,
no_state: bool = False,
parse_only: bool = False,
opaq: bool = False,
@@ -120,8 +119,6 @@ def parser_flags(
json_string_datatypes: bool = False,
) -> int:
flags = 0
- if lyb_mod_update:
- flags |= lib.LYD_PARSE_LYB_MOD_UPDATE
if no_state:
flags |= lib.LYD_PARSE_NO_STATE
if parse_only:
diff --git a/libyang/extension.py b/libyang/extension.py
index 57f7cb2..f7e4ba9 100644
--- a/libyang/extension.py
+++ b/libyang/extension.py
@@ -8,7 +8,7 @@
from _libyang import ffi, lib
from .context import Context
from .log import get_libyang_level
-from .schema import ExtensionCompiled, ExtensionParsed, Module
+from .schema import ExtensionCompiled, ExtensionParsed, Module, SNode
from .util import LibyangError, c2str, str2c
@@ -25,7 +25,7 @@ def __init__(self, message: str, ret: int, log_level: int) -> None:
@ffi.def_extern(name="lypy_lyplg_ext_parse_clb")
def libyang_c_lyplg_ext_parse_clb(pctx, pext):
- plugin = extensions_plugins[pext.record.plugin]
+ plugin = extensions_plugins[lib.lysc_get_ext_plugin(pext.plugin_ref)]
module_cdata = lib.lyplg_ext_parse_get_cur_pmod(pctx).mod
context = Context(cdata=module_cdata.ctx)
module = Module(context, module_cdata)
@@ -46,7 +46,7 @@ def libyang_c_lyplg_ext_parse_clb(pctx, pext):
@ffi.def_extern(name="lypy_lyplg_ext_compile_clb")
def libyang_c_lyplg_ext_compile_clb(cctx, pext, cext):
- plugin = extensions_plugins[pext.record.plugin]
+ plugin = extensions_plugins[lib.lysc_get_ext_plugin(pext.plugin_ref)]
context = Context(cdata=lib.lyplg_ext_compile_get_ctx(cctx))
module = Module(context, cext.module)
parsed_ext = ExtensionParsed(context, pext, module)
@@ -67,7 +67,7 @@ def libyang_c_lyplg_ext_compile_clb(cctx, pext, cext):
@ffi.def_extern(name="lypy_lyplg_ext_parse_free_clb")
def libyang_c_lyplg_ext_parse_free_clb(ctx, pext):
- plugin = extensions_plugins[pext.record.plugin]
+ plugin = extensions_plugins[lib.lysc_get_ext_plugin(pext.plugin_ref)]
context = Context(cdata=ctx)
parsed_ext = ExtensionParsed(context, pext, None)
plugin.parse_free_clb(parsed_ext)
@@ -75,7 +75,9 @@ def libyang_c_lyplg_ext_parse_free_clb(ctx, pext):
@ffi.def_extern(name="lypy_lyplg_ext_compile_free_clb")
def libyang_c_lyplg_ext_compile_free_clb(ctx, cext):
- plugin = extensions_plugins[getattr(cext, "def").plugin]
+ plugin = extensions_plugins[
+ lib.lysc_get_ext_plugin(getattr(cext, "def").plugin_ref)
+ ]
context = Context(cdata=ctx)
compiled_ext = ExtensionCompiled(context, cext)
plugin.compile_free_clb(compiled_ext)
@@ -200,9 +202,17 @@ def set_compile_ctx(self, cctx) -> None:
def parse_substmts(self, ext: ExtensionParsed) -> int:
return lib.lyplg_ext_parse_extension_instance(self._pctx, ext.cdata)
- def compile_substmts(self, pext: ExtensionParsed, cext: ExtensionCompiled) -> int:
+ def compile_substmts(
+ self,
+ pext: ExtensionParsed,
+ cext: ExtensionCompiled,
+ parent: Optional[SNode] = None,
+ ) -> int:
return lib.lyplg_ext_compile_extension_instance(
- self._cctx, pext.cdata, cext.cdata
+ self._cctx,
+ pext.cdata,
+ cext.cdata,
+ ffi.NULL if parent is None else parent.cdata,
)
def free_parse_substmts(self, ext: ExtensionParsed) -> None:
diff --git a/libyang/schema.py b/libyang/schema.py
index 23c1b1b..f104a87 100644
--- a/libyang/schema.py
+++ b/libyang/schema.py
@@ -1522,21 +1522,35 @@ def new(context: "libyang.Context", cdata) -> "SNode":
# -------------------------------------------------------------------------------------
@SNode.register(SNode.LEAF)
class SLeaf(SNode):
- __slots__ = ("cdata_leaf", "cdata_leaf_parsed")
+ __slots__ = ("cdata_leaf", "cdata_leaf_parsed", "cdata_default_realtype")
def __init__(self, context: "libyang.Context", cdata):
super().__init__(context, cdata)
self.cdata_leaf = ffi.cast("struct lysc_node_leaf *", cdata)
self.cdata_leaf_parsed = ffi.cast("struct lysp_node_leaf *", self.cdata_parsed)
+ self.cdata_default_realtype = None
def default(self) -> Union[None, bool, int, str, float]:
- if not self.cdata_leaf.dflt:
+ if not self.cdata_leaf.dflt.str:
return None
- val = lib.lyd_value_get_canonical(self.context.cdata, self.cdata_leaf.dflt)
- if not val:
- return None
- val = c2str(val)
- val_type = Type(self.context, self.cdata_leaf.dflt.realtype, None)
+
+ if self.cdata_default_realtype is None:
+ # calculate real type of default value just once
+ val_type_cdata = ffi.new("struct lysc_type **", ffi.NULL)
+ ret = lib.lyd_value_validate_dflt(
+ self.cdata,
+ self.cdata_leaf.dflt.str,
+ self.cdata_leaf.dflt.prefixes,
+ ffi.NULL,
+ val_type_cdata,
+ ffi.NULL,
+ )
+ if ret != lib.LY_SUCCESS:
+ raise self.context.error("Unable to get real type of default value")
+ self.cdata_default_realtype = Type(self.context, val_type_cdata[0], None)
+
+ val = c2str(self.cdata_leaf.dflt.str)
+ val_type = self.cdata_default_realtype
if val_type.base() == Type.BOOL:
return val == "true"
if val_type.base() in Type.NUM_TYPES:
@@ -1563,7 +1577,7 @@ def __str__(self):
# -------------------------------------------------------------------------------------
@SNode.register(SNode.LEAFLIST)
class SLeafList(SNode):
- __slots__ = ("cdata_leaflist", "cdata_leaflist_parsed")
+ __slots__ = ("cdata_leaflist", "cdata_leaflist_parsed", "cdata_default_realtypes")
def __init__(self, context: "libyang.Context", cdata):
super().__init__(context, cdata)
@@ -1571,6 +1585,7 @@ def __init__(self, context: "libyang.Context", cdata):
self.cdata_leaflist_parsed = ffi.cast(
"struct lysp_node_leaflist *", self.cdata_parsed
)
+ self.cdata_default_realtypes = None
def ordered(self) -> bool:
return bool(self.cdata_parsed.flags & lib.LYS_ORDBY_USER)
@@ -1586,12 +1601,37 @@ def type(self) -> Type:
def defaults(self) -> Iterator[Union[None, bool, int, str, float]]:
if self.cdata_leaflist.dflts == ffi.NULL:
return
- for dflt in ly_array_iter(self.cdata_leaflist.dflts):
- val = lib.lyd_value_get_canonical(self.context.cdata, dflt)
- if not val:
+
+ if self.cdata_default_realtypes is None:
+ # calculate real types of default values just once
+ val_type_cdata = ffi.new("struct lysc_type **", ffi.NULL)
+ self.cdata_default_realtypes = []
+ for dflt in ly_array_iter(self.cdata_leaflist.dflts):
+ if not dflt.str:
+ self.cdata_default_realtypes.append(None)
+ continue
+ val_type_cdata[0] = ffi.NULL
+ ret = lib.lyd_value_validate_dflt(
+ self.cdata,
+ dflt.str,
+ dflt.prefixes,
+ ffi.NULL,
+ val_type_cdata,
+ ffi.NULL,
+ )
+ if ret != lib.LY_SUCCESS:
+ raise self.context.error("Unable to get real type of default value")
+ self.cdata_default_realtypes.append(
+ Type(self.context, val_type_cdata[0], None)
+ )
+
+ for dflt, val_type in zip(
+ ly_array_iter(self.cdata_leaflist.dflts), self.cdata_default_realtypes
+ ):
+ if not dflt.str:
yield None
- val = c2str(val)
- val_type = Type(self.context, dflt.realtype, None)
+ continue
+ val = c2str(dflt.str)
if val_type.base() == Type.BOOL:
yield val == "true"
elif val_type.base() in Type.NUM_TYPES:
diff --git a/tests/test_context.py b/tests/test_context.py
index 61c0ae8..8ffd045 100644
--- a/tests/test_context.py
+++ b/tests/test_context.py
@@ -20,7 +20,11 @@ def test_ctx_no_dir(self):
self.assertIsNot(ctx, None)
def test_ctx_yanglib(self):
- ctx = Context(YANG_DIR, yanglib_path=YANG_DIR + "/yang-library.json")
+ ctx = Context(
+ YANG_DIR,
+ yanglib_path=YANG_DIR + "/yang-library.json",
+ compile_obsolete=True,
+ )
ctx.load_module("yolo-system")
dnode = ctx.get_yanglib_data()
j = dnode.print_mem("json", with_siblings=True)
diff --git a/tests/test_data.py b/tests/test_data.py
index 430873a..8f56dc1 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -33,7 +33,7 @@
# -------------------------------------------------------------------------------------
class DataTest(unittest.TestCase):
def setUp(self):
- self.ctx = Context(YANG_DIR)
+ self.ctx = Context(YANG_DIR, compile_obsolete=True)
modules = [
self.ctx.load_module("ietf-netconf"),
self.ctx.load_module("yolo-system"),
@@ -51,18 +51,18 @@ def tearDown(self):
"yolo-system:conf": {
"hostname": "foo",
"url": [
- {
- "proto": "https",
- "host": "github.com",
- "path": "/CESNET/libyang-python",
- "enabled": false
- },
{
"proto": "http",
"host": "foobar.com",
"port": 8080,
"path": "/index.html",
"enabled": true
+ },
+ {
+ "proto": "https",
+ "host": "github.com",
+ "path": "/CESNET/libyang-python",
+ "enabled": false
}
],
"number": [
@@ -76,7 +76,9 @@ def tearDown(self):
"""
def test_data_parse_config_json(self):
- dnode = self.ctx.parse_data_mem(self.JSON_CONFIG, "json", no_state=True)
+ dnode = self.ctx.parse_data_mem(
+ self.JSON_CONFIG, "json", no_state=True, ordered=True
+ )
self.assertIsInstance(dnode, DContainer)
try:
j = dnode.print_mem("json", with_siblings=True)
@@ -91,18 +93,18 @@ def test_data_parse_config_json(self):
"yolo-system:conf": {
"hostname": "foo",
"url": [
- {
- "proto": "https",
- "host": "github.com",
- "path": "/CESNET/libyang-python",
- "enabled": false
- },
{
"proto": "http",
"host": "foobar.com",
"port": 8080,
"path": "/index.html",
"enabled": true
+ },
+ {
+ "proto": "https",
+ "host": "github.com",
+ "path": "/CESNET/libyang-python",
+ "enabled": false
}
],
"number": [
@@ -128,12 +130,6 @@ def test_data_parse_config_json_without_yang_lib(self):
"yolo-system:conf": {
"hostname": "foo",
"url": [
- {
- "proto": "https",
- "host": "github.com",
- "path": "/CESNET/libyang-python",
- "enabled": false
- },
{
"proto": "http",
"host": "barfoo.com",
@@ -145,6 +141,12 @@ def test_data_parse_config_json_without_yang_lib(self):
"port": 8080,
"path": "/index.html",
"enabled": true
+ },
+ {
+ "proto": "https",
+ "host": "github.com",
+ "path": "/CESNET/libyang-python",
+ "enabled": false
}
],
"number": [
@@ -254,7 +256,9 @@ def test_data_parse_state_json(self):
"""
def test_data_parse_config_xml(self):
- dnode = self.ctx.parse_data_mem(self.XML_CONFIG, "xml", validate_present=True)
+ dnode = self.ctx.parse_data_mem(
+ self.XML_CONFIG, "xml", validate_present=True, ordered=True
+ )
self.assertIsInstance(dnode, DContainer)
try:
xml = dnode.print_mem("xml", with_siblings=True, trim_default_values=True)
@@ -509,6 +513,7 @@ def test_data_from_dict_module_free_func(self):
}
def test_data_from_dict_module_with_prefix(self):
+ self.maxDiff = None
module = self.ctx.get_module("yolo-system")
dnode = module.parse_data_dict(
self.DICT_CONFIG_WITH_PREFIX, strict=True, validate_present=True
@@ -853,17 +858,17 @@ def test_data_diff(self):
TREE = [
"/yolo-system:conf",
"/yolo-system:conf/hostname",
- "/yolo-system:conf/url[proto='https'][host='github.com']",
- "/yolo-system:conf/url[proto='https'][host='github.com']/proto",
- "/yolo-system:conf/url[proto='https'][host='github.com']/host",
- "/yolo-system:conf/url[proto='https'][host='github.com']/path",
- "/yolo-system:conf/url[proto='https'][host='github.com']/enabled",
"/yolo-system:conf/url[proto='http'][host='foobar.com']",
"/yolo-system:conf/url[proto='http'][host='foobar.com']/proto",
"/yolo-system:conf/url[proto='http'][host='foobar.com']/host",
"/yolo-system:conf/url[proto='http'][host='foobar.com']/port",
"/yolo-system:conf/url[proto='http'][host='foobar.com']/path",
"/yolo-system:conf/url[proto='http'][host='foobar.com']/enabled",
+ "/yolo-system:conf/url[proto='https'][host='github.com']",
+ "/yolo-system:conf/url[proto='https'][host='github.com']/proto",
+ "/yolo-system:conf/url[proto='https'][host='github.com']/host",
+ "/yolo-system:conf/url[proto='https'][host='github.com']/path",
+ "/yolo-system:conf/url[proto='https'][host='github.com']/enabled",
"/yolo-system:conf/number[.='1000']",
"/yolo-system:conf/number[.='2000']",
"/yolo-system:conf/number[.='3000']",
@@ -906,7 +911,7 @@ def test_find_all(self):
}
]
}
- self.assertEqual(urls[0].print_dict(absolute=False), expected_url)
+ self.assertEqual(urls[1].print_dict(absolute=False), expected_url)
finally:
dnode.free()
@@ -1090,7 +1095,9 @@ def test_dnode_leafref_linking(self):
"yolo-leafref-extended:ref1": "val1"
}"""
self.ctx.destroy()
- self.ctx = Context(YANG_DIR, leafref_extended=True, leafref_linking=True)
+ self.ctx = Context(
+ YANG_DIR, leafref_extended=True, leafref_linking=True, compile_obsolete=True
+ )
mod = self.ctx.load_module("yolo-leafref-extended")
self.assertIsInstance(mod, Module)
dnode1 = self.ctx.parse_data_mem(MAIN, "json", parse_only=True)
@@ -1121,7 +1128,7 @@ def test_dnode_builtin_plugins_only(self):
MAIN = {"yolo-nodetypes:ip-address": "test"}
self.tearDown()
gc.collect()
- self.ctx = Context(YANG_DIR, builtin_plugins_only=True)
+ self.ctx = Context(YANG_DIR, builtin_plugins_only=True, compile_obsolete=True)
module = self.ctx.load_module("yolo-nodetypes")
dnode = dict_to_dnode(MAIN, module, None, validate=False, store_only=True)
self.assertIsInstance(dnode, DLeaf)
@@ -1140,7 +1147,7 @@ def test_merge_builtin_plugins_only(self):
MAIN = {"yolo-nodetypes:ip-address": "test"}
self.tearDown()
gc.collect()
- self.ctx = Context(YANG_DIR, builtin_plugins_only=True)
+ self.ctx = Context(YANG_DIR, builtin_plugins_only=True, compile_obsolete=True)
module = self.ctx.load_module("yolo-nodetypes")
dnode = module.parse_data_dict(MAIN, validate=False, store_only=True)
self.assertIsInstance(dnode, DLeaf)
diff --git a/tests/test_diff.py b/tests/test_diff.py
index d4b7e87..2263e34 100644
--- a/tests/test_diff.py
+++ b/tests/test_diff.py
@@ -97,7 +97,9 @@ class DiffTest(unittest.TestCase):
)
def test_diff(self):
- with Context(OLD_YANG_DIR) as ctx_old, Context(NEW_YANG_DIR) as ctx_new:
+ with Context(OLD_YANG_DIR, compile_obsolete=True) as ctx_old, Context(
+ NEW_YANG_DIR, compile_obsolete=True
+ ) as ctx_new:
mod = ctx_old.load_module("yolo-system")
mod.feature_enable_all()
mod = ctx_new.load_module("yolo-system")
diff --git a/tests/test_schema.py b/tests/test_schema.py
index b1862ab..a1ca412 100644
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -272,7 +272,7 @@ def test_iffeature_dump(self):
# -------------------------------------------------------------------------------------
class ContainerTest(unittest.TestCase):
def setUp(self):
- self.ctx = Context(YANG_DIR)
+ self.ctx = Context(YANG_DIR, compile_obsolete=True)
mod = self.ctx.load_module("yolo-system")
mod.feature_enable_all()
self.container = next(self.ctx.find_path("/yolo-system:conf"))
@@ -549,7 +549,7 @@ def test_rpc_parsed(self):
# -------------------------------------------------------------------------------------
class LeafTypeTest(unittest.TestCase):
def setUp(self):
- self.ctx = Context(YANG_DIR)
+ self.ctx = Context(YANG_DIR, compile_obsolete=True)
self.ctx.load_module("yolo-system")
def tearDown(self):