From ba030282bd76ec073749a3a9ee442adf2e092ccf Mon Sep 17 00:00:00 2001 From: Antonio Prcela Date: Thu, 2 Apr 2026 10:46:43 +0200 Subject: [PATCH 1/3] cffi: allows to usage of libyang v5 Adapt CFFI bindings for libyang v5 (soversion 5.0.0+) Update cdefs.h, source.c, and Python call sites to match the libyang 4.2.2 -> 5.0.0 API changes: - parent field type changed from lyd_node_inner* to lyd_node* across all node structs - lyd_any_value_str gained a LYD_FORMAT parameter - lys_find_child signature was reworked - lyd_node_any lost the union lyd_any_value/LYD_ANYDATA_VALUETYPE fields - LYD_NEW_VAL_BIN / LYS_GETNEXT_WITHSCHEMAMOUNT removed Signed-off-by: Antonio Prcela --- cffi/cdefs.h | 41 +++++++++++------------------------------ cffi/source.c | 4 ++-- libyang/data.py | 6 ++---- libyang/schema.py | 2 -- 4 files changed, 15 insertions(+), 38 deletions(-) diff --git a/cffi/cdefs.h b/cffi/cdefs.h index 82ec974..afabe26 100644 --- a/cffi/cdefs.h +++ b/cffi/cdefs.h @@ -262,7 +262,7 @@ struct lyd_node { uint32_t hash; uint32_t flags; const struct lysc_node *schema; - struct lyd_node_inner *parent; + struct lyd_node *parent; struct lyd_node *next; struct lyd_node *prev; struct lyd_meta *meta; @@ -273,7 +273,6 @@ LY_ERR lys_set_implemented(struct lys_module *, const char **); #define LYD_NEW_VAL_OUTPUT ... #define LYD_NEW_VAL_STORE_ONLY ... -#define LYD_NEW_VAL_BIN ... #define LYD_NEW_VAL_CANON ... #define LYD_NEW_META_CLEAR_DFLT ... #define LYD_NEW_PATH_UPDATE ... @@ -876,9 +875,8 @@ struct lysc_ext { #define LYS_GETNEXT_WITHCASE ... #define LYS_GETNEXT_INTONPCONT ... #define LYS_GETNEXT_OUTPUT ... -#define LYS_GETNEXT_WITHSCHEMAMOUNT ... -const struct lysc_node* lys_find_child(const struct lysc_node *, const struct lys_module *, const char *, size_t, uint16_t, uint32_t); +const struct lysc_node* lys_find_child(const struct ly_ctx *, const struct lysc_node *, const struct lys_module *, const char *, uint32_t, const char *, uint32_t, uint32_t); const struct lysc_node* lysc_node_child(const struct lysc_node *); const struct lysc_node_action* lysc_node_actions(const struct lysc_node *); const struct lysc_node_notif* lysc_node_notifs(const struct lysc_node *); @@ -902,7 +900,7 @@ struct lyd_node_inner { uint32_t hash; uint32_t flags; const struct lysc_node *schema; - struct lyd_node_inner *parent; + struct lyd_node *parent; struct lyd_node *next; struct lyd_node *prev; struct lyd_meta *meta; @@ -924,7 +922,7 @@ struct lyd_node_term { uint32_t hash; uint32_t flags; const struct lysc_node *schema; - struct lyd_node_inner *parent; + struct lyd_node *parent; struct lyd_node *next; struct lyd_node *prev; struct lyd_meta *meta; @@ -984,9 +982,6 @@ struct lysc_must { struct lysc_ext_instance *exts; }; -struct pcre2_real_code; -typedef struct pcre2_real_code pcre2_code; - struct lysc_pattern { const char *expr; const char *dsc; @@ -1161,20 +1156,6 @@ struct lyd_meta { struct lyd_value value; }; -typedef enum { - LYD_ANYDATA_DATATREE, - LYD_ANYDATA_STRING, - LYD_ANYDATA_XML, - LYD_ANYDATA_JSON -} LYD_ANYDATA_VALUETYPE; - -union lyd_any_value { - struct lyd_node *tree; - const char *str; - const char *xml; - const char *json; -}; - struct lyd_node_any { union { struct lyd_node node; @@ -1182,18 +1163,18 @@ struct lyd_node_any { uint32_t hash; uint32_t flags; const struct lysc_node *schema; - struct lyd_node_inner *parent; + struct lyd_node *parent; struct lyd_node *next; struct lyd_node *prev; struct lyd_meta *meta; void *priv; }; }; - union lyd_any_value value; - LYD_ANYDATA_VALUETYPE value_type; + struct lyd_node *child; + ...; }; -LY_ERR lyd_any_value_str(const struct lyd_node *, char **); +LY_ERR lyd_any_value_str(const struct lyd_node *, LYD_FORMAT, char **); #define LYD_MERGE_DEFAULTS ... #define LYD_MERGE_DESTRUCT ... @@ -1212,8 +1193,8 @@ LY_ERR lyd_diff_apply_all(struct lyd_node **, const struct lyd_node *); #define LYD_DUP_WITH_FLAGS ... #define LYD_DUP_WITH_PARENTS ... -LY_ERR lyd_dup_siblings(const struct lyd_node *, struct lyd_node_inner *, uint32_t, struct lyd_node **); -LY_ERR lyd_dup_single(const struct lyd_node *, struct lyd_node_inner *, uint32_t, struct lyd_node **); +LY_ERR lyd_dup_siblings(const struct lyd_node *, struct lyd_node *, uint32_t, struct lyd_node **); +LY_ERR lyd_dup_single(const struct lyd_node *, struct lyd_node *, uint32_t, struct lyd_node **); void lyd_free_meta_single(struct lyd_meta *); struct lysp_tpdf { @@ -1291,7 +1272,7 @@ struct lyd_node_opaq { uint32_t hash; uint32_t flags; const struct lysc_node *schema; - struct lyd_node_inner *parent; + struct lyd_node *parent; struct lyd_node *next; struct lyd_node *prev; struct lyd_meta *meta; diff --git a/cffi/source.c b/cffi/source.c index 3c76e98..88b08bd 100644 --- a/cffi/source.c +++ b/cffi/source.c @@ -6,6 +6,6 @@ #include #include -#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+" +#if LY_VERSION_MAJOR * 10000 + LY_VERSION_MINOR * 100 + LY_VERSION_MICRO < 50000 +#error "This version of libyang bindings only works with libyang soversion 5.0.0+" #endif diff --git a/libyang/data.py b/libyang/data.py index 230c51a..97a492c 100644 --- a/libyang/data.py +++ b/libyang/data.py @@ -94,8 +94,6 @@ def newval_flags( flags |= lib.LYD_NEW_VAL_OUTPUT if store_only: flags |= lib.LYD_NEW_VAL_STORE_ONLY - if bin_value: - flags |= lib.LYD_NEW_VAL_BIN if canon_value: flags |= lib.LYD_NEW_VAL_CANON if meta_clear_default: @@ -1174,7 +1172,7 @@ class DNotif(DContainer): class DAnyxml(DNode): def value(self, fmt: str = "xml"): anystr = ffi.new("char **", ffi.NULL) - ret = lib.lyd_any_value_str(self.cdata, anystr) + ret = lib.lyd_any_value_str(self.cdata, data_format(fmt), anystr) if ret != lib.LY_SUCCESS: raise self.context.error("cannot get data") return c2str(anystr[0]) @@ -1185,7 +1183,7 @@ def value(self, fmt: str = "xml"): class DAnydata(DNode): def value(self, fmt: str = "xml"): anystr = ffi.new("char **", ffi.NULL) - ret = lib.lyd_any_value_str(self.cdata, anystr) + ret = lib.lyd_any_value_str(self.cdata, data_format(fmt), anystr) if ret != lib.LY_SUCCESS: raise self.context.error("cannot get data") return c2str(anystr[0]) diff --git a/libyang/schema.py b/libyang/schema.py index d3f5465..0236d07 100644 --- a/libyang/schema.py +++ b/libyang/schema.py @@ -1885,8 +1885,6 @@ def iter_children_options( options |= lib.LYS_GETNEXT_INTONPCONT if output: options |= lib.LYS_GETNEXT_OUTPUT - if with_schema_mount: - options |= lib.LYS_GETNEXT_WITHSCHEMAMOUNT return options From 1c1728b5370af859b99f87c75ca45c6dbd4344f4 Mon Sep 17 00:00:00 2001 From: Antonio Prcela Date: Thu, 2 Apr 2026 11:42:47 +0200 Subject: [PATCH 2/3] tests: fix failures caused by libyang v5 changes Add missing ietf-inet-types YANG module to the test search path, as libyang v5 no longer resolves it automatically. Update the module data callback test to handle the ietf-inet-types dependency, and adjust expected error paths to match libyang v5 output. Signed-off-by: Antonio Prcela --- tests/test_context.py | 11 +- tests/test_data.py | 8 +- .../yang/ietf/ietf-inet-types@2013-07-15.yang | 457 ++++++++++++++++++ 3 files changed, 469 insertions(+), 7 deletions(-) create mode 100644 tests/yang/ietf/ietf-inet-types@2013-07-15.yang diff --git a/tests/test_context.py b/tests/test_context.py index 8ffd045..6e0dde8 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -154,9 +154,14 @@ def test_ctx_disable_searchdirs(self): def test_ctx_using_clb(self): def get_module_valid_clb(mod_name, *_): - YOLO_NODETYPES_MOD_PATH = os.path.join(YANG_DIR, "yolo/yolo-nodetypes.yang") - self.assertEqual(mod_name, "yolo-nodetypes") - with open(YOLO_NODETYPES_MOD_PATH, encoding="utf-8") as f: + MOD_PATHS = { + "yolo-nodetypes": os.path.join(YANG_DIR, "yolo/yolo-nodetypes.yang"), + "ietf-inet-types": os.path.join( + YANG_DIR, "ietf/ietf-inet-types@2013-07-15.yang" + ), + } + self.assertIn(mod_name, MOD_PATHS) + with open(MOD_PATHS[mod_name], encoding="utf-8") as f: mod_str = f.read() return "yang", mod_str diff --git a/tests/test_data.py b/tests/test_data.py index 8f56dc1..5210147 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -288,21 +288,21 @@ def test_data_parse_config_xml_multi_error(self): self.assertEqual( str(cm.exception), 'failed to parse data tree: Invalid boolean value "abcd".: ' - "Data path: /yolo-system:conf/url[proto='https']/enabled (line 6): " + "Data path: /yolo-system:url[proto='https']/enabled (line 6): " 'List instance is missing its key "host".: ' - "Data path: /yolo-system:conf/url[proto='https'] (line 7)", + "Data path: /yolo-system:url[proto='https'] (line 7)", ) first = cm.exception.errors[0] self.assertEqual(first.msg, 'Invalid boolean value "abcd".') self.assertEqual( - first.data_path, "/yolo-system:conf/url[proto='https']/enabled" + first.data_path, "/yolo-system:url[proto='https']/enabled" ) self.assertEqual(first.line, 6) second = cm.exception.errors[1] self.assertEqual(second.msg, 'List instance is missing its key "host".') - self.assertEqual(second.data_path, "/yolo-system:conf/url[proto='https']") + self.assertEqual(second.data_path, "/yolo-system:url[proto='https']") self.assertEqual(second.line, 7) XML_STATE = """ diff --git a/tests/yang/ietf/ietf-inet-types@2013-07-15.yang b/tests/yang/ietf/ietf-inet-types@2013-07-15.yang new file mode 100644 index 0000000..2f14270 --- /dev/null +++ b/tests/yang/ietf/ietf-inet-types@2013-07-15.yang @@ -0,0 +1,457 @@ +module ietf-inet-types { + + namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types"; + prefix "inet"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Kessens + + + WG Chair: Juergen Schoenwaelder + + + Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of generally useful derived + YANG data types for Internet addresses and related things. + + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6991; see + the RFC itself for full legal notices."; + + revision 2013-07-15 { + description + "This revision adds the following new data types: + - ip-address-no-zone + - ipv4-address-no-zone + - ipv6-address-no-zone"; + reference + "RFC 6991: Common YANG Data Types"; + } + + revision 2010-09-24 { + description + "Initial revision."; + reference + "RFC 6021: Common YANG Data Types"; + } + + /*** collection of types related to protocol fields ***/ + + typedef ip-version { + type enumeration { + enum unknown { + value "0"; + description + "An unknown or unspecified version of the Internet + protocol."; + } + enum ipv4 { + value "1"; + description + "The IPv4 protocol as defined in RFC 791."; + } + enum ipv6 { + value "2"; + description + "The IPv6 protocol as defined in RFC 2460."; + } + } + description + "This value represents the version of the IP protocol. + + In the value set and its semantics, this type is equivalent + to the InetVersion textual convention of the SMIv2."; + reference + "RFC 791: Internet Protocol + RFC 2460: Internet Protocol, Version 6 (IPv6) Specification + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + typedef dscp { + type uint8 { + range "0..63"; + } + description + "The dscp type represents a Differentiated Services Code Point + that may be used for marking packets in a traffic stream. + In the value set and its semantics, this type is equivalent + to the Dscp textual convention of the SMIv2."; + reference + "RFC 3289: Management Information Base for the Differentiated + Services Architecture + RFC 2474: Definition of the Differentiated Services Field + (DS Field) in the IPv4 and IPv6 Headers + RFC 2780: IANA Allocation Guidelines For Values In + the Internet Protocol and Related Headers"; + } + + typedef ipv6-flow-label { + type uint32 { + range "0..1048575"; + } + description + "The ipv6-flow-label type represents the flow identifier or Flow + Label in an IPv6 packet header that may be used to + discriminate traffic flows. + + In the value set and its semantics, this type is equivalent + to the IPv6FlowLabel textual convention of the SMIv2."; + reference + "RFC 3595: Textual Conventions for IPv6 Flow Label + RFC 2460: Internet Protocol, Version 6 (IPv6) Specification"; + } + + typedef port-number { + type uint16 { + range "0..65535"; + } + description + "The port-number type represents a 16-bit port number of an + Internet transport-layer protocol such as UDP, TCP, DCCP, or + SCTP. Port numbers are assigned by IANA. A current list of + all assignments is available from . + + Note that the port number value zero is reserved by IANA. In + situations where the value zero does not make sense, it can + be excluded by subtyping the port-number type. + In the value set and its semantics, this type is equivalent + to the InetPortNumber textual convention of the SMIv2."; + reference + "RFC 768: User Datagram Protocol + RFC 793: Transmission Control Protocol + RFC 4960: Stream Control Transmission Protocol + RFC 4340: Datagram Congestion Control Protocol (DCCP) + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + /*** collection of types related to autonomous systems ***/ + + typedef as-number { + type uint32; + description + "The as-number type represents autonomous system numbers + which identify an Autonomous System (AS). An AS is a set + of routers under a single technical administration, using + an interior gateway protocol and common metrics to route + packets within the AS, and using an exterior gateway + protocol to route packets to other ASes. IANA maintains + the AS number space and has delegated large parts to the + regional registries. + + Autonomous system numbers were originally limited to 16 + bits. BGP extensions have enlarged the autonomous system + number space to 32 bits. This type therefore uses an uint32 + base type without a range restriction in order to support + a larger autonomous system number space. + + In the value set and its semantics, this type is equivalent + to the InetAutonomousSystemNumber textual convention of + the SMIv2."; + reference + "RFC 1930: Guidelines for creation, selection, and registration + of an Autonomous System (AS) + RFC 4271: A Border Gateway Protocol 4 (BGP-4) + RFC 4001: Textual Conventions for Internet Network Addresses + RFC 6793: BGP Support for Four-Octet Autonomous System (AS) + Number Space"; + } + + /*** collection of types related to IP addresses and hostnames ***/ + + typedef ip-address { + type union { + type inet:ipv4-address; + type inet:ipv6-address; + } + description + "The ip-address type represents an IP address and is IP + version neutral. The format of the textual representation + implies the IP version. This type supports scoped addresses + by allowing zone identifiers in the address format."; + reference + "RFC 4007: IPv6 Scoped Address Architecture"; + } + + typedef ipv4-address { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '(%[\p{N}\p{L}]+)?'; + } + description + "The ipv4-address type represents an IPv4 address in + dotted-quad notation. The IPv4 address may include a zone + index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format for the zone index is the numerical + format"; + } + + typedef ipv6-address { + type string { + pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}' + + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|' + + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}' + + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))' + + '(%[\p{N}\p{L}]+)?'; + pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|' + + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)' + + '(%.+)?'; + } + description + "The ipv6-address type represents an IPv6 address in full, + mixed, shortened, and shortened-mixed notation. The IPv6 + address may include a zone index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format of IPv6 addresses uses the textual + representation defined in Section 4 of RFC 5952. The + canonical format for the zone index is the numerical + format as described in Section 11.2 of RFC 4007."; + reference + "RFC 4291: IP Version 6 Addressing Architecture + RFC 4007: IPv6 Scoped Address Architecture + RFC 5952: A Recommendation for IPv6 Address Text + Representation"; + } + + typedef ip-address-no-zone { + type union { + type inet:ipv4-address-no-zone; + type inet:ipv6-address-no-zone; + } + description + "The ip-address-no-zone type represents an IP address and is + IP version neutral. The format of the textual representation + implies the IP version. This type does not support scoped + addresses since it does not allow zone identifiers in the + address format."; + reference + "RFC 4007: IPv6 Scoped Address Architecture"; + } + + typedef ipv4-address-no-zone { + type inet:ipv4-address { + pattern '[0-9\.]*'; + } + description + "An IPv4 address without a zone index. This type, derived from + ipv4-address, may be used in situations where the zone is + known from the context and hence no zone index is needed."; + } + + typedef ipv6-address-no-zone { + type inet:ipv6-address { + pattern '[0-9a-fA-F:\.]*'; + } + description + "An IPv6 address without a zone index. This type, derived from + ipv6-address, may be used in situations where the zone is + known from the context and hence no zone index is needed."; + reference + "RFC 4291: IP Version 6 Addressing Architecture + RFC 4007: IPv6 Scoped Address Architecture + RFC 5952: A Recommendation for IPv6 Address Text + Representation"; + } + + typedef ip-prefix { + type union { + type inet:ipv4-prefix; + type inet:ipv6-prefix; + } + description + "The ip-prefix type represents an IP prefix and is IP + version neutral. The format of the textual representations + implies the IP version."; + } + + typedef ipv4-prefix { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '/(([0-9])|([1-2][0-9])|(3[0-2]))'; + } + description + "The ipv4-prefix type represents an IPv4 address prefix. + The prefix length is given by the number following the + slash character and must be less than or equal to 32. + + A prefix length value of n corresponds to an IP address + mask that has n contiguous 1-bits from the most + significant bit (MSB) and all other bits set to 0. + + The canonical format of an IPv4 prefix has all bits of + the IPv4 address set to zero that are not part of the + IPv4 prefix."; + } + + typedef ipv6-prefix { + type string { + pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}' + + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|' + + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}' + + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))' + + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))'; + pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|' + + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)' + + '(/.+)'; + } + description + "The ipv6-prefix type represents an IPv6 address prefix. + The prefix length is given by the number following the + slash character and must be less than or equal to 128. + + A prefix length value of n corresponds to an IP address + mask that has n contiguous 1-bits from the most + significant bit (MSB) and all other bits set to 0. + + The IPv6 address should have all bits that do not belong + to the prefix set to zero. + + The canonical format of an IPv6 prefix has all bits of + the IPv6 address set to zero that are not part of the + IPv6 prefix. Furthermore, the IPv6 address is represented + as defined in Section 4 of RFC 5952."; + reference + "RFC 5952: A Recommendation for IPv6 Address Text + Representation"; + } + + /*** collection of domain name and URI types ***/ + + typedef domain-name { + type string { + length "1..253"; + pattern + '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*' + + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)' + + '|\.'; + } + description + "The domain-name type represents a DNS domain name. The + name SHOULD be fully qualified whenever possible. + + Internet domain names are only loosely specified. Section + 3.5 of RFC 1034 recommends a syntax (modified in Section + 2.1 of RFC 1123). The pattern above is intended to allow + for current practice in domain name use, and some possible + future expansion. It is designed to hold various types of + domain names, including names used for A or AAAA records + (host names) and other records, such as SRV records. Note + that Internet host names have a stricter syntax (described + in RFC 952) than the DNS recommendations in RFCs 1034 and + 1123, and that systems that want to store host names in + schema nodes using the domain-name type are recommended to + adhere to this stricter standard to ensure interoperability. + + The encoding of DNS names in the DNS protocol is limited + to 255 characters. Since the encoding consists of labels + prefixed by a length bytes and there is a trailing NULL + byte, only 253 characters can appear in the textual dotted + notation. + + The description clause of schema nodes using the domain-name + type MUST describe when and how these names are resolved to + IP addresses. Note that the resolution of a domain-name value + may require to query multiple DNS records (e.g., A for IPv4 + and AAAA for IPv6). The order of the resolution process and + which DNS record takes precedence can either be defined + explicitly or may depend on the configuration of the + resolver. + + Domain-name values use the US-ASCII encoding. Their canonical + format uses lowercase US-ASCII characters. Internationalized + domain names MUST be A-labels as per RFC 5890."; + reference + "RFC 952: DoD Internet Host Table Specification + RFC 1034: Domain Names - Concepts and Facilities + RFC 1123: Requirements for Internet Hosts -- Application + and Support + RFC 2782: A DNS RR for specifying the location of services + (DNS SRV) + RFC 5890: Internationalized Domain Names in Applications + (IDNA): Definitions and Document Framework"; + } + + typedef host { + type union { + type inet:ip-address; + type inet:domain-name; + } + description + "The host type represents either an IP address or a DNS + domain name."; + } + + typedef uri { + type string; + description + "The uri type represents a Uniform Resource Identifier + (URI) as defined by STD 66. + + Objects using the uri type MUST be in US-ASCII encoding, + and MUST be normalized as described by RFC 3986 Sections + 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary + percent-encoding is removed, and all case-insensitive + characters are set to lowercase except for hexadecimal + digits, which are normalized to uppercase as described in + Section 6.2.2.1. + + The purpose of this normalization is to help provide + unique URIs. Note that this normalization is not + sufficient to provide uniqueness. Two URIs that are + textually distinct after this normalization may still be + equivalent. + + Objects using the uri type may restrict the schemes that + they permit. For example, 'data:' and 'urn:' schemes + might not be appropriate. + + A zero-length URI is not a valid URI. This can be used to + express 'URI absent' where required. + + In the value set and its semantics, this type is equivalent + to the Uri SMIv2 textual convention defined in RFC 5017."; + reference + "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax + RFC 3305: Report from the Joint W3C/IETF URI Planning Interest + Group: Uniform Resource Identifiers (URIs), URLs, + and Uniform Resource Names (URNs): Clarifications + and Recommendations + RFC 5017: MIB Textual Conventions for Uniform Resource + Identifiers (URIs)"; + } + +} From 1aa6dfb8de9a14b8cb96615ba1e5136ae8afa826 Mon Sep 17 00:00:00 2001 From: Antonio Prcela Date: Thu, 2 Apr 2026 11:45:46 +0200 Subject: [PATCH 3/3] tests: fix failing lint caused by libyang v5 changes - add missing ietf-inet-types YANG module - update callback test and error paths Signed-off-by: Antonio Prcela --- tests/test_data.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_data.py b/tests/test_data.py index 5210147..fd45b4f 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -295,9 +295,7 @@ def test_data_parse_config_xml_multi_error(self): first = cm.exception.errors[0] self.assertEqual(first.msg, 'Invalid boolean value "abcd".') - self.assertEqual( - first.data_path, "/yolo-system:url[proto='https']/enabled" - ) + self.assertEqual(first.data_path, "/yolo-system:url[proto='https']/enabled") self.assertEqual(first.line, 6) second = cm.exception.errors[1]