mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
877 lines
32 KiB
Diff
877 lines
32 KiB
Diff
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):
|