From 891325b31fb575d9a8e998f3ce47610afedc762c Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Fri, 2 Jun 2023 18:02:45 +0200 Subject: [PATCH 01/41] Add options to render relationships to choices and cases and suppress the title --- pyang/plugins/uml.py | 84 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 547f44fc..3b3e3e9b 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -46,6 +46,11 @@ def add_opts(self, optparser): optparse.make_option("--uml-title", dest="uml_title", help="Set the title of the generated UML, including the output file name"), + optparse.make_option("--uml-no-title", + action="store_true", + dest="uml_no_title", + default = False, + help="Do not include a title. If a title has also been specified as an option, it will be ignored."), optparse.make_option("--uml-header", dest="uml_header", help="Set the page header of the generated UML"), @@ -93,6 +98,19 @@ def add_opts(self, optparser): optparse.make_option("--uml-filter-file", dest="uml_filter_file", help="NOT IMPLEMENTED: Only paths in the filter file will be included in the diagram"), + optparse.make_option("--uml-unbound-is-star", + action="store_true", + dest="uml_unbound_is_star", + default = False, + help="Use a star ('*') to render unbounded upper limit multiplicity instead of an 'N'."), + optparse.make_option("--uml-node-choice", + dest="uml_node_choice", + default = "", + help="Selects how to render the relationship between a container or list and a choice. \nValid values are one of: aggregation, composition, dependency, generalization, realization (default dependency)"), + optparse.make_option("--uml-choice-case", + dest="uml_choice_case", + default = "", + help="Selects how to render the relationship between a choice and its cases. \nValid values are one of: aggregation, composition, dependency, generalization, realization (default dependency)"), ] if hasattr(optparser, 'uml_opts'): g = optparser.uml_opts @@ -134,6 +152,7 @@ class uml_emitter: ctx_pagelayout = '1x1' ctx_outputdir = "img/" ctx_title = None + ctx_no_title = False ctx_fullpath = False ctx_classesonly = False ctx_description = False @@ -150,6 +169,9 @@ class uml_emitter: ctx_truncate_augments = False ctx_inline_augments = False ctx_no_module = False + ctx_unbound_is_star = False + ctx_relationship_node_choice = "dependency" + ctx_relationship_choice_case = "dependency" ctx_filterfile = False ctx_usefilterfile = None @@ -167,11 +189,16 @@ class uml_emitter: post_strings = [] module_prefixes = [] + symbol_node_to_choice = ".." + symbol_choice_to_case = ".." + def __init__(self, ctx): self._ctx = ctx self.ctx_fullpath = ctx.opts.uml_longids self.ctx_description = ctx.opts.uml_descr self.ctx_classesonly = ctx.opts.uml_classes_only + self.ctx_no_title = ctx.opts.uml_no_title + self.ctx_unbound_is_star = ctx.opts.uml_unbound_is_star # output dir from option -D or default img/ if ctx.opts.uml_outputdir is not None: self.ctx_outputdir = ctx.opts.uml_outputdir @@ -206,6 +233,37 @@ def __init__(self, ctx): if no_opt not in nostrings: sys.stderr.write("\"%s\" no valid argument to --uml-no=..., valid arguments: %s \n" %(no_opt, nostrings)) + relationship_strings = ("aggregation", "composition", "dependency", "generalization", "realization") + if ctx.opts.uml_node_choice != "": + if ctx.opts.uml_node_choice in relationship_strings: + self.ctx_relationship_node_choice = ctx.opts.uml_node_choice + else: + sys.stderr.write("\"%s\" not a valid argument to --uml-case=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_node_choice, relationship_strings)) + + if self.ctx_relationship_node_choice == 'generalization': + self.symbol_node_to_choice = "<|--" + elif self.ctx_relationship_node_choice == 'aggregation': + self.symbol_node_to_choice = "o--" + elif self.ctx_relationship_node_choice == 'composition': + self.symbol_node_to_choice = "*--" + elif self.ctx_relationship_node_choice == 'realization': + self.symbol_node_to_choice = "<|.." + + if ctx.opts.uml_choice_case != "": + if ctx.opts.uml_choice_case in relationship_strings: + self.ctx_relationship_choice_case = ctx.opts.uml_choice_case + else: + sys.stderr.write("\"%s\" not a valid argument to --uml-case=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_choice_case, relationship_strings)) + + if self.ctx_relationship_choice_case == 'generalization': + self.symbol_choice_to_case = "<|--" + elif self.ctx_relationship_choice_case == 'aggregation': + self.symbol_choice_to_case = "o--" + elif self.ctx_relationship_choice_case == 'composition': + self.symbol_choice_to_case = "*--" + elif self.ctx_relationship_choice_case == 'realization': + self.symbol_choice_to_case = "<|.." + self.ctx_filterfile = ctx.opts.uml_gen_filter_file self.ctx_truncate_augments = "augment" in ctx.opts.uml_truncate.split(",") @@ -226,6 +284,7 @@ def __init__(self, ctx): except IOError: raise error.EmitError("Filter file %s does not exist" %ctx.opts.uml_filter_file, 2) + def emit(self, modules, fd): title = '' if self.ctx_title is not None: @@ -323,7 +382,7 @@ def emit_stmt(self, mod, stmt, fd): elif stmt.keyword == 'choice': if not self.ctx_filterfile: fd.write('class \"%s\" as %s <> \n' % (self.full_display_path(stmt), self.full_path(stmt))) - fd.write('%s .. %s : choice \n' % (self.full_path(mod), self.full_path(stmt))) + fd.write('%s %s %s : choice \n' % (self.full_path(mod), self.symbol_node_to_choice, self.full_path(stmt))) # sys.stderr.write('in choice %s \n', self.full_path(mod)) for children in stmt.substmts: self.emit_child_stmt(stmt, children, fd) @@ -331,7 +390,7 @@ def emit_stmt(self, mod, stmt, fd): elif stmt.keyword == 'case': if not self.ctx_filterfile: fd.write('class \"%s\" as %s \n' %(self.full_display_path(stmt), self.full_path(stmt))) - fd.write('%s .. %s : choice\n' % (self.full_path(mod), self.full_path(stmt))) + fd.write('%s %s %s : choice\n' % (self.full_path(mod), self.symbol_choice_to_case, self.full_path(stmt))) # sys.stderr.write('in case %s \n', full_path(mod)) for children in mod.substmts: self.emit_child_stmt(stmt, children, fd) @@ -370,7 +429,8 @@ def emit_child_stmt(self, parent, node, fd, cont = True): # create fake parent statement.keyword = 'case' statement.arg = node.arg newparent = statements.Statement(parent, parent, None, 'case', node.arg) fd.write('class \"%s\" as %s <> \n' % (node.arg, self.full_path(newparent))) - fd.write('%s .. %s : choice %s\n' % (self.full_path(parent), self.full_path(newparent), node.parent.arg)) + fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.symbol_choice_to_case, self.full_path(newparent), node.parent.arg)) + parent = newparent @@ -391,7 +451,7 @@ def emit_child_stmt(self, parent, node, fd, cont = True): elif node.keyword == 'choice': if not self.ctx_filterfile: fd.write('class \"%s\" as %s <> \n' % (self.full_display_path(node), self.full_path(node))) - fd.write('%s .. %s : choice \n' % (self.full_path(parent), self.full_path(node))) + fd.write('%s %s %s : choice \n' % (self.full_path(parent), self.symbol_node_to_choice, self.full_path(node))) if cont: for children in node.substmts: # try pointing to parent @@ -401,7 +461,8 @@ def emit_child_stmt(self, parent, node, fd, cont = True): # sys.stderr.write('in case \n') if not self.ctx_filterfile: fd.write('class \"%s\" as %s <>\n' %(self.full_display_path(node), self.full_path(node))) - fd.write('%s .. %s : choice %s\n' % (self.full_path(parent), self.full_path(node), node.parent.arg)) + fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.symbol_choice_to_case, self.full_path(node), node.parent.arg)) + if cont: for children in node.substmts: self.emit_child_stmt(node, children, fd) @@ -501,10 +562,10 @@ def emit_uml_header(self, title, fd): # split into pages ? option -s fd.write('page %s \n' %self.ctx_pagelayout) - - fd.write('Title %s \n' %title) - if self._ctx.opts.uml_header is not None: - fd.write('center header\n %s \n endheader \n' %self._ctx.opts.uml_header) + if not self.ctx_no_title: + fd.write('Title %s \n' %title) + if self._ctx.opts.uml_header is not None: + fd.write('center header\n %s \n endheader \n' %self._ctx.opts.uml_header) def emit_module_header(self, module, fd): @@ -632,7 +693,10 @@ def emit_list(self, parent, node, fd): if not self.ctx_filterfile: fd.write('class \"%s\" as %s << (L, #FF7700) list>> \n' %(self.full_display_path(node), self.full_path(node))) minelem = '0' - maxelem = 'N' + if self.ctx_unbound_is_star : + maxelem = "*" + else: + maxelem = "N" oby = '' mi = node.search_one('min-elements') if mi is not None: From 283ff13bed59d9b5fa3a6c2608948afc93667a70 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Mon, 5 Jun 2023 15:07:05 +0200 Subject: [PATCH 02/41] Add support to suppress the footer --- pyang/plugins/uml.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 3b3e3e9b..9033e8df 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -50,13 +50,18 @@ def add_opts(self, optparser): action="store_true", dest="uml_no_title", default = False, - help="Do not include a title. If a title has also been specified as an option, it will be ignored."), + help="Do not include a title. If a title has also been specified as an option, it will be ignored"), optparse.make_option("--uml-header", dest="uml_header", help="Set the page header of the generated UML"), optparse.make_option("--uml-footer", dest="uml_footer", - help="Set the page footer of the generated UML"), + help="Set the page footer of the generated UML. If not specified, a default footer will be generated"), + optparse.make_option("--uml-no-footer", + action="store_true", + dest="uml_no_footer", + default = False, + help="Do not include a footer. If a footer has also been specified as an option, it will be ignored"), optparse.make_option("--uml-long-identifiers", action="store_true", dest="uml_longids", @@ -153,6 +158,7 @@ class uml_emitter: ctx_outputdir = "img/" ctx_title = None ctx_no_title = False + ctx_no_footer = False ctx_fullpath = False ctx_classesonly = False ctx_description = False @@ -198,6 +204,7 @@ def __init__(self, ctx): self.ctx_description = ctx.opts.uml_descr self.ctx_classesonly = ctx.opts.uml_classes_only self.ctx_no_title = ctx.opts.uml_no_title + self.ctx_no_footer = ctx.opts.uml_no_footer self.ctx_unbound_is_star = ctx.opts.uml_unbound_is_star # output dir from option -D or default img/ if ctx.opts.uml_outputdir is not None: @@ -564,8 +571,9 @@ def emit_uml_header(self, title, fd): if not self.ctx_no_title: fd.write('Title %s \n' %title) - if self._ctx.opts.uml_header is not None: - fd.write('center header\n %s \n endheader \n' %self._ctx.opts.uml_header) + + if self._ctx.opts.uml_header is not None: + fd.write('center header\n %s \n endheader \n' %self._ctx.opts.uml_header) def emit_module_header(self, module, fd): @@ -655,11 +663,12 @@ def emit_module_class(self, module, fd): def emit_uml_footer(self, module, fd): - if self._ctx.opts.uml_footer is not None: - fd.write('center footer\n %s \n endfooter \n' %self._ctx.opts.uml_footer) - else: - now = datetime.datetime.now() - fd.write('center footer\n UML Generated : %s \n endfooter \n' %now.strftime("%Y-%m-%d %H:%M")) + if not self.ctx_no_footer: + if self._ctx.opts.uml_footer is not None: + fd.write('center footer\n %s \n endfooter \n' %self._ctx.opts.uml_footer) + else: + now = datetime.datetime.now() + fd.write('center footer\n UML Generated : %s \n endfooter \n' %now.strftime("%Y-%m-%d %H:%M")) fd.write('@enduml \n') From cda7c92d8c1f30b6b8af74c39b8500eb2a95d9bf Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Tue, 6 Jun 2023 18:08:27 +0200 Subject: [PATCH 03/41] Add support for bits class Add <> stereotype to an enumeration class Add support for rendering a typedef of bits as a bits class Add support for defining the max number of bit values to render in the bits class. Add support to indicate that more enum or bit values are not shown by means of an ellipsis --- pyang/plugins/uml.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 9033e8df..1d80db68 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -93,7 +93,14 @@ def add_opts(self, optparser): optparse.make_option("--uml-max-enums", dest="uml_max_enums", default = "3", - help="The maximum number of enumerated values being rendered"), + help="The maximum number of enumerated values or bits values being rendered"), + optparse.make_option("--uml-max-bits", + dest="uml_max_bits", + help="When present enables the rendering of bits typedefs as a 'bits' class rather than a 'typedef' class and also defines the maximum number of bits values being rendered"), + optparse.make_option("--uml-more", + dest="uml_more", + default="MORE", + help="Selects how to indicate within a class that there are more enumerated or bits values than are shown. \nValid values are one of: MORE, ellipsis. \nNote that ellipsis is rendered as '...'"), optparse.make_option("--uml-filter", action="store_true", @@ -178,6 +185,8 @@ class uml_emitter: ctx_unbound_is_star = False ctx_relationship_node_choice = "dependency" ctx_relationship_choice_case = "dependency" + ctx_no_circles = False + ctx_more_string = "MORE" ctx_filterfile = False ctx_usefilterfile = None @@ -291,6 +300,14 @@ def __init__(self, ctx): except IOError: raise error.EmitError("Filter file %s does not exist" %ctx.opts.uml_filter_file, 2) + more_strings = ("MORE", "ellipsis") + if ctx.opts.uml_more in more_strings: + if ctx.opts.uml_more == "ellipsis": + self.ctx_more_string = "..." + else: + self.ctx_more_string = ctx.opts.uml_more + else: + sys.stderr.write("\"%s\" not a valid argument to --uml-more=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_more, more_strings)) def emit(self, modules, fd): title = '' @@ -551,8 +568,10 @@ def emit_uml_header(self, title, fd): fd.write('@startuml %s%s.png \n' %(self.ctx_outputdir, title)) + fd.write('hide empty fields \n') fd.write('hide empty methods \n') + fd.write('hide <> circle\n') fd.write('hide <> circle\n') fd.write('hide <> circle\n') @@ -777,11 +796,21 @@ def emit_typedef(self, m, t, fd): e = t.search_one('type') if e.arg == 'enumeration': # enum_name = self.full_path(t, False) - fd.write('enum \"%s\" as %s {\n' %(t.arg, self.full_path(t))) + fd.write('enum \"%s\" as %s <> {\n' %(t.arg, self.full_path(t))) for enums in e.substmts[:int(self._ctx.opts.uml_max_enums)]: fd.write('%s\n' %enums.arg) if len(e.substmts) > int(self._ctx.opts.uml_max_enums): - fd.write('%s\n' %"MORE") + fd.write('%s\n' %(self.ctx_more_string)) + fd.write("}\n") + elif e.arg == 'bits' and self._ctx.opts.uml_max_bits is not None: + fd.write( + 'class \"%s\" as %s << (B, Khaki) bits>> {\n' % ( + t.arg, self.full_path(t))) + for bits in e.substmts[ + :int(self._ctx.opts.uml_max_bits)]: + fd.write('%s\n' % bits.arg) + if len(e.substmts) > int(self._ctx.opts.uml_max_bits): + fd.write('%s\n' %(self.ctx_more_string)) fd.write("}\n") else: fd.write('class \"%s\" as %s << (T, YellowGreen) typedef>>\n' %(t.arg, self.make_plantuml_keyword(t.arg))) From 096cccbc65d6fc4de19974f28c04c014c8f12622 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Thu, 8 Jun 2023 14:53:00 +0200 Subject: [PATCH 04/41] Add support to hide the module prefix in the package representing the module being rendered --- pyang/plugins/uml.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 1d80db68..3890b678 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -123,6 +123,11 @@ def add_opts(self, optparser): dest="uml_choice_case", default = "", help="Selects how to render the relationship between a choice and its cases. \nValid values are one of: aggregation, composition, dependency, generalization, realization (default dependency)"), + optparse.make_option("--uml-hide-prefix-in-package-name", + action="store_true", + dest="uml_hide_prefix_in_package_name", + default = False, + help="Do not include the module prefix in the name of packages"), ] if hasattr(optparser, 'uml_opts'): g = optparser.uml_opts @@ -187,6 +192,7 @@ class uml_emitter: ctx_relationship_choice_case = "dependency" ctx_no_circles = False ctx_more_string = "MORE" + ctx_hide_prefix_in_package_name = False ctx_filterfile = False ctx_usefilterfile = None @@ -285,6 +291,7 @@ def __init__(self, ctx): self.ctx_truncate_augments = "augment" in ctx.opts.uml_truncate.split(",") self.ctx_truncate_leafrefs = "leafref" in ctx.opts.uml_truncate.split(",") self.ctx_no_module = "module" in no + self.ctx_hide_prefix_in_package_name = ctx.opts.uml_hide_prefix_in_package_name truncatestrings = ("augment", "leafref") if ctx.opts.uml_truncate != "": @@ -605,7 +612,10 @@ def emit_module_header(self, module, fd): #fd.write('package %s.%s \n' %(pre, pkg)) pre = i.search_one('prefix').arg pkg = i.arg - fd.write('package \"%s:%s\" as %s_%s { \n' %(pre, pkg, self.make_plantuml_keyword(pre), self.make_plantuml_keyword(pkg))) + if self.ctx_hide_prefix_in_package_name : + fd.write('package \"%s\" as %s_%s { \n' % (pkg, self.make_plantuml_keyword(pre),self.make_plantuml_keyword(pkg))) + else: + fd.write('package \"%s:%s\" as %s_%s { \n' %(pre, pkg, self.make_plantuml_keyword(pre), self.make_plantuml_keyword(pkg))) # search for augments and place them in correct package ## augments = module.search('augment') @@ -669,7 +679,10 @@ def emit_module_header(self, module, fd): fd.write('\n') # This package - fd.write('package \"%s:%s\" as %s_%s { \n' %(self.thismod_prefix, pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) + if self.ctx_hide_prefix_in_package_name: + fd.write('package \"%s\" as %s_%s { \n' %(pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) + else: + fd.write('package \"%s:%s\" as %s_%s { \n' %(self.thismod_prefix, pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) includes = module.search('include') for inc in includes: From fa21c1eef8832b6c50a7e099475d0754766b934b Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Thu, 8 Jun 2023 15:00:22 +0200 Subject: [PATCH 05/41] Tweak help text for the option uml-hide-prefix-in-package-name --- pyang/plugins/uml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 3890b678..194280ba 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -127,7 +127,7 @@ def add_opts(self, optparser): action="store_true", dest="uml_hide_prefix_in_package_name", default = False, - help="Do not include the module prefix in the name of packages"), + help="Do not include the module prefix within the displayed name of packages"), ] if hasattr(optparser, 'uml_opts'): g = optparser.uml_opts From afbad21bbd51eca6c2a38789abf544cd5e2a2e55 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Tue, 13 Jun 2023 17:44:06 +0200 Subject: [PATCH 06/41] Refactor option --uml-unbound-is-star to --uml-unbounded-multiplicity This refactoring allows for more alternatives in the future. --- pyang/plugins/uml.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 194280ba..c8954212 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -101,7 +101,6 @@ def add_opts(self, optparser): dest="uml_more", default="MORE", help="Selects how to indicate within a class that there are more enumerated or bits values than are shown. \nValid values are one of: MORE, ellipsis. \nNote that ellipsis is rendered as '...'"), - optparse.make_option("--uml-filter", action="store_true", dest="uml_gen_filter_file", @@ -110,11 +109,10 @@ def add_opts(self, optparser): optparse.make_option("--uml-filter-file", dest="uml_filter_file", help="NOT IMPLEMENTED: Only paths in the filter file will be included in the diagram"), - optparse.make_option("--uml-unbound-is-star", - action="store_true", - dest="uml_unbound_is_star", - default = False, - help="Use a star ('*') to render unbounded upper limit multiplicity instead of an 'N'."), + optparse.make_option("--uml-unbounded-multiplicity", + dest="uml_unbounded_multiplicity", + default = "", + help="Change how the unbounded upper limit multiplicity of relationships is rendered from the default of 'N'. \nValid values are one of: *."), optparse.make_option("--uml-node-choice", dest="uml_node_choice", default = "", @@ -187,7 +185,7 @@ class uml_emitter: ctx_truncate_augments = False ctx_inline_augments = False ctx_no_module = False - ctx_unbound_is_star = False + ctx_unbounded_maxelem = "N" ctx_relationship_node_choice = "dependency" ctx_relationship_choice_case = "dependency" ctx_no_circles = False @@ -220,7 +218,6 @@ def __init__(self, ctx): self.ctx_classesonly = ctx.opts.uml_classes_only self.ctx_no_title = ctx.opts.uml_no_title self.ctx_no_footer = ctx.opts.uml_no_footer - self.ctx_unbound_is_star = ctx.opts.uml_unbound_is_star # output dir from option -D or default img/ if ctx.opts.uml_outputdir is not None: self.ctx_outputdir = ctx.opts.uml_outputdir @@ -255,6 +252,13 @@ def __init__(self, ctx): if no_opt not in nostrings: sys.stderr.write("\"%s\" no valid argument to --uml-no=..., valid arguments: %s \n" %(no_opt, nostrings)) + alt_unbounded_multiplicity_strings = ("*") + if ctx.opts.uml_unbounded_multiplicity != "": + if ctx.opts.uml_unbounded_multiplicity in alt_unbounded_multiplicity_strings: + self.ctx_unbounded_maxelem = ctx.opts.uml_unbounded_multiplicity + else: + sys.stderr.write("\"%s\" not a valid argument to --uml-unbounded-multiplcity, valid arguments are (one only): %s \n" %(ctx.opts.uml_unbounded_multiplicity, alt_unbounded_multiplicity_strings)) + relationship_strings = ("aggregation", "composition", "dependency", "generalization", "realization") if ctx.opts.uml_node_choice != "": if ctx.opts.uml_node_choice in relationship_strings: @@ -734,10 +738,7 @@ def emit_list(self, parent, node, fd): if not self.ctx_filterfile: fd.write('class \"%s\" as %s << (L, #FF7700) list>> \n' %(self.full_display_path(node), self.full_path(node))) minelem = '0' - if self.ctx_unbound_is_star : - maxelem = "*" - else: - maxelem = "N" + maxelem = self.ctx_unbounded_maxelem oby = '' mi = node.search_one('min-elements') if mi is not None: From d0040dc53c1f9d3950f9cb7df13dd487eb2bb672 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Tue, 13 Jun 2023 18:41:37 +0200 Subject: [PATCH 07/41] Refactor support for changing the relationships for choices and cases Remove unnecessary variables. Add support for association. --- pyang/plugins/uml.py | 90 ++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index c8954212..9604b793 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -112,18 +112,18 @@ def add_opts(self, optparser): optparse.make_option("--uml-unbounded-multiplicity", dest="uml_unbounded_multiplicity", default = "", - help="Change how the unbounded upper limit multiplicity of relationships is rendered from the default of 'N'. \nValid values are one of: *."), - optparse.make_option("--uml-node-choice", - dest="uml_node_choice", + help="Change how the unbounded upper limit multiplicity of relationships is rendered (default: 'N'). \nValid values are one of: *."), + optparse.make_option("--uml-choice", + dest="uml_choice", default = "", - help="Selects how to render the relationship between a container or list and a choice. \nValid values are one of: aggregation, composition, dependency, generalization, realization (default dependency)"), - optparse.make_option("--uml-choice-case", - dest="uml_choice_case", + help="Change how the relationship between a container or list data node and a choice is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable, realization"), + optparse.make_option("--uml-case", + dest="uml_case", default = "", - help="Selects how to render the relationship between a choice and its cases. \nValid values are one of: aggregation, composition, dependency, generalization, realization (default dependency)"), - optparse.make_option("--uml-hide-prefix-in-package-name", + help="Change how the relationship between a choice and its cases is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable, realization"), + optparse.make_option("--uml-hide-prefix-in-package-names", action="store_true", - dest="uml_hide_prefix_in_package_name", + dest="uml_hide_prefix_in_package_names", default = False, help="Do not include the module prefix within the displayed name of packages"), ] @@ -186,11 +186,8 @@ class uml_emitter: ctx_inline_augments = False ctx_no_module = False ctx_unbounded_maxelem = "N" - ctx_relationship_node_choice = "dependency" - ctx_relationship_choice_case = "dependency" - ctx_no_circles = False ctx_more_string = "MORE" - ctx_hide_prefix_in_package_name = False + ctx_hide_prefix_in_package_names = False ctx_filterfile = False ctx_usefilterfile = None @@ -259,43 +256,46 @@ def __init__(self, ctx): else: sys.stderr.write("\"%s\" not a valid argument to --uml-unbounded-multiplcity, valid arguments are (one only): %s \n" %(ctx.opts.uml_unbounded_multiplicity, alt_unbounded_multiplicity_strings)) - relationship_strings = ("aggregation", "composition", "dependency", "generalization", "realization") - if ctx.opts.uml_node_choice != "": - if ctx.opts.uml_node_choice in relationship_strings: - self.ctx_relationship_node_choice = ctx.opts.uml_node_choice + relationship_strings = ("aggregation", "association", "composition", "generalization", "navigable-association", "realization") + if ctx.opts.uml_choice != "": + if ctx.opts.uml_choice in relationship_strings: + if ctx.opts.uml_choice == 'generalization': + self.symbol_node_to_choice = "<|--" + elif ctx.opts.uml_choice == 'aggregation': + self.symbol_node_to_choice = "o--" + elif ctx.opts.uml_choice == 'association': + self.symbol_node_to_choice = "--" + elif ctx.opts.uml_choice == 'composition': + self.symbol_node_to_choice = "*--" + elif ctx.opts.uml_choice == 'navigable-association': + self.symbol_node_to_choice = "-->" + elif ctx.opts.uml_choice == 'realization': + self.symbol_node_to_choice = "<|.." else: - sys.stderr.write("\"%s\" not a valid argument to --uml-case=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_node_choice, relationship_strings)) - - if self.ctx_relationship_node_choice == 'generalization': - self.symbol_node_to_choice = "<|--" - elif self.ctx_relationship_node_choice == 'aggregation': - self.symbol_node_to_choice = "o--" - elif self.ctx_relationship_node_choice == 'composition': - self.symbol_node_to_choice = "*--" - elif self.ctx_relationship_node_choice == 'realization': - self.symbol_node_to_choice = "<|.." - - if ctx.opts.uml_choice_case != "": - if ctx.opts.uml_choice_case in relationship_strings: - self.ctx_relationship_choice_case = ctx.opts.uml_choice_case + sys.stderr.write("\"%s\" not a valid argument to --uml-case=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_choice, relationship_strings)) + if ctx.opts.uml_case != "": + if ctx.opts.uml_case in relationship_strings: + if ctx.opts.uml_case == 'generalization': + self.symbol_choice_to_case = "<|--" + elif ctx.opts.uml_case == 'aggregation': + self.symbol_choice_to_case = "o--" + elif ctx.opts.uml_case == 'association': + self.symbol_choice_to_case = "--" + elif ctx.opts.uml_case == 'composition': + self.symbol_choice_to_case = "*--" + elif ctx.opts.uml_case == 'navigable-association': + self.symbol_choice_to_case = "-->" + elif ctx.opts.uml_case == 'realization': + self.symbol_choice_to_case = "<|.." else: - sys.stderr.write("\"%s\" not a valid argument to --uml-case=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_choice_case, relationship_strings)) - - if self.ctx_relationship_choice_case == 'generalization': - self.symbol_choice_to_case = "<|--" - elif self.ctx_relationship_choice_case == 'aggregation': - self.symbol_choice_to_case = "o--" - elif self.ctx_relationship_choice_case == 'composition': - self.symbol_choice_to_case = "*--" - elif self.ctx_relationship_choice_case == 'realization': - self.symbol_choice_to_case = "<|.." - + sys.stderr.write("\"%s\" not a valid argument to --uml-case=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_case, relationship_strings)) + self.ctx_filterfile = ctx.opts.uml_gen_filter_file self.ctx_truncate_augments = "augment" in ctx.opts.uml_truncate.split(",") self.ctx_truncate_leafrefs = "leafref" in ctx.opts.uml_truncate.split(",") self.ctx_no_module = "module" in no - self.ctx_hide_prefix_in_package_name = ctx.opts.uml_hide_prefix_in_package_name + self.ctx_hide_prefix_in_package_names = ctx.opts.uml_hide_prefix_in_package_names truncatestrings = ("augment", "leafref") if ctx.opts.uml_truncate != "": @@ -616,7 +616,7 @@ def emit_module_header(self, module, fd): #fd.write('package %s.%s \n' %(pre, pkg)) pre = i.search_one('prefix').arg pkg = i.arg - if self.ctx_hide_prefix_in_package_name : + if self.ctx_hide_prefix_in_package_names : fd.write('package \"%s\" as %s_%s { \n' % (pkg, self.make_plantuml_keyword(pre),self.make_plantuml_keyword(pkg))) else: fd.write('package \"%s:%s\" as %s_%s { \n' %(pre, pkg, self.make_plantuml_keyword(pre), self.make_plantuml_keyword(pkg))) @@ -683,7 +683,7 @@ def emit_module_header(self, module, fd): fd.write('\n') # This package - if self.ctx_hide_prefix_in_package_name: + if self.ctx_hide_prefix_in_package_names: fd.write('package \"%s\" as %s_%s { \n' %(pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) else: fd.write('package \"%s:%s\" as %s_%s { \n' %(self.thismod_prefix, pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) From 48c158028d4550798d06c0f70f7e4433470c7f61 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Wed, 14 Jun 2023 14:49:06 +0200 Subject: [PATCH 08/41] Add support for changing how the uses statement is rendered when not inline --- pyang/plugins/uml.py | 72 +++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 9604b793..f6cea32f 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -116,11 +116,15 @@ def add_opts(self, optparser): optparse.make_option("--uml-choice", dest="uml_choice", default = "", - help="Change how the relationship between a container or list data node and a choice is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable, realization"), + help="Change how the choice statement is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable-association, realization"), optparse.make_option("--uml-case", dest="uml_case", default = "", - help="Change how the relationship between a choice and its cases is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable, realization"), + help="Change how case statement is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable-association, realization"), + optparse.make_option("--uml-uses", + dest="uml_uses", + default = "", + help="Change how the uses statement is rendered (default: navigable association). \nValid values are one of: aggregation, composition, dependency. generalization, realization. \nThis option has no effect if option --uml-inline-groupings is selected "), optparse.make_option("--uml-hide-prefix-in-package-names", action="store_true", dest="uml_hide_prefix_in_package_names", @@ -205,8 +209,10 @@ class uml_emitter: post_strings = [] module_prefixes = [] - symbol_node_to_choice = ".." - symbol_choice_to_case = ".." + choice_statement_symbol = ".." + case_statement_symbol = ".." + uses_statement_symbol = "-->" + uses_statement_label = "uses" def __init__(self, ctx): self._ctx = ctx @@ -260,35 +266,53 @@ def __init__(self, ctx): if ctx.opts.uml_choice != "": if ctx.opts.uml_choice in relationship_strings: if ctx.opts.uml_choice == 'generalization': - self.symbol_node_to_choice = "<|--" + self.choice_statement_symbol = "<|--" elif ctx.opts.uml_choice == 'aggregation': - self.symbol_node_to_choice = "o--" + self.choice_statement_symbol = "o--" elif ctx.opts.uml_choice == 'association': - self.symbol_node_to_choice = "--" + self.choice_statement_symbol = "--" elif ctx.opts.uml_choice == 'composition': - self.symbol_node_to_choice = "*--" + self.choice_statement_symbol = "*--" elif ctx.opts.uml_choice == 'navigable-association': - self.symbol_node_to_choice = "-->" + self.choice_statement_symbol = "-->" elif ctx.opts.uml_choice == 'realization': - self.symbol_node_to_choice = "<|.." + self.choice_statement_symbol = "<|.." else: - sys.stderr.write("\"%s\" not a valid argument to --uml-case=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_choice, relationship_strings)) + sys.stderr.write("\"%s\" not a valid argument to --uml-choice, valid arguments are (one only): %s \n" %(ctx.opts.uml_choice, relationship_strings)) if ctx.opts.uml_case != "": if ctx.opts.uml_case in relationship_strings: if ctx.opts.uml_case == 'generalization': - self.symbol_choice_to_case = "<|--" + self.case_statement_symbol = "<|--" elif ctx.opts.uml_case == 'aggregation': - self.symbol_choice_to_case = "o--" + self.case_statement_symbol = "o--" elif ctx.opts.uml_case == 'association': - self.symbol_choice_to_case = "--" + self.case_statement_symbol = "--" elif ctx.opts.uml_case == 'composition': - self.symbol_choice_to_case = "*--" + self.case_statement_symbol = "*--" elif ctx.opts.uml_case == 'navigable-association': - self.symbol_choice_to_case = "-->" + self.case_statement_symbol = "-->" elif ctx.opts.uml_case == 'realization': - self.symbol_choice_to_case = "<|.." + self.case_statement_symbol = "<|.." + else: + sys.stderr.write("\"%s\" not a valid argument to --uml-case, valid arguments are (one only): %s \n" %(ctx.opts.uml_case, uses_strings)) + uses_strings = ("aggregation", "association", "composition", "dependency", "generalization", "realization") + if ctx.opts.uml_uses != "": + if ctx.opts.uml_uses in uses_strings: + if ctx.opts.uml_uses == 'generalization': + self.uses_statement_symbol = "<|--" + elif ctx.opts.uml_uses == 'aggregation': + self.uses_statement_symbol = "o--" + elif ctx.opts.uml_uses == 'association': + self.uses_statement_symbol = "--" + elif ctx.opts.uml_uses == 'composition': + self.uses_statement_symbol = "*--" + elif ctx.opts.uml_uses == 'dependency': + self.uses_statement_symbol = "..>" + self.uses_statement_label = "<>" + elif ctx.opts.uml_uses == 'realization': + self.uses_statement_symbol = "<|.." else: - sys.stderr.write("\"%s\" not a valid argument to --uml-case=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_case, relationship_strings)) + sys.stderr.write("\"%s\" not a valid argument to --uml-uses, valid arguments are (one only): %s \n" %(ctx.opts.uml_uses, uses_strings)) self.ctx_filterfile = ctx.opts.uml_gen_filter_file @@ -417,7 +441,7 @@ def emit_stmt(self, mod, stmt, fd): elif stmt.keyword == 'choice': if not self.ctx_filterfile: fd.write('class \"%s\" as %s <> \n' % (self.full_display_path(stmt), self.full_path(stmt))) - fd.write('%s %s %s : choice \n' % (self.full_path(mod), self.symbol_node_to_choice, self.full_path(stmt))) + fd.write('%s %s %s : choice \n' % (self.full_path(mod), self.choice_statement_symbol, self.full_path(stmt))) # sys.stderr.write('in choice %s \n', self.full_path(mod)) for children in stmt.substmts: self.emit_child_stmt(stmt, children, fd) @@ -425,7 +449,7 @@ def emit_stmt(self, mod, stmt, fd): elif stmt.keyword == 'case': if not self.ctx_filterfile: fd.write('class \"%s\" as %s \n' %(self.full_display_path(stmt), self.full_path(stmt))) - fd.write('%s %s %s : choice\n' % (self.full_path(mod), self.symbol_choice_to_case, self.full_path(stmt))) + fd.write('%s %s %s : choice\n' % (self.full_path(mod), self.case_statement_symbol, self.full_path(stmt))) # sys.stderr.write('in case %s \n', full_path(mod)) for children in mod.substmts: self.emit_child_stmt(stmt, children, fd) @@ -464,7 +488,7 @@ def emit_child_stmt(self, parent, node, fd, cont = True): # create fake parent statement.keyword = 'case' statement.arg = node.arg newparent = statements.Statement(parent, parent, None, 'case', node.arg) fd.write('class \"%s\" as %s <> \n' % (node.arg, self.full_path(newparent))) - fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.symbol_choice_to_case, self.full_path(newparent), node.parent.arg)) + fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.case_statement_symbol, self.full_path(newparent), node.parent.arg)) parent = newparent @@ -486,7 +510,7 @@ def emit_child_stmt(self, parent, node, fd, cont = True): elif node.keyword == 'choice': if not self.ctx_filterfile: fd.write('class \"%s\" as %s <> \n' % (self.full_display_path(node), self.full_path(node))) - fd.write('%s %s %s : choice \n' % (self.full_path(parent), self.symbol_node_to_choice, self.full_path(node))) + fd.write('%s %s %s : choice \n' % (self.full_path(parent), self.choice_statement_symbol, self.full_path(node))) if cont: for children in node.substmts: # try pointing to parent @@ -496,7 +520,7 @@ def emit_child_stmt(self, parent, node, fd, cont = True): # sys.stderr.write('in case \n') if not self.ctx_filterfile: fd.write('class \"%s\" as %s <>\n' %(self.full_display_path(node), self.full_path(node))) - fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.symbol_choice_to_case, self.full_path(node), node.parent.arg)) + fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.case_statement_symbol, self.full_path(node), node.parent.arg)) if cont: for children in node.substmts: @@ -1174,7 +1198,7 @@ def post_process_diagram(self, fd): if self.ctx_uses: for p,u in self.uses: try: - fd.write('%s --> %s : uses \n' %(p, self.groupings[u])) + fd.write('%s %s %s : %s \n' % (p, self.uses_statement_symbol, self.groupings[u], self.uses_statement_label)) except KeyError: # grouping in imported module, TODO correct paths # Grouping in other module, use red... # fd.write('class \"%s\" as %s << (G,Red) grouping>>\n' %(self.uses_as_string[u], self.make_plantuml_keyword(self.uses_as_string[u]))) From 10b7c60429207a9b6df25441bfdb531966bb1c33 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Wed, 14 Jun 2023 16:03:39 +0200 Subject: [PATCH 09/41] Refactor new UML options Shorten and simplify descriptions of new UML options where possible. Align more with existing descriptions, even if not 100% correct. Simplify code where applicable. --- pyang/plugins/uml.py | 66 +++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index f6cea32f..915dfabf 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -50,7 +50,7 @@ def add_opts(self, optparser): action="store_true", dest="uml_no_title", default = False, - help="Do not include a title. If a title has also been specified as an option, it will be ignored"), + help="Do not include a title. If --uml-title has also been specified, --uml-title will be ignored"), optparse.make_option("--uml-header", dest="uml_header", help="Set the page header of the generated UML"), @@ -61,7 +61,7 @@ def add_opts(self, optparser): action="store_true", dest="uml_no_footer", default = False, - help="Do not include a footer. If a footer has also been specified as an option, it will be ignored"), + help="Do not include a footer. If --uml-footer has also been specified, --uml-footer will be ignored"), optparse.make_option("--uml-long-identifiers", action="store_true", dest="uml_longids", @@ -93,14 +93,14 @@ def add_opts(self, optparser): optparse.make_option("--uml-max-enums", dest="uml_max_enums", default = "3", - help="The maximum number of enumerated values or bits values being rendered"), + help="The maximum number of enumerated values to render"), optparse.make_option("--uml-max-bits", dest="uml_max_bits", - help="When present enables the rendering of bits typedefs as a 'bits' class rather than a 'typedef' class and also defines the maximum number of bits values being rendered"), - optparse.make_option("--uml-more", - dest="uml_more", - default="MORE", - help="Selects how to indicate within a class that there are more enumerated or bits values than are shown. \nValid values are one of: MORE, ellipsis. \nNote that ellipsis is rendered as '...'"), + help="The maximum number of bit values to render. If set also enables rendering of bits typedefs as a 'bits' class"), + optparse.make_option("--uml-more-values", + dest="uml_more_values", + default="", + help="Change how to indicate that there are more enumerated or bits values than are shown (default:'MORE'). \nValid value: ellipsis. \nNote that ellipsis is rendered as '...'. \nExample --uml-more-values=ellipsis"), optparse.make_option("--uml-filter", action="store_true", dest="uml_gen_filter_file", @@ -109,25 +109,25 @@ def add_opts(self, optparser): optparse.make_option("--uml-filter-file", dest="uml_filter_file", help="NOT IMPLEMENTED: Only paths in the filter file will be included in the diagram"), - optparse.make_option("--uml-unbounded-multiplicity", - dest="uml_unbounded_multiplicity", + optparse.make_option("--uml-unbounded", + dest="uml_unbounded", default = "", - help="Change how the unbounded upper limit multiplicity of relationships is rendered (default: 'N'). \nValid values are one of: *."), + help="Change how the unbounded upper limit multiplicity of relationships is rendered (default: 'N'). \nValid value: *. \nExample --uml-unbounded=* "), optparse.make_option("--uml-choice", dest="uml_choice", default = "", - help="Change how the choice statement is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable-association, realization"), + help="Change how the choice statement is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable-association, realization. \nExample --uml-choice=composition"), optparse.make_option("--uml-case", dest="uml_case", default = "", - help="Change how case statement is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable-association, realization"), + help="Change how case statement is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable-association, realization. \nExample --uml-case=generalization"), optparse.make_option("--uml-uses", dest="uml_uses", default = "", - help="Change how the uses statement is rendered (default: navigable association). \nValid values are one of: aggregation, composition, dependency. generalization, realization. \nThis option has no effect if option --uml-inline-groupings is selected "), - optparse.make_option("--uml-hide-prefix-in-package-names", + help="Change how the uses statement is rendered (default: navigable association). \nValid values are one of: aggregation, composition, dependency. generalization, realization. \nThis option has no effect if option --uml-inline-groupings is selected. \nExample --uml-uses=dependency"), + optparse.make_option("--uml-no-package-prefix", action="store_true", - dest="uml_hide_prefix_in_package_names", + dest="uml_no_package_prefix", default = False, help="Do not include the module prefix within the displayed name of packages"), ] @@ -191,7 +191,7 @@ class uml_emitter: ctx_no_module = False ctx_unbounded_maxelem = "N" ctx_more_string = "MORE" - ctx_hide_prefix_in_package_names = False + ctx_no_package_prefix = False ctx_filterfile = False ctx_usefilterfile = None @@ -255,12 +255,12 @@ def __init__(self, ctx): if no_opt not in nostrings: sys.stderr.write("\"%s\" no valid argument to --uml-no=..., valid arguments: %s \n" %(no_opt, nostrings)) - alt_unbounded_multiplicity_strings = ("*") - if ctx.opts.uml_unbounded_multiplicity != "": - if ctx.opts.uml_unbounded_multiplicity in alt_unbounded_multiplicity_strings: - self.ctx_unbounded_maxelem = ctx.opts.uml_unbounded_multiplicity + unbounded_strings = ("*") + if ctx.opts.uml_unbounded != "": + if ctx.opts.uml_unbounded in unbounded_strings: + self.ctx_unbounded_maxelem = ctx.opts.uml_unbounded else: - sys.stderr.write("\"%s\" not a valid argument to --uml-unbounded-multiplcity, valid arguments are (one only): %s \n" %(ctx.opts.uml_unbounded_multiplicity, alt_unbounded_multiplicity_strings)) + sys.stderr.write("\"%s\" no valid argument to --uml-unbounded-multiplcity=..., valid arguments (one only): %s \n" %(ctx.opts.uml_unbounded, unbounded_strings)) relationship_strings = ("aggregation", "association", "composition", "generalization", "navigable-association", "realization") if ctx.opts.uml_choice != "": @@ -278,7 +278,7 @@ def __init__(self, ctx): elif ctx.opts.uml_choice == 'realization': self.choice_statement_symbol = "<|.." else: - sys.stderr.write("\"%s\" not a valid argument to --uml-choice, valid arguments are (one only): %s \n" %(ctx.opts.uml_choice, relationship_strings)) + sys.stderr.write("\"%s\" no valid argument to --uml-choice=..., valid arguments (one only): %s \n" %(ctx.opts.uml_choice, relationship_strings)) if ctx.opts.uml_case != "": if ctx.opts.uml_case in relationship_strings: if ctx.opts.uml_case == 'generalization': @@ -294,7 +294,7 @@ def __init__(self, ctx): elif ctx.opts.uml_case == 'realization': self.case_statement_symbol = "<|.." else: - sys.stderr.write("\"%s\" not a valid argument to --uml-case, valid arguments are (one only): %s \n" %(ctx.opts.uml_case, uses_strings)) + sys.stderr.write("\"%s\" no valid argument to --uml-case=..., valid arguments (one only): %s \n" %(ctx.opts.uml_case, uses_strings)) uses_strings = ("aggregation", "association", "composition", "dependency", "generalization", "realization") if ctx.opts.uml_uses != "": if ctx.opts.uml_uses in uses_strings: @@ -312,14 +312,14 @@ def __init__(self, ctx): elif ctx.opts.uml_uses == 'realization': self.uses_statement_symbol = "<|.." else: - sys.stderr.write("\"%s\" not a valid argument to --uml-uses, valid arguments are (one only): %s \n" %(ctx.opts.uml_uses, uses_strings)) + sys.stderr.write("\"%s\" no valid argument to --uml-uses=..., valid arguments (one only): %s \n" %(ctx.opts.uml_uses, uses_strings)) self.ctx_filterfile = ctx.opts.uml_gen_filter_file self.ctx_truncate_augments = "augment" in ctx.opts.uml_truncate.split(",") self.ctx_truncate_leafrefs = "leafref" in ctx.opts.uml_truncate.split(",") self.ctx_no_module = "module" in no - self.ctx_hide_prefix_in_package_names = ctx.opts.uml_hide_prefix_in_package_names + self.ctx_no_package_prefix = ctx.opts.uml_no_package_prefix truncatestrings = ("augment", "leafref") if ctx.opts.uml_truncate != "": @@ -335,14 +335,12 @@ def __init__(self, ctx): except IOError: raise error.EmitError("Filter file %s does not exist" %ctx.opts.uml_filter_file, 2) - more_strings = ("MORE", "ellipsis") - if ctx.opts.uml_more in more_strings: - if ctx.opts.uml_more == "ellipsis": + more_strings = ("ellipsis") + if ctx.opts.uml_more_values in more_strings: + if ctx.opts.uml_more_values == "ellipsis": self.ctx_more_string = "..." - else: - self.ctx_more_string = ctx.opts.uml_more else: - sys.stderr.write("\"%s\" not a valid argument to --uml-more=..., valid arguments are (one only): %s \n" %(ctx.opts.uml_more, more_strings)) + sys.stderr.write("\"%s\" no valid argument to --uml-more=..., valid argument: %s \n" %(ctx.opts.uml_more_values, more_strings)) def emit(self, modules, fd): title = '' @@ -640,7 +638,7 @@ def emit_module_header(self, module, fd): #fd.write('package %s.%s \n' %(pre, pkg)) pre = i.search_one('prefix').arg pkg = i.arg - if self.ctx_hide_prefix_in_package_names : + if self.ctx_no_package_prefix : fd.write('package \"%s\" as %s_%s { \n' % (pkg, self.make_plantuml_keyword(pre),self.make_plantuml_keyword(pkg))) else: fd.write('package \"%s:%s\" as %s_%s { \n' %(pre, pkg, self.make_plantuml_keyword(pre), self.make_plantuml_keyword(pkg))) @@ -707,7 +705,7 @@ def emit_module_header(self, module, fd): fd.write('\n') # This package - if self.ctx_hide_prefix_in_package_names: + if self.ctx_no_package_prefix: fd.write('package \"%s\" as %s_%s { \n' %(pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) else: fd.write('package \"%s:%s\" as %s_%s { \n' %(self.thismod_prefix, pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) From 8a134ab9b442b72dd9947e3ed49c5e82d9b6c635 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Mon, 19 Jun 2023 13:09:03 +0200 Subject: [PATCH 10/41] Refactor option to suppress the prefix in the package name to use --uml-no Also correct error in uml-case which references the wrong set of strings, if the option includes an invalid string. --- pyang/plugins/uml.py | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 915dfabf..0624cd17 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -85,7 +85,7 @@ def add_opts(self, optparser): optparse.make_option("--uml-no", dest="uml_no", default = "", - help="Suppress parts of the diagram. \nValid suppress values are: module, uses, leafref, identity, identityref, typedef, import, annotation, circles, stereotypes. Annotations suppresses YANG constructs represented as annotations such as config statements for containers and module info. Module suppresses module box around the diagram and module information. \nExample --uml-no=circles,stereotypes,typedef,import"), + help="Suppress parts of the diagram. \nValid suppress values are: module, uses, leafref, identity, identityref, typedef, import, prefix, annotation, circles, stereotypes. Annotations suppresses YANG constructs represented as annotations such as config statements for containers and module info. Module suppresses module box around the diagram and module information. Prefix suppresses the the prefix in the name of packages. \nExample --uml-no=circles,stereotypes,typedef,import"), optparse.make_option("--uml-truncate", dest="uml_truncate", default = "", @@ -125,11 +125,6 @@ def add_opts(self, optparser): dest="uml_uses", default = "", help="Change how the uses statement is rendered (default: navigable association). \nValid values are one of: aggregation, composition, dependency. generalization, realization. \nThis option has no effect if option --uml-inline-groupings is selected. \nExample --uml-uses=dependency"), - optparse.make_option("--uml-no-package-prefix", - action="store_true", - dest="uml_no_package_prefix", - default = False, - help="Do not include the module prefix within the displayed name of packages"), ] if hasattr(optparser, 'uml_opts'): g = optparser.uml_opts @@ -185,13 +180,13 @@ class uml_emitter: ctx_annotations = True ctx_circles = True ctx_stereotypes = True + ctx_prefix = True ctx_truncate_leafrefs = False ctx_truncate_augments = False ctx_inline_augments = False ctx_no_module = False ctx_unbounded_maxelem = "N" ctx_more_string = "MORE" - ctx_no_package_prefix = False ctx_filterfile = False ctx_usefilterfile = None @@ -248,8 +243,9 @@ def __init__(self, ctx): self.ctx_imports = not "import" in no self.ctx_circles = not "circles" in no self.ctx_stereotypes = not "stereotypes" in no + self.ctx_prefix = not "prefix" in no - nostrings = ("module", "leafref", "uses", "annotation", "identityref", "typedef", "import", "circles", "stereotypes") + nostrings = ("module", "leafref", "uses", "annotation", "identityref", "typedef", "import", "circles", "stereotypes", "prefix") if ctx.opts.uml_no != "": for no_opt in no: if no_opt not in nostrings: @@ -294,7 +290,7 @@ def __init__(self, ctx): elif ctx.opts.uml_case == 'realization': self.case_statement_symbol = "<|.." else: - sys.stderr.write("\"%s\" no valid argument to --uml-case=..., valid arguments (one only): %s \n" %(ctx.opts.uml_case, uses_strings)) + sys.stderr.write("\"%s\" no valid argument to --uml-case=..., valid arguments (one only): %s \n" %(ctx.opts.uml_case, relationship_strings)) uses_strings = ("aggregation", "association", "composition", "dependency", "generalization", "realization") if ctx.opts.uml_uses != "": if ctx.opts.uml_uses in uses_strings: @@ -319,7 +315,6 @@ def __init__(self, ctx): self.ctx_truncate_augments = "augment" in ctx.opts.uml_truncate.split(",") self.ctx_truncate_leafrefs = "leafref" in ctx.opts.uml_truncate.split(",") self.ctx_no_module = "module" in no - self.ctx_no_package_prefix = ctx.opts.uml_no_package_prefix truncatestrings = ("augment", "leafref") if ctx.opts.uml_truncate != "": @@ -638,10 +633,10 @@ def emit_module_header(self, module, fd): #fd.write('package %s.%s \n' %(pre, pkg)) pre = i.search_one('prefix').arg pkg = i.arg - if self.ctx_no_package_prefix : - fd.write('package \"%s\" as %s_%s { \n' % (pkg, self.make_plantuml_keyword(pre),self.make_plantuml_keyword(pkg))) + if self.ctx_prefix : + fd.write('package \"%s:%s\" as %s_%s { \n' % (pre, pkg, self.make_plantuml_keyword(pre), self.make_plantuml_keyword(pkg))) else: - fd.write('package \"%s:%s\" as %s_%s { \n' %(pre, pkg, self.make_plantuml_keyword(pre), self.make_plantuml_keyword(pkg))) + fd.write('package \"%s\" as %s_%s { \n' % (pkg, self.make_plantuml_keyword(pre),self.make_plantuml_keyword(pkg))) # search for augments and place them in correct package ## augments = module.search('augment') @@ -705,10 +700,10 @@ def emit_module_header(self, module, fd): fd.write('\n') # This package - if self.ctx_no_package_prefix: - fd.write('package \"%s\" as %s_%s { \n' %(pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) - else: + if self.ctx_prefix: fd.write('package \"%s:%s\" as %s_%s { \n' %(self.thismod_prefix, pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) + else: + fd.write('package \"%s\" as %s_%s { \n' %(pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) includes = module.search('include') for inc in includes: From e4ebf17a1e6b99c7548a33bf7c820faceac923f6 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Fri, 23 Jun 2023 11:59:23 +0200 Subject: [PATCH 11/41] Minor refactoring --- pyang/plugins/uml.py | 62 ++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 0624cd17..d29e1e69 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -99,8 +99,8 @@ def add_opts(self, optparser): help="The maximum number of bit values to render. If set also enables rendering of bits typedefs as a 'bits' class"), optparse.make_option("--uml-more-values", dest="uml_more_values", - default="", - help="Change how to indicate that there are more enumerated or bits values than are shown (default:'MORE'). \nValid value: ellipsis. \nNote that ellipsis is rendered as '...'. \nExample --uml-more-values=ellipsis"), + default = "", + help="Use an alternative to 'MORE' to indicate that there are more enumerated or bits values than are shown. \nValid value: ellipsis. \nNote that ellipsis is rendered as '...'. \nExample --uml-more-values=ellipsis"), optparse.make_option("--uml-filter", action="store_true", dest="uml_gen_filter_file", @@ -204,10 +204,10 @@ class uml_emitter: post_strings = [] module_prefixes = [] - choice_statement_symbol = ".." - case_statement_symbol = ".." - uses_statement_symbol = "-->" - uses_statement_label = "uses" + choice_relation_symbol = ".." + case_relation_symbol = ".." + uses_relation_symbol = "-->" + uses_relation_label = "uses" def __init__(self, ctx): self._ctx = ctx @@ -262,51 +262,51 @@ def __init__(self, ctx): if ctx.opts.uml_choice != "": if ctx.opts.uml_choice in relationship_strings: if ctx.opts.uml_choice == 'generalization': - self.choice_statement_symbol = "<|--" + self.choice_relation_symbol = "<|--" elif ctx.opts.uml_choice == 'aggregation': - self.choice_statement_symbol = "o--" + self.choice_relation_symbol = "o--" elif ctx.opts.uml_choice == 'association': - self.choice_statement_symbol = "--" + self.choice_relation_symbol = "--" elif ctx.opts.uml_choice == 'composition': - self.choice_statement_symbol = "*--" + self.choice_relation_symbol = "*--" elif ctx.opts.uml_choice == 'navigable-association': - self.choice_statement_symbol = "-->" + self.choice_relation_symbol = "-->" elif ctx.opts.uml_choice == 'realization': - self.choice_statement_symbol = "<|.." + self.choice_relation_symbol = "<|.." else: sys.stderr.write("\"%s\" no valid argument to --uml-choice=..., valid arguments (one only): %s \n" %(ctx.opts.uml_choice, relationship_strings)) if ctx.opts.uml_case != "": if ctx.opts.uml_case in relationship_strings: if ctx.opts.uml_case == 'generalization': - self.case_statement_symbol = "<|--" + self.case_relation_symbol = "<|--" elif ctx.opts.uml_case == 'aggregation': - self.case_statement_symbol = "o--" + self.case_relation_symbol = "o--" elif ctx.opts.uml_case == 'association': - self.case_statement_symbol = "--" + self.case_relation_symbol = "--" elif ctx.opts.uml_case == 'composition': - self.case_statement_symbol = "*--" + self.case_relation_symbol = "*--" elif ctx.opts.uml_case == 'navigable-association': - self.case_statement_symbol = "-->" + self.case_relation_symbol = "-->" elif ctx.opts.uml_case == 'realization': - self.case_statement_symbol = "<|.." + self.case_relation_symbol = "<|.." else: sys.stderr.write("\"%s\" no valid argument to --uml-case=..., valid arguments (one only): %s \n" %(ctx.opts.uml_case, relationship_strings)) uses_strings = ("aggregation", "association", "composition", "dependency", "generalization", "realization") if ctx.opts.uml_uses != "": if ctx.opts.uml_uses in uses_strings: if ctx.opts.uml_uses == 'generalization': - self.uses_statement_symbol = "<|--" + self.uses_relation_symbol = "<|--" elif ctx.opts.uml_uses == 'aggregation': - self.uses_statement_symbol = "o--" + self.uses_relation_symbol = "o--" elif ctx.opts.uml_uses == 'association': - self.uses_statement_symbol = "--" + self.uses_relation_symbol = "--" elif ctx.opts.uml_uses == 'composition': - self.uses_statement_symbol = "*--" + self.uses_relation_symbol = "*--" elif ctx.opts.uml_uses == 'dependency': - self.uses_statement_symbol = "..>" - self.uses_statement_label = "<>" + self.uses_relation_symbol = "..>" + self.uses_relation_label = "<>" elif ctx.opts.uml_uses == 'realization': - self.uses_statement_symbol = "<|.." + self.uses_relation_symbol = "<|.." else: sys.stderr.write("\"%s\" no valid argument to --uml-uses=..., valid arguments (one only): %s \n" %(ctx.opts.uml_uses, uses_strings)) @@ -434,7 +434,7 @@ def emit_stmt(self, mod, stmt, fd): elif stmt.keyword == 'choice': if not self.ctx_filterfile: fd.write('class \"%s\" as %s <> \n' % (self.full_display_path(stmt), self.full_path(stmt))) - fd.write('%s %s %s : choice \n' % (self.full_path(mod), self.choice_statement_symbol, self.full_path(stmt))) + fd.write('%s %s %s : choice \n' % (self.full_path(mod), self.choice_relation_symbol, self.full_path(stmt))) # sys.stderr.write('in choice %s \n', self.full_path(mod)) for children in stmt.substmts: self.emit_child_stmt(stmt, children, fd) @@ -442,7 +442,7 @@ def emit_stmt(self, mod, stmt, fd): elif stmt.keyword == 'case': if not self.ctx_filterfile: fd.write('class \"%s\" as %s \n' %(self.full_display_path(stmt), self.full_path(stmt))) - fd.write('%s %s %s : choice\n' % (self.full_path(mod), self.case_statement_symbol, self.full_path(stmt))) + fd.write('%s %s %s : choice\n' % (self.full_path(mod), self.case_relation_symbol, self.full_path(stmt))) # sys.stderr.write('in case %s \n', full_path(mod)) for children in mod.substmts: self.emit_child_stmt(stmt, children, fd) @@ -481,7 +481,7 @@ def emit_child_stmt(self, parent, node, fd, cont = True): # create fake parent statement.keyword = 'case' statement.arg = node.arg newparent = statements.Statement(parent, parent, None, 'case', node.arg) fd.write('class \"%s\" as %s <> \n' % (node.arg, self.full_path(newparent))) - fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.case_statement_symbol, self.full_path(newparent), node.parent.arg)) + fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.case_relation_symbol, self.full_path(newparent), node.parent.arg)) parent = newparent @@ -503,7 +503,7 @@ def emit_child_stmt(self, parent, node, fd, cont = True): elif node.keyword == 'choice': if not self.ctx_filterfile: fd.write('class \"%s\" as %s <> \n' % (self.full_display_path(node), self.full_path(node))) - fd.write('%s %s %s : choice \n' % (self.full_path(parent), self.choice_statement_symbol, self.full_path(node))) + fd.write('%s %s %s : choice \n' % (self.full_path(parent), self.choice_relation_symbol, self.full_path(node))) if cont: for children in node.substmts: # try pointing to parent @@ -513,7 +513,7 @@ def emit_child_stmt(self, parent, node, fd, cont = True): # sys.stderr.write('in case \n') if not self.ctx_filterfile: fd.write('class \"%s\" as %s <>\n' %(self.full_display_path(node), self.full_path(node))) - fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.case_statement_symbol, self.full_path(node), node.parent.arg)) + fd.write('%s %s %s : choice %s\n' % (self.full_path(parent), self.case_relation_symbol, self.full_path(node), node.parent.arg)) if cont: for children in node.substmts: @@ -1191,7 +1191,7 @@ def post_process_diagram(self, fd): if self.ctx_uses: for p,u in self.uses: try: - fd.write('%s %s %s : %s \n' % (p, self.uses_statement_symbol, self.groupings[u], self.uses_statement_label)) + fd.write('%s %s %s : %s \n' % (p, self.uses_relation_symbol, self.groupings[u], self.uses_relation_label)) except KeyError: # grouping in imported module, TODO correct paths # Grouping in other module, use red... # fd.write('class \"%s\" as %s << (G,Red) grouping>>\n' %(self.uses_as_string[u], self.make_plantuml_keyword(self.uses_as_string[u]))) From 0d43f12ba7d00c708ede9cd731e0ff34fc84e44f Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Fri, 23 Jun 2023 14:46:14 +0200 Subject: [PATCH 12/41] Refactor uml-no-title and uml-no-footer to use the uml-no option Exitsing ctx_title renamed ctx_title_text so that ctx_title could be used for uml-no. --- pyang/plugins/uml.py | 79 +++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index d29e1e69..4fd6bf5f 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -35,7 +35,7 @@ def add_opts(self, optparser): optparse.make_option("--uml-classes-only", action="store_true", dest="uml_classes_only", - default = False, + default=False, help="Generate UML with classes only, no attributes "), optparse.make_option("--uml-split-pages", dest="uml_pages_layout", @@ -46,85 +46,77 @@ def add_opts(self, optparser): optparse.make_option("--uml-title", dest="uml_title", help="Set the title of the generated UML, including the output file name"), - optparse.make_option("--uml-no-title", - action="store_true", - dest="uml_no_title", - default = False, - help="Do not include a title. If --uml-title has also been specified, --uml-title will be ignored"), optparse.make_option("--uml-header", dest="uml_header", help="Set the page header of the generated UML"), optparse.make_option("--uml-footer", dest="uml_footer", help="Set the page footer of the generated UML. If not specified, a default footer will be generated"), - optparse.make_option("--uml-no-footer", - action="store_true", - dest="uml_no_footer", - default = False, - help="Do not include a footer. If --uml-footer has also been specified, --uml-footer will be ignored"), optparse.make_option("--uml-long-identifiers", action="store_true", dest="uml_longids", - default =False, + default=False, help="Use the full schema identifiers for UML class names."), optparse.make_option("--uml-inline-groupings", action="store_true", dest="uml_inline", - default =False, + default=False, help="Inline groupings where they are used."), optparse.make_option("--uml-inline-augments", action="store_true", dest="uml_inline_augments", - default =False, + default=False, help="Inline augmentations where they are used."), optparse.make_option("--uml-description", action="store_true", dest="uml_descr", - default =False, + default=False, help="Include description of structural nodes in diagram."), optparse.make_option("--uml-no", dest="uml_no", - default = "", - help="Suppress parts of the diagram. \nValid suppress values are: module, uses, leafref, identity, identityref, typedef, import, prefix, annotation, circles, stereotypes. Annotations suppresses YANG constructs represented as annotations such as config statements for containers and module info. Module suppresses module box around the diagram and module information. Prefix suppresses the the prefix in the name of packages. \nExample --uml-no=circles,stereotypes,typedef,import"), + default="", + help="Suppress parts of the diagram. \nValid suppress values are: module, uses, leafref, identity, identityref, typedef, import, annotation, circles, stereotypes, prefix, footer, title. " + "Annotations suppresses YANG constructs represented as annotations such as config statements for containers and module info. Module suppresses module box around the diagram and module information. " + "Prefix suppresses the the prefix in the name of packages. \nIf footer or title are selected, the options --uml-footer and --uml-title respectively will be ignored. \nExample --uml-no=circles,stereotypes,typedef,import"), optparse.make_option("--uml-truncate", dest="uml_truncate", - default = "", + default="", help="Leafref attributes and augment elements can have long paths making the classes too wide. \nThis option will only show the tail of the path. \nExample --uml-truncate=augment,leafref"), optparse.make_option("--uml-max-enums", dest="uml_max_enums", - default = "3", + default="3", help="The maximum number of enumerated values to render"), optparse.make_option("--uml-max-bits", dest="uml_max_bits", help="The maximum number of bit values to render. If set also enables rendering of bits typedefs as a 'bits' class"), optparse.make_option("--uml-more-values", dest="uml_more_values", - default = "", + default="", help="Use an alternative to 'MORE' to indicate that there are more enumerated or bits values than are shown. \nValid value: ellipsis. \nNote that ellipsis is rendered as '...'. \nExample --uml-more-values=ellipsis"), optparse.make_option("--uml-filter", action="store_true", dest="uml_gen_filter_file", - default = False, + default=False, help="Generate filter file, comment out lines with '-' and use with option '--filter-file' to filter the UML diagram"), optparse.make_option("--uml-filter-file", dest="uml_filter_file", help="NOT IMPLEMENTED: Only paths in the filter file will be included in the diagram"), optparse.make_option("--uml-unbounded", dest="uml_unbounded", - default = "", - help="Change how the unbounded upper limit multiplicity of relationships is rendered (default: 'N'). \nValid value: *. \nExample --uml-unbounded=* "), + default="", + help="Change how the unbounded upper limit multiplicity of relationships is rendered from the default 'N'. \nValid value: *. \nExample --uml-unbounded=* "), optparse.make_option("--uml-choice", dest="uml_choice", - default = "", - help="Change how the choice statement is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable-association, realization. \nExample --uml-choice=composition"), + default="", + help="Change how the choice statement is rendered from the default of a dotted line. \nValid values are one of: aggregation, composition, generalization, navigable-association, realization. \nExample --uml-choice=composition"), optparse.make_option("--uml-case", dest="uml_case", - default = "", - help="Change how case statement is rendered (default: dotted line). \nValid values are one of: aggregation, composition, generalization, navigable-association, realization. \nExample --uml-case=generalization"), + default="", + help="Change how case statement is rendered from the default of a dotted line. \nValid values are one of: aggregation, composition, generalization, navigable-association, realization. \nExample --uml-case=generalization"), optparse.make_option("--uml-uses", dest="uml_uses", - default = "", - help="Change how the uses statement is rendered (default: navigable association). \nValid values are one of: aggregation, composition, dependency. generalization, realization. \nThis option has no effect if option --uml-inline-groupings is selected. \nExample --uml-uses=dependency"), + default="", + help="Change how the uses statement is rendered from the default of a navigable association. \nValid values are one of: aggregation, composition, dependency. generalization, realization. \nThis option has no effect if option --uml-inline-groupings is selected. \nExample --uml-uses=dependency"), ] if hasattr(optparser, 'uml_opts'): g = optparser.uml_opts @@ -165,9 +157,7 @@ class uml_emitter: unique = '' ctx_pagelayout = '1x1' ctx_outputdir = "img/" - ctx_title = None - ctx_no_title = False - ctx_no_footer = False + ctx_title_text = None ctx_fullpath = False ctx_classesonly = False ctx_description = False @@ -180,7 +170,6 @@ class uml_emitter: ctx_annotations = True ctx_circles = True ctx_stereotypes = True - ctx_prefix = True ctx_truncate_leafrefs = False ctx_truncate_augments = False ctx_inline_augments = False @@ -214,8 +203,6 @@ def __init__(self, ctx): self.ctx_fullpath = ctx.opts.uml_longids self.ctx_description = ctx.opts.uml_descr self.ctx_classesonly = ctx.opts.uml_classes_only - self.ctx_no_title = ctx.opts.uml_no_title - self.ctx_no_footer = ctx.opts.uml_no_footer # output dir from option -D or default img/ if ctx.opts.uml_outputdir is not None: self.ctx_outputdir = ctx.opts.uml_outputdir @@ -229,7 +216,7 @@ def __init__(self, ctx): self.ctx_pagelayout = ctx.opts.uml_pages_layout # Title from option -t - self.ctx_title = ctx.opts.uml_title + self.ctx_title_text = ctx.opts.uml_title self.ctx_inline_augments = ctx.opts.uml_inline_augments @@ -244,8 +231,10 @@ def __init__(self, ctx): self.ctx_circles = not "circles" in no self.ctx_stereotypes = not "stereotypes" in no self.ctx_prefix = not "prefix" in no + self.ctx_title = not "title" in no + self.ctx_footer = not "footer" in no - nostrings = ("module", "leafref", "uses", "annotation", "identityref", "typedef", "import", "circles", "stereotypes", "prefix") + nostrings = ("module", "leafref", "uses", "annotation", "identityref", "typedef", "import", "circles", "stereotypes", "prefix", "footer", "title") if ctx.opts.uml_no != "": for no_opt in no: if no_opt not in nostrings: @@ -339,8 +328,8 @@ def __init__(self, ctx): def emit(self, modules, fd): title = '' - if self.ctx_title is not None: - title = self.ctx_title + if self.ctx_title_text is not None: + title = self.ctx_title_text else: for m in modules: title += m.arg + '_' @@ -616,7 +605,7 @@ def emit_uml_header(self, title, fd): # split into pages ? option -s fd.write('page %s \n' %self.ctx_pagelayout) - if not self.ctx_no_title: + if self.ctx_title: fd.write('Title %s \n' %title) if self._ctx.opts.uml_header is not None: @@ -662,7 +651,13 @@ def emit_module_header(self, module, fd): #this_pkg = self.make_plantuml_keyword(module.search_one('prefix').arg) + '.' + self.make_plantuml_keyword(module.arg) pkg = module.arg - fd.write('package \"%s:%s\" as %s_%s { \n' %(self.thismod_prefix, pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) + # define a empty package for the module + # this ensures that PlantUML knows that its keyword represents a package and not a class when referenced before the main definition of the package within the Plant UML code, + # e.g., by the note definition that follows below + if self.ctx_prefix: + fd.write('package \"%s:%s\" as %s_%s { \n' %(self.thismod_prefix, pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) + else: + fd.write('package \"%s\" as %s_%s { \n' % (pkg, self.make_plantuml_keyword(self.thismod_prefix), self.make_plantuml_keyword(pkg))) fd.write('} \n') # print package for this module and a class to represent module (notifs and rpcs) @@ -716,7 +711,7 @@ def emit_module_class(self, module, fd): def emit_uml_footer(self, module, fd): - if not self.ctx_no_footer: + if self.ctx_footer: if self._ctx.opts.uml_footer is not None: fd.write('center footer\n %s \n endfooter \n' %self._ctx.opts.uml_footer) else: From 15394586e236bd7bb351772972c5ff2402e7550a Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Thu, 13 Jul 2023 17:23:08 +0200 Subject: [PATCH 13/41] Revert adding enumeration stereotype to enums, no included in a separate PR --- pyang/plugins/uml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 4fd6bf5f..1486a9ec 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -822,7 +822,7 @@ def emit_typedef(self, m, t, fd): e = t.search_one('type') if e.arg == 'enumeration': # enum_name = self.full_path(t, False) - fd.write('enum \"%s\" as %s <> {\n' %(t.arg, self.full_path(t))) + fd.write('enum \"%s\" as %s {\n' % (t.arg, self.full_path(t))) for enums in e.substmts[:int(self._ctx.opts.uml_max_enums)]: fd.write('%s\n' %enums.arg) if len(e.substmts) > int(self._ctx.opts.uml_max_enums): From 44a1d44d5eb955989330cb83159d0cc2acf9ba1b Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Thu, 13 Jul 2023 17:25:40 +0200 Subject: [PATCH 14/41] Correct unwanted formatting change --- pyang/plugins/uml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 1486a9ec..aee9d334 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -822,7 +822,7 @@ def emit_typedef(self, m, t, fd): e = t.search_one('type') if e.arg == 'enumeration': # enum_name = self.full_path(t, False) - fd.write('enum \"%s\" as %s {\n' % (t.arg, self.full_path(t))) + fd.write('enum \"%s\" as %s {\n' %(t.arg, self.full_path(t))) for enums in e.substmts[:int(self._ctx.opts.uml_max_enums)]: fd.write('%s\n' %enums.arg) if len(e.substmts) > int(self._ctx.opts.uml_max_enums): From 1a3c2458febd7fed476ddc81dcb04165e5b9af44 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Tue, 27 Jun 2023 10:22:57 +0200 Subject: [PATCH 15/41] Remove warning regarding wrong type assignment Correct default assignment to glob in function emit_grouping, should be Boolean not string. --- pyang/plugins/uml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index aee9d334..921105cd 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -867,7 +867,7 @@ def emit_uses(self, parent, node): self.uses.append([p,u]) self.uses_as_string[u] = node.arg - def emit_grouping(self, module, stmt, fd, glob = 'False'): + def emit_grouping(self, module, stmt, fd, glob = False): if not self.ctx_filterfile: # MEF # When referenced from this module From acc7f3b01e0212a6e61c37086d117b3620170ed4 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Tue, 27 Jun 2023 11:08:37 +0200 Subject: [PATCH 16/41] Modify info text to report the grouping referenced Modifies the info message to quote the name of the grouping rather than the PlantUML keyword of the parent node of the uses statement, which may not be understandable to uses not familiar with PlantUML code. --- pyang/plugins/uml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 921105cd..968eee50 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -1191,7 +1191,7 @@ def post_process_diagram(self, fd): # Grouping in other module, use red... # fd.write('class \"%s\" as %s << (G,Red) grouping>>\n' %(self.uses_as_string[u], self.make_plantuml_keyword(self.uses_as_string[u]))) # fd.write('%s --> %s : uses \n' %(p, self.make_plantuml_keyword(self.uses_as_string[u]))) - sys.stderr.write("Info: Skipping uses reference to %s, grouping not in input files \n" %p) + sys.stderr.write("Info: Skipping uses reference to %s, grouping not in input files \n" %self.uses_as_string[u]) pass if self.ctx_leafrefs: # TODO correct paths for external leafrefs From c84222d74ff8e4ac8b95b447ea5c73ce483d1263 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Wed, 19 Jul 2023 17:42:26 +0200 Subject: [PATCH 17/41] Fix dots in identifiers not being converted to underscore in PlantUML keywords PlantUML does not accept dots in keywords, but the current UML plugin does not convert dots in keywords (as permitted for YANG identifiers by RFC 7950 section 6.2) to underscores. Also to ensure there is no chance of a clash of keywords where say both the identifiers 'a.b' and 'a-b' exist, use 2 underscores for dots. --- pyang/plugins/uml.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 968eee50..034e3f9d 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -1103,10 +1103,13 @@ def grouping_name(self, s): def make_plantuml_keyword(self, s): - #plantuml does not like -/: in identifiers, fixed :) + #plantuml does not like -/:. in identifiers, fixed :) s = s.replace('-', '_') s = s.replace('/', '_') s = s.replace(':', '_') + # RFC 7950 allows YANG identifiers to contain dots and dashes, so to ensure there is no chance of a clash of keywords where say identifiers 'a.b' and 'a-b' exist, use underscores for dots + s = s.replace('.', '__') + return s From f58d6353a6045a4d522d3db459bcbebe51b1d6e6 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Wed, 19 Jul 2023 17:55:13 +0200 Subject: [PATCH 18/41] Minor correction to a comment --- pyang/plugins/uml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 034e3f9d..c2b6cf2d 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -1107,7 +1107,7 @@ def make_plantuml_keyword(self, s): s = s.replace('-', '_') s = s.replace('/', '_') s = s.replace(':', '_') - # RFC 7950 allows YANG identifiers to contain dots and dashes, so to ensure there is no chance of a clash of keywords where say identifiers 'a.b' and 'a-b' exist, use underscores for dots + # RFC 7950 allows YANG identifiers to contain dots and dashes, so to ensure there is no chance of a clash of keywords where say identifiers 'a.b' and 'a-b' exist, use 2 underscores for dots s = s.replace('.', '__') return s From d5bbef990868086f99293b43fa0e10df95d01b22 Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Thu, 13 Jul 2023 17:09:57 +0200 Subject: [PATCH 19/41] Fix issues with the rendering of identities, identityrefs, typedefs and leafrefs --- pyang/plugins/uml.py | 105 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 22 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index c2b6cf2d..13529810 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -191,7 +191,9 @@ class uml_emitter: thismod_prefix = '' _ctx = None post_strings = [] + end_strings = [] module_prefixes = [] + leafref_classes = [] choice_relation_symbol = ".." case_relation_symbol = ".." @@ -767,12 +769,21 @@ def emit_list(self, parent, node, fd): def emit_identity(self, mod, stmt, fd): if self.ctx_identities: - self.post_strings.append('class \"%s\" as %s << (I,Silver) identity>> \n' %(self.full_display_path(stmt), self.make_plantuml_keyword(stmt.arg))) - self.identities.append(stmt.arg) + # add module prefix to ensure global uniqueness across modules + identity = self.thismod_prefix + ':' + stmt.arg + keyword = self.make_plantuml_keyword(identity)+'_identity' + self.post_strings.append('class \"%s\" as %s << (I,Silver) identity>> \n' %(self.full_display_path(stmt), keyword)) + if identity not in self.identities: + self.identities.append(identity) base = stmt.search_one('base') if base is not None: - self.baseid.append(base.arg) - self.post_strings.append('%s <|-- %s \n' %(self.make_plantuml_keyword(base.arg), self.make_plantuml_keyword(stmt.arg))) + # if base does not include prefix, add prefix of current module + baseid = base.arg + if ':' not in baseid: + baseid = self.thismod_prefix+':'+baseid + if baseid not in self.baseid: + self.baseid.append(baseid) + self.post_strings.append('%s <|-- %s \n' %(self.make_plantuml_keyword(baseid)+'_identity', keyword)) def emit_feature(self, parent, feature, fd): @@ -819,10 +830,11 @@ def emit_action(self, parent, action, fd): def emit_typedef(self, m, t, fd): if self.ctx_typedefs: + keyword = self.make_plantuml_keyword(self.thismod_prefix) + '_' + self.make_plantuml_keyword(t.arg) + '_typedef' e = t.search_one('type') if e.arg == 'enumeration': # enum_name = self.full_path(t, False) - fd.write('enum \"%s\" as %s {\n' %(t.arg, self.full_path(t))) + fd.write('enum \"%s\" as %s <> {\n' %(t.arg, keyword)) for enums in e.substmts[:int(self._ctx.opts.uml_max_enums)]: fd.write('%s\n' %enums.arg) if len(e.substmts) > int(self._ctx.opts.uml_max_enums): @@ -839,8 +851,8 @@ def emit_typedef(self, m, t, fd): fd.write('%s\n' %(self.ctx_more_string)) fd.write("}\n") else: - fd.write('class \"%s\" as %s << (T, YellowGreen) typedef>>\n' %(t.arg, self.make_plantuml_keyword(t.arg))) - fd.write('%s : %s\n' %(self.make_plantuml_keyword(t.arg), self.typestring(t))) + fd.write('class \"%s\" as %s << (T, YellowGreen) typedef>>\n' %(t.arg, keyword)) + fd.write('%s : %s\n' %(keyword, self.typestring(t))) def emit_notif(self, module, stmt,fd): @@ -955,23 +967,39 @@ def typestring(self, node): s = s.replace(')', '}') if node.i_leafref_ptr is not None: - n = node.i_leafref_ptr[0] + target_node = node.i_leafref_ptr[0] else: - n = None + target_node = None - prefix, _ = util.split_identifier(p.arg) - # FIXME: previous code skipped first char, possibly in error - prefix = self.thismod_prefix if prefix is None else prefix[1:] + if target_node is not None: - if n is not None: if node.keyword == 'typedef': - self.leafrefs.append(self.make_plantuml_keyword(node.arg) + '-->' + '"' + leafrefkey + '"' + self.full_path(n.parent) + ': ' + node.arg + '\n') + source_keyword = self.make_plantuml_keyword(self.thismod_prefix) + '_' + self.make_plantuml_keyword(node.arg) + '_typedef' else: - self.leafrefs.append(self.full_path(node.parent) + '-->' + '"' + leafrefkey + '"' + self.full_path(n.parent) + ': ' + node.arg + '\n') - if prefix not in self.module_prefixes: - self.post_strings.append('class \"%s\" as %s <> \n' %(leafrefparent, self.full_path(n.parent))) - # self.post_strings.append('%s : %s\n' %(self.full_path(n.parent), leafrefkey)) - sys.stderr.write("Info: Leafref %s outside diagram. Prefix = %s\n" %(p.arg, prefix)) + source_keyword = self.full_path(node.parent) + + target_prefix, _ = util.split_identifier(leafrefkey) + # FIXME: previous code skipped first char, possibly in error + if target_prefix is None: + target_prefix = self.thismod_prefix + + # if target node (last node in path) is located in the list of input modules, a relation to the target class can be created + if target_prefix in self.module_prefixes: + # if the relation is internal to this module append to leafrefs else append to end of diagram outside the scope of any input module + target_keyword = self.full_path(target_node.parent) + if target_prefix == self.thismod_prefix: + self.leafrefs.append(source_keyword + '-->' + '"' + leafrefkey + '"' + target_keyword + ': ' + node.arg + '\n') + else: + self.end_strings.append(source_keyword + '-->' + '"' + leafrefkey + '"' + target_keyword + ': ' + node.arg + '\n') + else: + # no target within input modules, so create a class as placeholder + target_keyword = self.full_path(target_node.parent) + '_leafref' + # add a class to represent the target of the leafref, if not already previously created during processing of this module + if target_keyword not in self.leafref_classes: + self.post_strings.append('class \"%s\" as %s <> \n' %(leafrefparent, target_keyword)) + self.leafref_classes.append(target_keyword) + self.leafrefs.append(source_keyword + '-->' + '"' + leafrefkey + '"' + target_keyword + ': ' + node.arg + '\n') + sys.stderr.write("Info: Leafref %s outside diagram. Prefix = %s\n" %(p.arg, target_prefix)) else: sys.stderr.write("Info: Did not find leafref target %s\n" %p.arg) @@ -989,7 +1017,30 @@ def typestring(self, node): if b is not None: s = s + ' {' + b.arg + '}' if self.ctx_identityrefs and self.ctx_identities: - self.post_strings.append(self.full_path(node.parent) + '-->' + self.make_plantuml_keyword(b.arg) + ': ' + node.arg + '\n') + baseid = b.arg + if ':' not in baseid: + # if no prefix found, it must be defined in this module, so add this module's prefix + baseid = self.thismod_prefix + ':' + baseid + + if baseid not in self.baseid: + self.baseid.append(baseid) + + if node.keyword == 'typedef': + keyword = self.make_plantuml_keyword(self.thismod_prefix) + '_' + self.make_plantuml_keyword(node.arg) + '_typedef' + else: + keyword = self.full_path(node.parent) + + # add a relation to the baseid: + # if baseid is defined in this module, then an identity class will have been defined in this module and + # if baseid is not in an input module, then function post_process_module() will then add a placeholder class for the identity + # in both the above cases the keyword will be then same + # if baseid is in another input module, then an identity class will have been defined there (with the same keyword), in which case the relation must be defined outside of the module packages + prefix, _ = util.split_identifier(baseid) + if prefix == self.thismod_prefix or prefix not in self.module_prefixes: + self.post_strings.append(keyword + '-->' + self.make_plantuml_keyword(baseid) + '_identity : ' + node.arg + '\n') + else: + self.end_strings.append(keyword + '-->' + self.make_plantuml_keyword(baseid) + '_identity : ' + node.arg + '\n') + elif t.arg == 'union': uniontypes = t.search('type') @@ -1185,6 +1236,7 @@ def find_target_node(self, stmt): stmt.i_annotate_node = node return inthismod, node + def post_process_diagram(self, fd): if self.ctx_uses: for p,u in self.uses: @@ -1201,6 +1253,9 @@ def post_process_diagram(self, fd): for l in self.leafrefs: fd.write(l) + for s in self.end_strings: + fd.write(s) + # remove duplicates self.augments = list(set(self.augments)) for augm in self.augments: @@ -1210,13 +1265,19 @@ def post_process_diagram(self, fd): def post_process_module(self, module, fd): for base in self.baseid: + # If a base is not defined in the module, define it, if it is not in another input module if not base in self.identities: - fd.write('class \"%s\" as %s << (I,Silver) identity>> \n' %(base, self.make_plantuml_keyword(base))) + prefix, _ = util.split_identifier(base) + if prefix not in self.module_prefixes: + keyword = self.make_plantuml_keyword(base) + '_identity' + fd.write('class \"%s\" as %s << (I,Silver) identity>> \n' %(base, keyword)) for s in self.post_strings: fd.write(s) - self.based = [] + self.baseid = [] + self.identities = [] + self.leafref_classes = [] self.post_strings = [] if not self.ctx_no_module: From 54c39164012e2fca490b6df7662af5ba157f02be Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Fri, 21 Jul 2023 16:40:03 +0200 Subject: [PATCH 20/41] Fix missing notifications defined in interior data nodes --- pyang/plugins/uml.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 13529810..2e71f1ab 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -562,6 +562,8 @@ def emit_child_stmt(self, parent, node, fd, cont = True): elif node.keyword == 'leaf-list': fd.write('%s : %s %s %s\n' %(self.full_path(parent), node.arg, '[]: ' + self.typestring(node), self.attribs(node)) ) self.emit_must_leaf(parent, node, fd) + elif node.keyword == 'notification': + self.emit_notif(parent, node, fd) elif node.keyword in ['action', ('tailf-common', 'action')]: self.emit_action(parent, node, fd) elif node.keyword == ('tailf-common', 'callpoint'): @@ -855,13 +857,13 @@ def emit_typedef(self, m, t, fd): fd.write('%s : %s\n' %(keyword, self.typestring(t))) - def emit_notif(self, module, stmt,fd): + def emit_notif(self, parent, node, fd): # ALTERNATIVE 1 # notif as class stereotype, ugly, but easier to layout params - fd.write('class \"%s\" as %s << (N,#00D1B2) notification>> \n' %(self.full_display_path(stmt), self.full_path(stmt))) - fd.write('%s -- %s : notification \n' %(self.make_plantuml_keyword(module.arg), self.full_path(stmt))) - for params in stmt.substmts: - self.emit_child_stmt(stmt, params, fd) + fd.write('class \"%s\" as %s << (N,#00D1B2) notification>> \n' % (self.full_display_path(node), self.full_path(node))) + fd.write('%s -- %s : notification \n' % (self.make_plantuml_keyword(self.full_path(parent)), self.full_path(node))) + for params in node.substmts: + self.emit_child_stmt(node, params, fd) # ALTERNATIVE 2 # notif as oper, better, but hard to layout params From ecf1bf1ed28f1c11cf01d9f09d9d6818ff4957fe Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Fri, 28 Jul 2023 14:35:11 +0200 Subject: [PATCH 21/41] Move emit_child_stmt() out of emit_notify() Whether further child statements should be rendered depends on whether cont=true when emit_child_stmt() is called and by augments it is set to false, but emit_notify() always emits child statements. So this change moves the the call to emit_child_stmt() out of emit_notify() in the same way that this is done for lists. --- pyang/plugins/uml.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 2e71f1ab..5b57ac7e 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -448,6 +448,8 @@ def emit_stmt(self, mod, stmt, fd): self.emit_action(mod, stmt,fd) elif stmt.keyword == 'notification': self.emit_notif(mod, stmt,fd) + for s in stmt.substmts: + self.emit_child_stmt(stmt, s, fd) elif stmt.keyword == 'feature': self.emit_feature(mod,stmt, fd) elif stmt.keyword == 'deviation': @@ -564,6 +566,9 @@ def emit_child_stmt(self, parent, node, fd, cont = True): self.emit_must_leaf(parent, node, fd) elif node.keyword == 'notification': self.emit_notif(parent, node, fd) + if cont: + for children in node.substmts: + self.emit_child_stmt(node, children, fd) elif node.keyword in ['action', ('tailf-common', 'action')]: self.emit_action(parent, node, fd) elif node.keyword == ('tailf-common', 'callpoint'): @@ -862,8 +867,8 @@ def emit_notif(self, parent, node, fd): # notif as class stereotype, ugly, but easier to layout params fd.write('class \"%s\" as %s << (N,#00D1B2) notification>> \n' % (self.full_display_path(node), self.full_path(node))) fd.write('%s -- %s : notification \n' % (self.make_plantuml_keyword(self.full_path(parent)), self.full_path(node))) - for params in node.substmts: - self.emit_child_stmt(node, params, fd) + # for params in node.substmts: + # self.emit_child_stmt(node, params, fd) # ALTERNATIVE 2 # notif as oper, better, but hard to layout params From 9bc3d4b2f6410f8033c403fd1af78ca8430101e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Wed, 1 Nov 2023 09:46:40 +0100 Subject: [PATCH 22/41] converted man pages from docbook to markdown; use pandoc to create nroff --- doc/Makefile | 29 +- doc/json2xml.1.dbk | 170 --- doc/pyang.1.dbk | 2556 ------------------------------------------- doc/yang2dsdl.1.dbk | 517 --------- 4 files changed, 5 insertions(+), 3267 deletions(-) delete mode 100644 doc/json2xml.1.dbk delete mode 100644 doc/pyang.1.dbk delete mode 100644 doc/yang2dsdl.1.dbk diff --git a/doc/Makefile b/doc/Makefile index db8df1db..089fd005 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,19 +1,6 @@ -# ifeq ($(DBSS),) -# DBSS=$(wildcard /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl) -# endif -# ifeq ($(DBSS),) -# DBSS=$(wildcard /usr/share/sgml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl) -# endif -# ifeq ($(DBSS),) -# $(error docbook stylesheet not found) -# endif +MANPAGES=$(patsubst %.1.md,../man/man1/%.1,$(wildcard *.1.md)) -# NOTE: 1.79.1 generates bad man pages; they don't render properly -#DBURI=http://docbook.sourceforge.net/release/xsl/current -DBURI=http://docbook.sourceforge.net/release/xsl/1.78.1 -MANPAGES=../man/man1/yang2dsdl.1 ../man/man1/pyang.1 ../man/man1/json2xml.1 - -PYANG_VERSION=$(shell grep __version__ ../pyang/__init__.py | \ +VERSION=$(shell grep __version__ ../pyang/__init__.py | \ awk -F\' '{print $$2}') DATE=$(shell grep __date__ ../pyang/__init__.py | \ awk -F\' '{print $$2}') @@ -24,14 +11,8 @@ all: $(MANPAGES) clean: rm -f $(MANPAGES) -../man/man1/%.1: %.1.dbk - cat $< | \ - sed -e 's/%PYANG_VERSION%/$(PYANG_VERSION)/g' \ - -e 's/%DATE%/$(DATE)/g' | \ - xsltproc -o $@ $(DBURI)/manpages/docbook.xsl - - -%.1.html: %.1.dbk +../man/man1/%.1: %.1.md cat $< | \ - sed -e 's/%PYANG_VERSION%/$(PYANG_VERSION)/g' \ + sed -e 's/%VERSION%/$(VERSION)/g' \ -e 's/%DATE%/$(DATE)/g' | \ - xsltproc -o $@ $(DBURI)/xhtml/docbook.xsl - + pandoc - -s -t man -o $@ diff --git a/doc/json2xml.1.dbk b/doc/json2xml.1.dbk deleted file mode 100644 index 7a0dc35c..00000000 --- a/doc/json2xml.1.dbk +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - Ladislav Lhotka - CZ.NIC - lhotka@nic.cz - - - %DATE% - - - - json2xml - 1 - pyang manual - json2xml-%PYANG_VERSION% - - - - json2xml - translates JSON documents conforming to a YANG data - model into XML. - - - - - json2xml - -t target - -o output_file - - driver_file - - - json_file - - - - json2xml - - -h - --help - - - - - - Description - This program translates json_file - into XML using the procedure specified in - RFC 7951. - The translation uses a second input file, - driver_file, which contains a concise - JSON representation of the YANG data model to which - json_file should conform, at least - structurally. Normally, driver_file is - obtained as the jtox output of - pyang. - Using "-" (hyphen) in place of - json_file instructs the program to read - a JSON document from the standard input. - The target argument specifies the - document (root) element for the output XML document. This - encapsulation is necessary because the input JSON document may - contain multiple JSON objects at the top level. Supported values - for the target argument are: - - - data - The document element will be - <nc:data>. This is the default. - - - config - The document element will be <nc:data>. - - - The XML prefix "nc" represents the standard - NETCONF namespace with URI - "urn:ietf:params:xml:ns:netconf:base:1.0". - - - - Options - - - - target, - target - - - Specifies the target type of the output XML document, - i.e. its document element. The default is - data. - - - - - output_file, - output_file - - - Write output to output_file - instead of the standard output. - - - - - , - - - - Displays help screen and exits. - - - - - - - Example - - $ pyang -f jtox -o dhcp.jtox dhcp.yang - $ json2xml -o dhcp-data.xml dhcp.jtox dhcp-data.json - The first command generates the driver file - dhcp.jtox, which is then used for translating - JSON file dhcp-data.json to XML file - dhcp-data.xml. - - - - Diagnostics - json2xml return codes have the - following meaning: - - - 0 - No error (normal termination) - - - 1 - One of the input files cannot be read - - - 2 - Error in command line arguments - - - 3 - JSON to XML translation failed - - - - - - See Also - RFC 7951, - pyang - 1 - , - JSON. - - - - diff --git a/doc/pyang.1.dbk b/doc/pyang.1.dbk deleted file mode 100644 index 9b766837..00000000 --- a/doc/pyang.1.dbk +++ /dev/null @@ -1,2556 +0,0 @@ - - - - - - Martin Björklund - Tail-f Systems - mbj@tail-f.com - - - - Ladislav Lhotka - CZ.NIC - lhotka@nic.cz - - - - Stefan Wallin - Tail-f Systems - stefan@tail-f.com - - - - %DATE% - - - - pyang - 1 - pyang manual - pyang-%PYANG_VERSION% - - - - pyang - - validate and convert YANG modules to various formats - - - - - - pyang - --verbose - --canonical - --strict - --lint - --ietf - --lax-quote-checks - --lax-xpath-checks - --features features - --exclude-features features - --max-status maxstatus - --hello - --implicit-hello-deviations - --check-update-from oldfile - -o outfile - -t transform - -f format - -p path - -W warning - -E error - - file - - - - - pyang - --sid-list - --sid-generate-file - - count - entry-point:size - - yang-filename - - - - pyang - --sid-list - --sid-update-file - sid-filename - yang-filename - --sid-extra-range - - count - entry-point:size - - - - - - pyang - --sid-list - --sid-check-file - sid-filename - yang-filename - - - - pyang - - -h - --help - - - - pyang - - -v - --version - - - - - One or more file parameters may be - given on the command line. They denote either YANG modules to be - processed (in YANG or YIN syntax) or, using the - switch, a server <hello> message - conforming to RFC 6241 - and RFC - 6020, which completely defines the data model - supported - YANG modules as well as features and capabilities. In the latter - case, only one file parameter may be - present. - - - - If no files are given, pyang reads input - from stdin, which must be one module or a server <hello> message. - - - - - Description - - The pyang program is used to validate YANG - modules (RFC - 6020 and RFC - 7950). It is also used to convert YANG modules into - equivalent YIN modules. From a valid module a hybrid DSDL schema (RFC 6110) - can be generated. - - - - If no format is given, the specified - modules are validated, and the program exits with exit code 0 if - all modules are valid. - - - - - Options - - - - - - - - - - Print a short help text and exit. - - - - - - - - - - - - Print the version number and exit. - - - - - - - - - - - - Print a listing of all error codes and messages pyang - might generate, and then exit. - - - - - - - - - - - On errors, print the symbolic error code instead of the - error message. - - - - - - - - - - - On errors, print only the base file name independent - of its module path location. - - - - - - - - - - - Treat warnings as errors. - - - - - - - - - - - Do not print any warnings. - - - - - - - - errorcode - - - - Treat errorcode as a warning, - even if is given. - errorcode must be a warning or - a minor error. - - - Use to get a listing of all - errors and warnings. - - - The following example treats all warnings except the - warning for unused imports as errors: - - - $ pyang --Werror -W UNUSED_IMPORT - - - - - - - - errorcode - - - - Treat the warning errorcode as - an error. - - - Use to get a listing of all - errors and warnings. - - - The following example treats only the warning for unused - import as an error: - - - $ pyang --Werror -W UNUSED_IMPORT - - - - - - - - errorcode - - - - Ignore error errorcode. - - - Use with care. Plugins that don't expect to be invoked if - there are errors present may crash. - - - Use to get a listing of all - errors and warnings. - - - The following example ignores syntax errors in patterns: - - - $ pyang --ignore-error PATTERN_ERROR - - - - - - - - msg-template - - - - Print out error message in defined msg-template. - - - Template used to display error messages. This is a python - new-style format string used to format the message - information with keys file, line, code, type, and msg. - - - The following example create a msg template in defined pattern: - - - $ pyang --msg-template='{file} || {line} || {type} || {level} || {code} || {msg}' - - - - - - - - - - - Ignore all errors. Use with care. Plugins that don't expect - to be invoked if there are errors present may crash. - - - - - - - - - - - This parameter has effect only if a plugin can handle - comments. - - - - - - - - - - - Validate the module(s) according to the canonical YANG order. - - - - - - - - - - - Ensure that the revision history in the given module(s) is - correct, by checking that it can find the old revisions of - the module(s) in the YANG module search path. - - - - - - - - - - - Force strict YANG compliance. Currently this checks - that the deref() function is not used in XPath expressions - and leafrefs. - - - - - - - - - - - Validate the module(s) according to the generic YANG guideline as - specified in RFC - 8407. In addition, it checks that the module is in - canonical order. - - - - - - - - - - - Validate the module(s) like , and - in addition verifies that the namespace and module name - follow the IETF conventions, and that the module has the - correct license text and RFC - 2119 / RFC - 8174 boilerplate text. - - - - - - - - - - - Lax checks of backslashes in double quoted strings in YANG - version 1 modules. RFC - 6020 does not clearly define how to handle - backslahes within double quoted strings, when the - character after the backslash is not one of the characters - listed in Section 6.1.3 in RFC - 6020. - - - Earlier versions of pyang silently accepted such escape - sequences, but the current version treats this as an - error, just like it is defined in YANG 1.1 (RFC - 7950). Passing this flag to pyang makes pyang - silently accept such escape sequences. - - - - - - - - - - - Lax checks of XPath expressions. Specifically, do not - generate an error if an XPath expression uses a variable - or an unknown function. - - - - - - - - - - - - Interpret the input file or standard input as a server - <hello> message. In this case, no more than one - file parameter may be given. - - - - - - - - - - - Attempt to parse all deviations from a supplied <hello> - message. Not all implementations provide deviations explicitly - as modules. This flag enables more logic to attempt to derive - all deviations from the message. - - - - - - - - - - - In YIN input modules, remove leading and trailing - whitespace from every line in the arguments of the - following statements: 'contact', 'description', - 'error-message', 'organization' and 'reference'. This way, - the XML-indented argument texts look tidy after - translating the module to the compact YANG syntax. - - - - - - - - maxlen - - - - Give a warning if any line is longer than - maxlen. The value 0 means no - check (default). - - - - - - - - maxlen - - - - Give a error if any identifier is longer than - maxlen. - - - - - - - - - transform - - - - Transform the module(s) after parsing them but before outputting - them. Multiple transformations can be given, and will be performed - in the order that they were specified. The supported - transformations are listed in below. - - - - - - - - - format - - - - Convert the module(s) into - format. Some translators - require a single module, and some can translate multiple - modules at one time. If no - outfile file is specified, the - result is printed on stdout. The supported formats are - listed in below. - - - - - - - - - outfile - - - - Write the output to the file - outfile instead of stdout. - - - - - - - - - features - - - - features is a string of the - form - modulename:[feature(,feature)*] - - - This option is used to prune the data model by removing - all nodes that are defined with a "if-feature" that is - not listed as feature. This option - affects all output formats. - - - This option can be given multiple times, and may also be combined - with . The - option overrides any supported features for a module that are taken - from the hello file. - - - If this option is not given, nothing is pruned, i.e., it works - as if all features were explicitly listed. - - - The option can be used for - excluding a list of named features. and - can't both be specified for a - given module. - - - For example, to view the tree output for a module with all - if-feature'd nodes removed, do: - - - $ pyang -f tree --features mymod: mymod.yang - - - - - - - - - features - - - - features is a string of the - form - modulename:[feature(,feature)*] - - - This option is used to prune the data model by removing - all nodes that are defined with a "if-feature" that is - listed as feature. This option - affects all output formats. - - - This option can be given multiple times. It can't be combined with - . - - - The option can be used for including - all features or a list of named - features. and - can't both be specified for a - given module. - - - For example, to view the tree output for a module with - if-feature'd nodes for the specified feature removed, do: - - - $ pyang -f tree --exclude-features mymod:myfeat mymod.yang - - - - - - - - maxstatus - - - - maxstatus is one of: - current, - deprecated, or - obsolete. - - - This option is used to prune the data model by removing - all nodes that are defined with a "status" that is less - than the given maxstatus. This - option affects all output formats. - - - - - - - - file - - - - This option is used to apply the deviations defined in - file. This option - affects all output formats. - - - This option can be given multiple times. - - - For example, to view the tree output for a module with some - deviations applied, do: - - - $ pyang -f tree --deviation-module mymod-devs.yang mymod.yang - - - - - - - - - path - - - - path is a colon (:) separated - list of directories to search for imported modules. This - option may be given multiple times. - - - By default, all directories (except ".") found in the path - are recursively scanned for modules. This behavior can be - disabled by giving the option . - - - The following directories are always added to the search path: - - - - - current directory - - - - - $YANG_MODPATH - - - - - $HOME/yang/modules - - - - - $YANG_INSTALL/yang/modules - OR if $YANG_INSTALL is unset - <the default installation - directory>/yang/modules (on Unix - systems: /usr/share/yang/modules) - - - - - - - - - - - - - If this parameter is given, directories in the search path - are not recursively scanned for modules. - - - - - - - - plugindir - - - - Load all YANG plugins found in the directory - plugindir. This option may be given - multiple times. - - - list of directories to search for pyang plugins. The - following directories are always added to the search - path: - - - - - pyang/plugins from - where pyang is installed - - - - - $PYANG_PLUGINPATH - - - - - - - - - - oldfile - - - - Checks that a new revision of a module follows the update - rules given in RFC - 6020 and RFC - 7950. oldfile is the old - module and file is the new version of - the module. - - - If the old module imports or includes any modules or - submodules, it is important that the the old versions of - these modules and submodules are found. By default, the - directory where oldfile is found is - used as the only directory in the search path for old - modules. Use the option - to control this - path. - - - - - - - - - oldpath - - - - oldpath is a colon (:) separated - list of directories to search for imported modules. This - option may be given multiple times. - - - - - - - - - olddeviation - - - - olddeviation is an old deviation module - of the old module oldfile. This option - may be given multiple times. For example, to check updates of - a module with some deviations applied, do: - - - $ pyang --check-update-from-deviation-module oldmod-devs.yang --check-update-from oldmod.yang \ - --deviation-module newmod-devs.yang newmod.yang - - - - - - - file... - - - - These are the names of the files containing the modules to - be validated, or the module to be converted. - - - - - - - - - - - Transformations - - - - Installed pyang transformations are (like output formats) plugins and - therefore may define their own options, or add new transformations to the - option. These options and transformations are listed in pyang -h. - - - - - edit - - - Modify the supplied module(s) in various ways. This transform will usually be used - with the yang output format. - - - - - - - - Edit Transform - - The edit transform modifies the supplied module(s) in various ways. - It can, for example, replace top-level description statements, update - include statements and manage revision statements. - Unless otherwise noted below, it only modifies existing - statements. - - - Each edit transform string (non-date) option value is either a plain - string (which is taken literally) or a +-separated list of directives - (whose expansions are concatenated with double-linebreak separators, i.e. each directive - results in one or more paragraphs). - - - Each directive is either of the form @filename (which is replaced - with the contents of the file; there is no search path; trailing whitespace is discarded) or - of the form %keyword. Any unrecognized directives are treated as plain - strings. The following %-directives are currently supported: - - - %SUMMARY : This expands to a "summary" of the original argument - value. It's intended for use with top-level description statements - that typically consist of a hand-crafted summary followed by copyrights, license and - other boiler-plate text. The summary is the text up to but not including the first line - that (ignoring leading and trailing whitespace) starts with the word - Copyright followed by a space. - - - - - %SUBST/old/new : This expands to the original argument value - with all instances of old replaced with new. - There is no provision for replacing characters that contain forward slashes, and there - is no terminating slash. - - - - - %DELETE : This clears the output buffer and suppresses a check - that would normally prevent overwriting an existing value (unless that value is the - literal string TBD). - - - - - - In the examples given below, it's assumed that there are CONTACT, - CONTEXT, LICENSE, - ORGANIZATION, REFERENCE and - REVISION files in a top-level project directory (which in this case is - the parent of the directory in which pyang is being run). These examples - illustrate how the edit transform might be used with the - yang output format to prepare YANG files for publication. - - - Edit transform specific options: - - - - - - version - - - - Set the YANG version (i.e., the yang-version statement's - argument) to version. This does nothing if the YANG module - doesn't already have a yang-version statement. - - - Example: --edit-yang-version 1.1. - - - - - - - namespace - - - - Set the YANG namespace (i.e., the namespace statement's - argument) to namespace. This does nothing if the YANG module - doesn't already have a namespace statement. - - - Example: --edit-namespace %SUBST/acme-pacific-org/apo - - - - - - - - - - Update any import (or include) - revision-date statements to match imported (or included) modules - and submodules. If there isn't already a revision-date statement, - it will be added. - - - - - - - - - Delete any import (or include) - revision-date statements. - - - - - - - organization - - - - Set the organization (i.e. the organization statement's - argument) to organization. This does nothing if the YANG - module doesn't already have an organization statement. - - - Example: --edit-organization @../ORGANIZATION - - - - - - - contact - - - - Set the contact info (i.e. the contact statement's argument) to - contact. This does nothing if the YANG module doesn't - already have a contact statement. - - - Example: --edit-contact @../CONTACT - - - - - - - description - - - - Set the top-level description (i.e. the top-level description - statement's argument) to description. This does nothing if - the YANG module doesn't already have a description - statement. - - - Example: --edit-description %SUMMARY+@../LICENSE+@../CONTEXT - - - - - - - prevdate - - - - Delete any revision statements after (i.e. that are more - recent than) the supplied yyyy-mm-dd revision date. A typical use - case is to supply the date of the previous release: any revisions since then will be - internal (e.g. developers often feel that they should add revision statements for git - commits) and are not wanted in the next released version. - - - Example: --edit-delete-revisions-after 2019-03-15 - - - - - - - date - - - - Set the most recent revision date to the supplied - yyyy-mm-dd revision date. This does nothing if the YANG - module doesn't already have at least one revision statement. If - necessary, a new revision statement will be inserted before any - (remaining) existing revisions. - - - Example: --edit-revision-date 2020-03-15 - - - - - - - description - - - - Set the most recent revision description to description. - - - Example: --edit-revision-description=%DELETE+@../REVISION - - - - - - - reference - - - - Set the most recent revision reference to reference. - - - Example: --edit-revision-reference=%DELETE+@../REFERENCE - - - - - - - - - - Output Formats - - - - Installed pyang plugins may define their own - options, or add new formats to the option. - These options and formats are listed in pyang -h. - - - - - capability - - Capability URIs for each module of the data model. - - - - depend - - Makefile dependency rule for the module. - - - - dsdl - - Hybrid DSDL schema, see RFC - 6110. - - - - identifiers - - All identifiers in the module. - - - - jsonxsl - - XSLT stylesheet for transforming XML instance - documents to JSON. - - - - jstree - - HTML/JavaScript tree navigator. - - - - jtox - - Driver file for transforming JSON - instance documents to XML. - - - - name - - Module name, and the name of the main module for a - submodule. - - - - omni - - An applescript file that draws a diagram in - OmniGraffle. - - - - sample-xml-skeleton - - Skeleton of a sample XML instance document. - - - - tree - - Tree structure of the module. - - - - flatten - - Print the schema nodes in CSV form. - - - - uml - - UML file that can be read by - plantuml to generate UML diagrams. - - - - yang - - Normal YANG syntax. - - - - yin - - The XML syntax of YANG. - - - - - - - - Lint Checker - - The lint option validates that the module - follows the generic conventions and rules given in RFC 8407. - In addition, it checks that the module is in canonical order. - - - Options for the lint checker: - - - - - - - prefix - - - - Validate that the module's namespace is of the form: - "<prefix><modulename>". - - - - - - - - - prefix - - - - Validate that the module's name starts with - prefix. - - - - - - - - - - - - Validate that all identifiers use hyphenated style, i.e., - no uppercase letters or underscores. - - - - - - - - YANG Schema Item iDentifiers (SID) - - YANG Schema Item iDentifiers (SID) are globally unique unsigned integers - used to identify YANG items. SIDs are used instead of names to save space - in constrained applications such as COREconf. This plugin is used to - automatically generate and updated .sid files used to persist and - distribute SID assignments. - - - Options for generating, updating and checking .sid files: - - - - - - - This option is used to generate a new .sid file from a YANG module. - - - Two arguments are required to generate a .sid file; the SID range assigned - to the YANG module and its definition file. The SID range specified is a - sub-range within a range obtained from a registrar or a sub-range within - the experimental range (i.e. 60000 to 99999). The SID range consists of - the first SID of the range, followed by a colon, followed by the number - of SID allocated to the YANG module. The filename consists of the module - name, followed by an @ symbol, followed by the module revision, followed - by the ".yang" extension. - - - This example shows how to generate the file - toaster@2009-11-20.sid. - - - $ pyang --sid-generate-file 20000:100 toaster@2009-11-20.yang - - - - - - - - Each time new items are added to a YANG module by the introduction of - a new revision of this module, its included sub-modules or imported - modules, the associated .sid file need to be updated. This is done - by using the option. - - - Two arguments are required to generate a .sid file for an updated YANG - module; the previous .sid file generated for the YANG module and the - definition file of the updated module. Both filenames follow the usual - naming conversion consisting of the module name, followed by an @ symbol, - followed by the module revision, followed by the extension. - - - This example shows how to generate the file - toaster@2009-12-28.sid based on the SIDs already - present in toaster@2009-11-20.sid. - - - $ pyang --sid-update-file toaster@2009-11-20.sid \ -toaster@2009-12-28.yang - - - - - - - - The option can be used at any time - to verify if a .sid file need to be updated. - - - Two arguments are required to verify a .sid file; the filename of the .sid file - to be checked and the corresponding definition file. - - - For example: - - - $ pyang --sid-check-file toaster@2009-12-28.sid \ -toaster@2009-12-28.yang - - - - - - - - The option can be used before any of the - previous options to obtains the list of SIDs assigned or validated. For example: - - - $ pyang --sid-list --sid-generate-file 20000:100 \ -toaster@2009-11-20.yang - - - - - - - - If needed, an extra SID range can be assigned to an existing YANG module - during its update with the option. - - - For example, this command generates the file toaster@2009-12-28.sid - using the initial range(s) present in toaster@2009-11-20.sid - and the extra range specified in the command line. - - - $ pyang --sid-update-file toaster@2009-11-20.sid \ -toaster@2009-12-28.yang --sid-extra-range 20100:100 - - - - - count - - - The number of SID required when generating or updating a .sid file can - be computed by specifying "count" as SID range. - - - For example: - - - $ pyang --sid-generate-file count toaster@2009-11-20.yang - - - or: - - - $ pyang --sid-update-file toaster@2009-11-20.sid \ -toaster@2009-12-28.yang --sid-extra-range count - - - - - - - - Capability Output - The capability output prints a - capability URL for each module of the input data model, taking - into account features and deviations, as described in section - 5.6.4 of RFC 6020. - - Options for the capability output format: - - - - - - - - Write ampersands in the output as XML entities ("&amp;"). - - - - - - - - Depend Output - - The depend output generates a Makefile - dependency rule for files based on a YANG module. This is - useful if files are generated from the module. For example, - suppose a .c file is generated from each YANG module. If the - YANG module imports other modules, or includes submodules, the - .c file needs to be regenerated if any of the imported or - included modules change. Such a dependency rule can be - generated like this: - - - - $ pyang -f depend --depend-target mymod.c \ - --depend-extension .yang mymod.yang - mymod.c : ietf-yang-types.yang my-types.yang - - - - Options for the depend output format: - - - - - - - Makefile rule target. Default is the module name. - - - - - - - - YANG module file name extension. Default is no extension. - - - - - - - - Do not generate dependencies for included submodules. - - - - - - - - Generate dependencies taken from all included submodules. - - - - - - - - Recurse into imported modules and generate dependencies - for their imported modules etc. - - - - - - - - Include file path in the prerequisites. Note that if no - has been given, the - prerequisite is the filename as found, i.e., ending in - ".yang" or ".yin". - - - - - - - - Name of YANG module or submodule to ignore in the - prerequisites. This option can be given multiple times. - - - - - - - - DSDL Output - The dsdl output takes a data model - consisting of one or more YANG modules and generates a hybrid - DSDL schema as described in RFC - 6110. The hybrid schema is primarily intended as an - interim product used by yang2dsdl(1). - The dsdl plugin also supports metadata - annotations, if they are defined and used as described in RFC - 7952. - - Options for the dsdl output format: - - - - - - - Do not print documentation annotations - - - - - - - - Do not print Dublin Core metadata terms - - - - - - - - Record translations of all top-level typedefs and - groupings in the output schema, even if they are not - used. This is useful for translating library modules. - - - - - - - - - JSONXSL Output - - The jsonxsl output generates an XSLT 1.0 - stylesheet that can be used for transforming an XML instance - document into JSON text as specified in RFC - 7951. The XML document must be a valid instance of the - data model which is specified as one or more input YANG modules - on the command line (or via a <hello> message, see the - option). - - The jsonxsl plugin also converts - metadata annotations, if they are defined and used as described - in RFC - 7952. - - The data tree(s) must be wrapped at least in either - <nc:data> or <nc:config> element, where "nc" is the - namespace prefix for the standard NETCONF URI - "urn:ietf:params:xml:ns:netconf:base:1.0", or the XML instance - document has to be a complete NETCONF RPC request/reply or - notification. Translation of RPCs and notifications defined by - the data model is also supported. - - - The generated stylesheet accepts the following parameters that - modify its behaviour: - - - - compact: setting this parameter to - 1 results in a compact representation of the JSON text, - i.e. without any whitespace. The default is 0 which means that - the JSON output is pretty-printed. - - - ind-step: indentation step, - i.e. the number of spaces to use for each level. The default - value is 2 spaces. Note that this setting is only useful for - pretty-printed output (compact=0). - - - - The stylesheet also includes the file - jsonxsl-templates.xsl which is a part of - pyang distribution. - - - - - jstree Output - - The jstree output grenerates an - HTML/JavaScript page that presents a tree-navigator to the given - YANG module(s). - - - jstree output specific option: - - - - - - - Do not include paths in the output. This option makes the - page less wide. - - - - - - - - JTOX Output - - The jtox output generates a driver file - which can be used as one of the inputs to - json2xml for transforming a JSON document - to XML as specified in RFC - 7951. - - - The jtox output itself is a JSON document - containing a concise representation of the data model which is - specified as one or more input YANG modules on the command line - (or via a <hello> message, see the - option). - - - See json2xml manual page for more information. - - - - - Omni Output - - The plugin generates an - applescript file that draws a diagram in OmniGraffle. Requires - OmniGraffle 6. Usage: - - $ pyang -f omni foo.yang -o foo.scpt -$ osascript foo.scpt - - - - omni output specific option: - - - - - - path - - - - Subtree to print. The path is - a slash ("/") separated path to a subtree to print. For - example "/nacm/groups". - - - - - - - - Name Output - The name output prints the name of each - module in the input data model. For submodules, it also shows the - name of the main module to which the submodule belongs. - - name output specific option: - - - - - - - - - Print the name and revision in name@revision format. - - - - - - - - Sample-xml-skeleton Output - - The sample-xml-skeleton output generates an - XML instance document with sample elements for all nodes in the - data model, according to the following rules: - - - - An element is present for every leaf, container or anyxml. - - - At least one element is present for every leaf-list or - list. The number of entries in the sample is min(1, - min-elements). - - - For a choice node, sample element(s) are present for - each case. - - - Leaf, leaf-list and anyxml elements are empty (but see - the option - below). - - - Note that the output document will most likely be invalid - and needs manual editing. - - Options specific to the sample-xml-skeleton output - format: - - - - - - - Add XML comments to the sample documents with hints about - expected contents, for example types of leaf nodes, - permitted number of list entries etc. - - - - - - - - Add leaf elements with defined defaults to the output with - their default value. Without this option, the default - elements are omitted. - - - - - - - - - - Type of the sample XML document. Supported values for - type are - data (default) and - config. This option determines the - document element of the output XML document (<data> - or <config> in the NETCONF namespace) and also affects the contents: for - config, only data nodes representing - configuration are included. - - - - - - - - - - Subtree of the sample XML document to generate, including - all ancestor elements. The - path is a slash ("/") separated - list of data node names that specifies the path to a subtree to - print. For example "/nacm/rule-list/rule/rpc-name". - - - - - - - - Tree Output - - The tree output prints the resulting schema - tree from one or more modules. Use pyang - --tree-help to print a description on the symbols - used by this format. - - - Tree output specific options: - - - - - - - Print help on symbols used in the tree output and exit. - - - - - - - depth - - - - Levels of the tree to print. - - - - - - - path - - - - Subtree to print. The path is - a slash ("/") separated path to a subtree to print. For - example "/nacm/groups". All ancestors and the selected - subtree are printed. - - - - - - - - - - Print the top-level groupings defined in the module. - - - - - - - - - - Print the ietf-yang-structure-ext:structure structures - defined in the module. - - - - - - - - - - Print the ietf-restconf:yang-data structures defined in - the module. - - - - - - - maxlen - - - - Try to break lines so they are no longer than - maxlen. This is a best effort - algorithm. - - - - - - - maxlen - - - - Use the module name (instead of the prefix) to prefix - parameters and types. - - - - - - - - Flatten Output - - The flatten output flattens provided - YANG module and outputs the schema nodes and some of their - properties in CSV format. - - - Flatten output specific options: - - - - - - - Do not emit the CSV header. - - - - - - - - Output the keyword. - This will resolve as container, leaf, etc. - - - - - - - - Output the top-level type. - This will resolve to a module-prefixed type. - - - - - - - - Output the primitive type. - This resolves to a YANG type such as uint64. - - - - - - - - Output flag property. - Derives a flag - for instance rw/ro for config, or x for RPC. - - - - - - - - Output the description. - - - - - - - - Output whether the XPath is identified as a key. - key or null will be output per XPath. - - - - - - - - Output the XPath with keys in path. - - - - - - - - Output the XPath with prefixes instead of modules. - - - - - - - - Output the qualified XPath i.e. /module1:root/module1:node/module2:node/... - - - - - - - - Output an XPath with both module and prefix i.e. /module1:prefix1:root/... - This is NOT a colloquial syntax of XPath. Emitted separately. - - - - - - - - Output deviated nodes in the schema as well. - - - - - - - - Flatten all data keywords instead of only data definition keywords. - - - - - - - keyword - - - - Filter output to only desired keywords. - Keywords specified are what will be displayed in output. - Can be specified more than once. - - - - - - - primitive_type - - - - Filter output to only desired primitive types. - Primitives specified are what will be displayed in output. - Can be specified more than once. - - - - - - - choice - - - - Filter output to flag. - rw for configuration data. - ro for non-configuration data, output parameters to rpcs and actions, and notification parameters. - w for input parameters to rpcs and actions. - u for uses of a grouping. - x for rpcs and actions. - n for notifications. - - - - - - - dialect - - - - CSV dialect for output. - excel | excel-tab | unix - - - - - - - - Ignore error if primitive is missing. - - - - - - - - Output the status statement value. - - - - - - - - Output the XPath of the leafref target. - - - - - - - - UML Output - - The uml output prints an output that can be - used as input-file to plantuml - (http://plantuml.sourceforge.net) in order to - generate a UML diagram. Note that it requires - graphviz - (http://www.graphviz.org/). - - - For large diagrams you may need to increase the Java heap-size - by the -XmxSIZEm option, to java. For example: java - -Xmx1024m -jar plantuml.jar .... - - - Options for the UML output format: - - - - - - - - - Generate UML with classes only, no attributes - - - - - - - - - - - Generate UML output split into pages, NxN, example 2x2. - One .png file per page will be rendered. - - - - - - - - - - - Put the generated .png files(s) in the specified output directory. - Default is "img/" - - - - - - - - - - - Set the title of the generated UML diagram, (default is - YANG module name). - - - - - - - - - - Set the header of the generated UML diagram. - - - - - - - - - - - Set the footer of the generated UML diagram. - - - - - - - - - Use complete YANG schema identifiers for UML class names. - - - - - - - - - - - This option suppresses specified arguments in the - generated UML diagram. Valid arguments are: uses, - leafref, identity, identityref, typedef, annotation, - import, circles, stereotypes. Annotation suppresses YANG - constructs rendered as annotations, examples module info, - config statements for containers. Example - --uml-no=circles,stereotypes,typedef,import - - - - - - - - - - - - Leafref attributes and augment elements can have long - paths making the classes too wide. This option will only - show the tail of the path. Example - --uml-truncate=augment,leafref. - - - - - - - - - Render the diagram with groupings inlined. - - - - - - - - - Render the diagram with augments inlined. - - - - - - - - - - - Maximum of enum items rendered. - - - - - - - - - - - NOT IMPLEMENTED: Only paths in the filter file will be - included in the diagram. A default filter file is generated by - option --filter. - - - - - - - - - YANG Output - - Options for the yang output format: - - - - - - - - Generate all statements in the canonical order. - - - - - - - - Remove unused import statements from the output. - - - - - - - - Remove all comments from the output. - - - - - - len - - - Try to format each line with a maximum line length of - len. Does not reformat long - lines within strings. - - - - - - - - YIN Output - - Options for the yin output format: - - - - - - - Generate all statements in the canonical order. - - - - - - - - Pretty print strings, i.e. print with extra whitespace in - the string. This is not strictly correct, since the - whitespace is significant within the strings in XML, but - the output is more readable. - - - - - - - - YANG Extensions - - This section describes XPath functions that can be used in - "must", "when", or "path" expressions in YANG modules, in - addition to the core XPath 1.0 functions. - - - pyang can be instructed to reject the usage - of these functions with the parameter - --strict. - - - - Function: node-set - deref(node-set) - - - The deref function follows the reference - defined by the first node in document order in the argument - node-set, and returns the nodes it refers to. - - - If the first argument node is an - instance-identifier, the function returns a - node-set that contains the single node that the instance - identifier refers to, if it exists. If no such node exists, - an empty node-set is returned. - - - If the first argument node is a leafref, the - function returns a node-set that contains the nodes that the - leafref refers to. - - - If the first argument node is of any other type, an empty - node-set is returned. - - - The following example shows how a leafref can be written with - and without the deref function: - - - -/* without deref */ - -leaf my-ip { - type leafref { - path "/server/ip"; - } -} -leaf my-port { - type leafref { - path "/server[ip = current()/../my-ip]/port"; - } -} - -/* with deref */ - -leaf my-ip { - type leafref { - path "/server/ip"; - } -} -leaf my-port { - type leafref { - path "deref(../my-ip)/../port"; - } -} - - - - - - Example - - - The following example validates the standard YANG modules with - derived types: - - - - $ pyang ietf-yang-types.yang ietf-inet-types.yang - - - - The following example converts the ietf-yang-types module into - YIN: - - - - $ pyang -f yin -o ietf-yang-types.yin ietf-yang-types.yang - - - - The following example converts the ietf-netconf-monitoring module into - a UML diagram: - - - - - $ pyang -f uml ietf-netconf-monitoring.yang > \ - ietf-netconf-monitoring.uml - $ java -jar plantuml.jar ietf-netconf-monitoring.uml - $ open img/ietf-netconf-monitoring.png - - - - - - Environment Variables - - - pyang searches for referred modules in the colon (:) separated - path defined by the environment variable - $YANG_MODPATH and in the directory - $YANG_INSTALL/yang/modules. - - - - pyang searches for plugins in the colon (:) separated path - defined by the environment variable - $PYANG_PLUGINDIR. - - - - - - - Bugs - - - - - The XPath arguments for the must and - when statements are checked only for - basic syntax errors. - - - - - - - diff --git a/doc/yang2dsdl.1.dbk b/doc/yang2dsdl.1.dbk deleted file mode 100644 index 1090df31..00000000 --- a/doc/yang2dsdl.1.dbk +++ /dev/null @@ -1,517 +0,0 @@ - - - - - - Ladislav Lhotka - CZ.NIC - lhotka@nic.cz - - - %DATE% - - - - yang2dsdl - 1 - pyang manual - yang2dsdl-%PYANG_VERSION% - - - - yang2dsdl - translates YANG data models to DSDL schemas and - validates instance documents. - - - - - yang2dsdl - -t target - -d dir - -b basename - -j - -x - -c - -v instance - - file - - - - yang2dsdl - -L - -t target - -d dir - -b basename - -j - -x - -c - -v instance - - file - - - - yang2dsdl - -s - -t target - -d dir - -b basename - -j - -x - -c - -v instance - - - yang2dsdl - -h - - - - - Description - This shell script facilitates the translation of a data - model described by one or more input YANG modules to DSDL schemas - (RELAX NG, Schematron and DSRL) for a selected instance XML - document type, as described in RFC 6110. Optionally, - the script can validate an instance document of the given type - against the schemas. - The input YANG module(s) may be given either directly as - file parameter(s) on the command line, - or indirectly through a server <hello> message which also - declares capabilities and features supported by the server. The - latter alternative is indicated by the switch, - and only one file parameter may be - given in this case. - Input YANG module(s) may be expressed in YANG or YIN - syntax. The output DSDL schemas are written to the directory - dir (current directory by - default). Unless the option is used, this - directory must be writable. - Metadata annotations are also supported, if they are defined - and used as described in RFC 7952. - - The script can be executed by any shell interpreter - compatible with POSIX.2, such as - bash1 - or - dash1. - - The target argument specifies the - type of the target instance document. Supported values are: - - - data - Datastore contents (configuration and state - data) encapsulated in <nc:data> document - element. - - - config - A configuration datastore contents - encapsulated in <nc:config> document - element. - - - get-reply - A complete NETCONF message - containing a reply to the <nc:get> - operation. - - - get-data-reply - A complete NETCONF message - containing a reply to the <ncds:get-data> - operation. - - - get-config-reply - A complete NETCONF message - containing a reply to the <nc:get-config> - operation. - - - edit-config - A complete NETCONF message - containing an <nc:edit-config> request. Only the RELAX - NG schema is generated for this target. - - - rpc - An RPC request defined in an input YANG - module. - - - rpc-reply - An RPC reply defined in an input YANG - module. - - - notification - An event notification defined in an input - YANG module. - - - - The output schemas are contained in the following four files - whose names depend on the arguments - basename and - target: - - - - basename-target.rng - - RELAX NG schema for the target document - type. - - - - basename-gdefs-config.rng, - basename-gdefs-edit.rng, - basename-gdefs.rng - - Auxiliary RELAX NG schema containing global - named pattern definitions. The first is generated for "config" - and "get-config-reply" targets, the second for "edit-config" - and the third for the remaining targets. - - - - basename-target.sch - - Schematron schema for the target document - type. Not generated for the "edit-config" target. - - - - basename-target.dsrl - - DSRL schema for the target document - type. Not generated for the "edit-config" target. - - - - Optional validation of an XML document stored in the file - instance proceeds as follows: - - - Grammatical and datatype constraints are checked using - the RELAX NG schema. - - - The DSRL schema is used for adding default values - together with ancestor containers to the instance document - where necessary. - - - Semantic constraints are checked using the Schematron - schema. The skeleton implementation of ISO Schematron - by Rick Jelliffe is included in the distribution and used for - this purpose. - - - Steps and are not performed for the "edit-config" - target, or if step reports any errors. - Option may be used together with - for validating an instance document without - generating the schemas. This assumes that the schemas are already - present in the directory selected by the - option (current directory by default). In this case, the basename - of the schemas must be specified using - basename and the input YANG modules - need not be given. Also, if the DSRL or Schematron schema is - missing, the corresponding step is skipped. - The script uses programs from the libxml2 suite - - xmllint(1) for RELAX NG validation and - xsltproc(1) for performing XSLT - transformations. Alternatively, jing(1) can be - used for RELAX NG validation (option ). If - necessary, the script could be easily modified for use with other - RELAX NG validators and/or XSLT1 processors supporting - EXSLT. - - - - Options - - - - basename - - Specifies the basename of files in which the output - schemas are stored. The default is the concatenation of the - names of all input YANG modules connected with the - underscore character "_". This option is mandatory if - is used. - - - - - dir - - Specifies the directory for output files. By default - they are stored in the current directory. - - - - - - Displays help screen and exits. - - - - - - Uses jing(1) for RELAX NG validation - instead of the default xmllint(1). - - - - - - - Interpret the file parameter as - the name of a file containing a server <hello> - message. In this case, exactly one - file parameter must be given. - - - - - - - Performs just validation, without (re)generating the - schemas. This option is only allowed together with - and - basename must also be - specified. - - - - - target - - Specifies the target XML document type using one of - the following strings as explained above: - data (default), - config, - get-reply, - get-data-reply, - get-config-reply, - edit-config, - rpc, rpc-reply - or notification. - - - - - instance - - Validates an instance XML document contained in file - instance. - - - - - - Try to translate modules written in unsupported YANG - versions. If the module doesn't use any constructs - introduced after YANG version 1, this may work. This option - may produce unexpected results. Use at own risk. - - - - - - Use only definitions with status "current" in the YANG - module. - - - - - - - FILES - - - - /usr/local/share/yang/xslt/gen-relaxng.xsl - - - XSLT stylesheet generating RELAX NG schemas. - - - - - /usr/local/share/yang/xslt/gen-schematron.xsl - - - XSLT stylesheet generating Schematron schemas. - - - - - /usr/local/share/yang/xslt/gen-dsrl.xsl - - - XSLT stylesheet generating DSRL schemas. - - - - - /usr/local/share/yang/xslt/gen-common.xsl - - - Common templates for all three XSLT generators. - - - - - /usr/local/share/yang/xslt/dsrl2xslt.xsl - - - Translates a subset of DSRL containing only - specification of default contents to an XSLT - stylesheet. - - - - - /usr/local/share/yang/xslt/svrl2text.xsl - - - Translates an SVRL report to plain text. - - - - - /usr/local/share/yang/schema/relaxng-lib.rng - - - RELAX NG library of common NETCONF elements. - - - - - /usr/local/share/yang/schema/edit-config-attributes.rng - - - RELAX NG definitions of <edit-config> attributes. - - - - - - - ENVIRONMENT VARIABLES - - - PYANG_XSLT_DIR - - Alternative directory for XSLT stylesheets. The - default is installation dependent. - - - - PYANG_RNG_LIBDIR - - Alternative directory for the RELAX NG library. The - default is installation dependent. - - - - XSLT_OPTS - - Options to pass to the XSLT processor when generating - the DSDL schemas. This is mainly useful for debugging. - - - - - - - Examples - - $ yang2dsdl -v dhcp-data.xml dhcp.yang - This command generates the DSDL schemas for the datastore - contents (default data target) as - defined by the dhcp.yang module and validates - an instance document stored in the - dhcp-data.xml file. - - $ yang2dsdl -t rpc rpc-rock.yang - This command generates DSDL schemas for the choice of input - parts (requests) of all RPC operations defined in the module - rpc-rock.yang. - - - - Diagnostics - yang2dsdl return codes have the - following meaning: - - - 0 - No error (normal termination) - - - 1 - Error in input parameters - - - 2 - Error in DSDL schema generation - - - 3 - Instance validation failed - - - - - - Bugs - - - - - The logic of command-line arguments may not be able to - distinguish replies to different RPC requests, for example - if the replies have the same top-level element. - - - - - - - - See Also - - pyang - 1 - , - xsltproc - 1 - , - xmllint - 1 , RFC 6110, - DSDL, RELAX NG, ISO Schematron. - - - - - - From c5d89e3b083052b2612803d97a12963ee0011ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Wed, 1 Nov 2023 10:03:54 +0100 Subject: [PATCH 23/41] added missing markdown files --- doc/json2xml.1.md | 93 ++++ doc/pyang.1.md | 1127 ++++++++++++++++++++++++++++++++++++++++++++ doc/yang2dsdl.1.md | 273 +++++++++++ 3 files changed, 1493 insertions(+) create mode 100644 doc/json2xml.1.md create mode 100644 doc/pyang.1.md create mode 100644 doc/yang2dsdl.1.md diff --git a/doc/json2xml.1.md b/doc/json2xml.1.md new file mode 100644 index 00000000..27a10493 --- /dev/null +++ b/doc/json2xml.1.md @@ -0,0 +1,93 @@ +--- +title: JSON2XML +section: 1 +header: User Manual +footer: json2xml-%VERSION% +date: %DATE% +--- +# NAME + +json2xml - translates JSON documents conforming to a YANG data +model into XML. + +# SYNOPSIS + +**json2xml** [-t target] [-o *output_file*] *driver_file* *json_file* + +**json2xml** -h | -\-help + + +# DESCRIPTION + +This program translates *json_file* into XML using the procedure +specified in **RFC 7951**. + +The translation uses a second input file, *driver_file*, which +contains a concise JSON representation of the YANG data model to which +*json_file* should conform, at least structurally. Normally, +*driver_file* is obtained as the *jtox* output of **pyang**. + +Using \"-\" (hyphen) in place of *json_file* instructs the program to +read a JSON document from the standard input. + +The *target* argument specifies the document (root) element for the +output XML document. This encapsulation is necessary because the input +JSON document may contain multiple JSON objects at the top +level. Supported values for the *target* argument are: + +data +: The document element will be <nc:data>. This is the default. + +config +: The document element will be <nc:data>. + +The XML prefix \"nc\" represents the standard NETCONF namespace with URI +\"urn:ietf:params:xml:ns:netconf:base:1.0\". + +# OPTIONS + +**-t** *target*, **target** *target* +: Specifies the target type of the output XML document, + i.e., its document element. The default is **data**. + +**-o** *output_file*, **-\-output** *output_file* +: Write output to *output_file* instead of the standard output. + +**-h**, **-\-help** +: Displays help screen and exits. + +# EXAMPLES + + $ pyang -f jtox -o dhcp.jtox dhcp.yang + + $ json2xml -o dhcp-data.xml dhcp.jtox dhcp-data.json + +The first command generates the driver file dhcp.jtox, which is then +used for translating JSON file dhcp-data.json to XML file +dhcp-data.xml. + +# DIAGNOSTICS + +**json2xml** return codes have the following meaning: + +0 +: No error (normal termination) + +1 +: One of the input files cannot be read + +2 +: Error in command line arguments + +3 +: JSON to XML translation failed + +# SEE ALSO + +**RFC 7951**, **pyang**(1) + + +# AUTHOR + +**Ladislav Lhotka** <lhotka@nic.cz>\ +CZ.NIC diff --git a/doc/pyang.1.md b/doc/pyang.1.md new file mode 100644 index 00000000..d3188516 --- /dev/null +++ b/doc/pyang.1.md @@ -0,0 +1,1127 @@ +--- +title: PYANG +section: 1 +header: User Manual +footer: pyang-%VERSION% +date: %DATE% +--- +# NAME +pyang - validate and convert YANG modules to various formats + +# SYNOPSIS + +**pyang** [-\-verbose] [-\-canonical] [-\-strict] [-\-lint] [-\-ietf] + [-\-lax-quote-checks] [-\-lax-xpath-checks] [-\-features + *features*] [-\-exclude-features *features*] [-\-max-status + *maxstatus*] [-\-hello] [-\-implicit-hello-deviations] + [-\-check-update-from *oldfile*] + [-o *outfile*] [-t *transform*] [-f *format*] [-p *path*] [-W + *warning*] [-E *error*] *file*... + +**pyang** [-\-sid-list] -\-sid-generate-file {count | + *entry-point:size*} *yang-filename* + +**pyang** [-\-sid-list] -\-sid-update-file *sid-filename* *yang-filename* + [-\-sid-extra-range count *entry-point:size*] + +**pyang** [-\-sid-list] -\-sid-check-file *sid-filename* *yang-filename* + +**pyang** -h | -\-help + +**pyang** -v -\-version + + +One or more *file* parameters may be given on the command line. They +denote either YANG modules to be processed (in YANG or YIN syntax) or, +using the **-\-hello** switch, a server <hello> message +conforming to **RFC 6241** and +**RFC 6020**, +which completely defines the data model - supported YANG modules as +well as features and capabilities. In the latter case, only one *file* +parameter may be present. + +If no files are given, **pyang** reads input +from stdin, which must be one module or a server <hello> message. + +# DESCRIPTION + +The **pyang** program is used to validate YANG modules (**RFC 6020** and +**RFC 7950**). It is also used to convert YANG modules into +equivalent YIN modules. From a valid module a hybrid DSDL +schema (**RFC 6110**) can be generated. + +If no *format* is given, the specified modules are validated, and the +program exits with exit code 0 if all modules are valid. + +# OPTIONS + +**-h**, **-\-help** +: Print a short help text and exit. + +**-v**, **-\-version** +: Print the version number and exit. + +**-e**, **-\-list-errors** +: Print a listing of all error codes and messages pyang might + generate, and then exit. + +**-\-print-error-code** +: On errors, print the symbolic error code instead of the error message. + +**-\-print-error-basename** +: On errors, print only the base file name independent of its module + path location. + +**-Werror** +: Treat warnings as errors. + +**-Wnone** +: Do not print any warnings. + +**-W** _errorcode_ +: Treat _errorcode_ as a warning, even if **-Werror** is given. + _errorcode_ must be a warning or a minor error. + + Use **-\-list-errors** to get a listing of all errors and warnings. + + The following example treats all warnings except the warning for + unused imports as errors: + + $ pyang --Werror -W UNUSED_IMPORT + +**-E** _errorcode_ +: Treat the warning _errorcode_ as an error. + + Use **-\-list-errors** to get a listing of all errors and warnings. + + The following example treats only the warning for unused import as an error: + + $ pyang --Werror -W UNUSED_IMPORT + +**-\-ignore-error** _errorcode_ +: Ignore error _errorcode_. + + Use with care. Plugins that dont expect to be invoked if there are + errors present may crash. + + Use **-\-list-errors** to get a listing of all errors and warnings. + + The following example ignores syntax errors in patterns: + + $ pyang --ignore-error PATTERN_ERROR + +**-\-msg-template** _msg-template_ +: Print out error message in defined _msg-template_. + + Template used to display error messages. This is a python + new-style format string used to format the message information + with keys file, line, code, type, and msg. + + The following example create a msg template in defined pattern: + + $ pyang --msg-template={file} || {line} || {type} || {level} + || {code} || {msg} + +**-\-ignore-errors** +: Ignore all errors. Use with care. Plugins that dont expect to be + invoked if there are errors present may crash. + +**-\-keep-comments** +: This parameter has effect only if a plugin can handle comments. + +**-\-canonical** +: Validate the module(s) according to the canonical YANG order. + +**-\-verify-revision-history** +: Ensure that the revision history in the given module(s) is + correct, by checking that it can find the old revisions of the + module(s) in the YANG module search path. + +**-\-strict** +: Force strict YANG compliance. Currently this checks that the + deref() function is not used in XPath expressions and leafrefs. + +**-\-lint** +: Validate the module(s) according to the generic YANG guideline as + specified in **RFC 8407**. In addition, it checks that the + module is in canonical order. + +**-\-ietf** +: Validate the module(s) like **-\-lint**, and in addition verifies + that the namespace and module name follow the IETF conventions, + and that the module has the correct license text and **RFC + 2119** / **RFC 8174** boilerplate text. + +**-\-lax-quote-checks** +: Lax checks of backslashes in double quoted strings in YANG version + 1 modules. **RFC 6020** does not clearly define how to handle + backslahes within double quoted strings, when the character after + the backslash is not one of the characters listed in Section 6.1.3 + in **RFC 6020**. + + Earlier versions of pyang silently accepted such escape sequences, + but the current version treats this as an error, just like it is + defined in YANG 1.1 **RFC 7950**. Passing this flag to pyang + makes pyang silently accept such escape sequences. + +**-\-lax-xpath-checks** +: Lax checks of XPath expressions. Specifically, do not generate an + error if an XPath expression uses a variable or an unknown + function. + +**-L** **-\-hello** +: Interpret the input file or standard input as a server <hello> + message. In this case, no more than one _file_ parameter may be given. + +**-\-implicit-hello-deviations** +: Attempt to parse all deviations from a supplied <hello> + message. Not all implementations provide deviations explicitly as + modules. This flag enables more logic to attempt to derive all + deviations from the message. + +**-\-trim-yin** +: In YIN input modules, remove leading and trailing whitespace from + every line in the arguments of the following statements: contact, + description, error-message, organization and reference. This way, + the XML-indented argument texts look tidy after translating the + module to the compact YANG syntax. + +**-\-max-line-length** _maxlen_ +: Give a warning if any line is longer than _maxlen_. The value 0 + means no check (default). + +**-\-max-identifier-length** _maxlen_ +: Give a error if any identifier is longer than_maxlen_. + +**-t** **-\-transform** _transform_ +: Transform the module(s) after parsing them but before outputting + them. Multiple transformations can be given, and will be performed + in the order that they were specified. The supported + transformations are listed in TRANSFORMATIONS below. + +**-f** **-\-format** _format_ +: Convert the module(s) into _format_. Some translators require a + single module, and some can translate multiple modules at one + time. If no _outfile_ file is specified, the result is printed on + stdout. The supported formats are listed in OUTPUT FORMATS below. + +**-o** **-\-output** _outfile_ +: Write the output to the file _outfile_ instead of stdout. + +**-F** **-\-features** _features_ +: _features_ is a string of the form + _modulename_:[_feature_(,_feature_)*] + + This option is used to prune the data model by removing all nodes + that are defined with a \"if-feature\" that is not listed as + _feature_. This option affects all output formats. + + This option can be given multiple times, and may also be combined + with **-\-hello**. The **-\-features** option overrides any + supported features for a module that are taken from the hello + file. + + If this option is not given, nothing is pruned, i.e., it works as + if all features were explicitly listed. + + The **-\-exclude-features** option can be used for excluding a list + of named features. **-\-features** and **-\-exclude-features** cant + both be specified for a given module. + + For example, to view the tree output for a module with all + if-featured nodes removed, do: + + $ pyang -f tree --features mymod: mymod.yang + +**-X** **-\-exclude-features** _features_ +: _features_ is a string of the form + _modulename_:[_feature_(,_feature_)*] + + This option is used to prune the data model by removing all nodes + that are defined with a \"if-feature\" that is listed as + _feature_. This option affects all output formats. + + This option can be given multiple times. It cant be combined with + **-\-hello**. + + The **-\-features** option can be used for including all features + or a list of named features. **-\-features** and + **-\-exclude-features** cant both be specified for a given module. + + For example, to view the tree output for a module with if-featured + nodes for the specified feature removed, do: + + $ pyang -f tree --exclude-features mymod:myfeat mymod.yang + +**-\-max-status** _maxstatus_ +: _maxstatus_ is one of:_current_,_deprecated_, or _obsolete_. + + This option is used to prune the data model by removing all nodes + that are defined with a \"status\" that is less than the given + _maxstatus_. This option affects all output formats. + +**-\-deviation-module** _file_ +: This option is used to apply the deviations defined in + _file_. This option affects all output formats. + + This option can be given multiple times. + + For example, to view the tree output for a module with some + deviations applied, do: + + $ pyang -f tree --deviation-module mymod-devs.yang mymod.yang + +**-p** **-\-path** _path_ +: _path_ is a colon (:) separated list of directories to search for + imported modules. This option may be given multiple times. + + By default, all directories (except \".\") found in the path are + recursively scanned for modules. This behavior can be disabled by + giving the option **-\-no-path-recurse**. + + The following directories are always added to the search path: + + 1. current directory + 2. **$YANG\_MODPATH** + 3. **$HOME**/yang/modules + 4. **$YANG\_INSTALL**/yang/modules OR if **$YANG\_INSTALL** is unset + <the default installation directory>/yang/modules + (on Unix systems: /usr/share/yang/modules) + +**-\-no-path-recurse** +: If this parameter is given, directories in the search path are not + recursively scanned for modules. + +**-\-plugindir** _plugindir_ +: Load all YANG plugins found in the directory _plugindir_. This + option may be given multiple times. + + List of directories to search for pyang plugins. The following + directories are always added to the search path: + + 1. pyang/plugins from where pyang is installed + 2. **$PYANG\_PLUGINPATH** + +**-\-check-update-from** _oldfile_ +: Checks that a new revision of a module follows the update rules + given in **RFC 6020** and **RFC 7950**. _oldfile_ is the old + module and _file_ is the new version of the module. + + If the old module imports or includes any modules or submodules, + it is important that the the old versions of these modules and + submodules are found. By default, the directory where _oldfile_ is + found is used as the only directory in the search path for old + modules. Use the option + +**-\-check-update-from-path** +: to control this path. + +**-P** **-\-check-update-from-path** _oldpath_ +: _oldpath_ is a colon (:) separated list of directories to search for + imported modules. This option may be given multiple times. + +**-D** **-\-check-update-from-deviation-module** _olddeviation_ +: _olddeviation_ is an old deviation module of the old module + _oldfile_. This option may be given multiple times. For example, + to check updates of a module with some deviations applied, do: + + $ pyang --check-update-from-deviation-module oldmod-devs.yang \ + --check-update-from oldmod.yang \ + --deviation-module newmod-devs.yang newmod.yang + +_file..._ +: These are the names of the files containing the modules to be + validated, or the module to be converted. + +# TRANSFORMATIONS + +Installed **pyang** transformations are (like output formats) plugins +and therefore may define their own options, or add new transformations +to the **-t** option. These options and transformations are listed in +**pyang -h**. + +*edit* +: Modify the supplied module(s) in various ways. This transform will + usually be used with the *yang* output format. + +# EDIT TRANSFORM + +The *edit* transform modifies the supplied module(s) in various ways. +It can, for example, replace top-level *description* statements, +update *include* statements and manage *revision* statements. Unless +otherwise noted below, it only modifies *existing* statements. + +Each *edit* transform string (non-date) option value is either a plain +string (which is taken literally) or a *+*-separated list of +directives (whose expansions are concatenated with double-linebreak +separators, i.e., each directive results in one or more paragraphs). + +Each directive is either of the form *@filename* (which is replaced +with the contents of the file; there is no search path; trailing +whitespace is discarded) or of the form *%keyword*. Any unrecognized +directives are treated as plain strings. The following *%*-directives +are currently supported: + +- *%SUMMARY* : This expands to a \"summary\" of the original argument + value. It's intended for use with top-level *description* statements + that typically consist of a hand-crafted summary followed by + copyrights, license and other boiler-plate text. The summary is the + text up to but not including the first line that (ignoring leading + and trailing whitespace) starts with the word *Copyright* followed + by a space. + +- *%SUBST/old/new* : This expands to the original argument value with + all instances of *old* replaced with *new*. There is no provision + for replacing characters that contain forward slashes, and there is + no terminating slash. + +- *%DELETE* : This clears the output buffer and suppresses a check + that would normally prevent overwriting an existing value (unless + that value is the literal string **TBD**). + +In the examples given below, it's assumed that there are *CONTACT*, +*CONTEXT*, *LICENSE*, *ORGANIZATION*, *REFERENCE* and *REVISION* files +in a top-level project directory (which in this case is the parent of +the directory in which **pyang** is being run). These examples +illustrate how the *edit* transform might be used with the *yang* +output format to prepare YANG files for publication. + +Edit transform specific options: + +**-\-edit-yang-version** *version* +: Set the YANG version (i.e., the *yang-version* statement's + argument) to *version*. This does nothing if the YANG module + doesn't already have a *yang-version* statement. + + Example: **-\-edit-yang-version 1.1**. + +**-\-edit-namespace** *namespace* +: Set the YANG namespace (i.e., the *namespace* statement's + argument) to *namespace*. This does nothing if the YANG module + doesn't already have a *namespace* statement. + + Example: **-\-edit-namespace %SUBST/acme-pacific-org/apo** + +**-\-edit-update-import-dates** +: Update any *import* (or *include*) *revision-date* statements to + match imported (or included) modules and submodules. If there + isn't already a *revision-date* statement, it will be added. + +**-\-edit-delete-import-dates** +: Delete any *import* (or *include*) *revision-date* statements. + +**-\-edit-organization** *organization* +: Set the organization (i.e., the *organization* statement's + argument) to *organization*. This does nothing if the YANG module + doesn't already have an *organization* statement. + + Example: **-\-edit-organization @../ORGANIZATION** + +**-\-edit-contact** *contact* +: Set the contact info (i.e., the *contact* statement's argument) to + *contact*. This does nothing if the YANG module doesn't already + have a *contact* statement. + + Example: **-\-edit-contact @../CONTACT** + +**-\-edit-description** *description* +: Set the top-level description (i.e., the top-level *description* + statement's argument) to *description*. This does nothing if the + YANG module doesn't already have a *description* statement. + + Example: **-\-edit-description %SUMMARY+@../LICENSE+@../CONTEXT** + +**-\-edit-delete-revisions-after** *prevdate* +: Delete any *revision* statements after (i.e., that are more recent + than) the supplied *yyyy-mm-dd* revision date. A typical use case + is to supply the date of the previous release: any revisions since + then will be internal (e.g., developers often feel that they should + add revision statements for git commits) and are not wanted in the + next released version. + + Example: **-\-edit-delete-revisions-after 2019-03-15** + +**-\-edit-revision-date** *date* +: Set the most recent revision date to the supplied *yyyy-mm-dd* + revision date. This does nothing if the YANG module doesn't + already have at least one *revision* statement. If necessary, a + new *revision* statement will be inserted before any (remaining) + existing revisions. + + Example: **-\-edit-revision-date 2020-03-15** + +**-\-edit-revision-description** *description* +: Set the most recent revision description to *description*. + + Example: **-\-edit-revision-description=%DELETE+@../REVISION** + +**-\-edit-revision-reference** *reference* +: Set the most recent revision reference to *reference*. + + Example: **-\-edit-revision-reference=%DELETE+@../REFERENCE** + +# OUTPUT FORMATS + +Installed **pyang** plugins may define their own options, or add new +formats to the **-f** option. These options and formats are listed in +**pyang -h**. + +*capability* +: Capability URIs for each module of the data model. + +*depend* +: Makefile dependency rule for the module. + +*dsdl* +: Hybrid DSDL schema, see **RFC 6110**. + +*identifiers* +: All identifiers in the module. + +*jsonxsl* +: XSLT stylesheet for transforming XML instance documents to JSON. + +*jstree* +: HTML/JavaScript tree navigator. + +*jtox* +: Driver file for transforming JSON instance documents to XML. + +*name* +: Module name, and the name of the main module for a submodule. + +*omni* +: An applescript file that draws a diagram in **OmniGraffle**. + +*sample-xml-skeleton* +: Skeleton of a sample XML instance document. + +*tree* +: Tree structure of the module. + +*flatten* +: Print the schema nodes in CSV form. + +*uml* +: UML file that can be read by **plantuml** to generate UML diagrams. + +*yang* +: Normal YANG syntax. + +*yin* +: The XML syntax of YANG. + +# LINT CHECKER + +The *lint* option validates that the module follows the generic +conventions and rules given in **RFC 8407**. In +addition, it checks that the module is in canonical order. + +Options for the *lint* checker: + +**-\-lint-namespace-prefix** *prefix* +: Validate that the module's namespace is of the form: + \"<prefix><modulename>\". + +**-\-lint-modulename-prefix** *prefix* +: Validate that the module's name starts with *prefix*. + +**-\-lint-ensure-hyphenated-names** +: Validate that all identifiers use hyphenated style, i.e., + no uppercase letters or underscores. + +# YANG SCHEMA ITEM IDENTIFIERS (SID) + +YANG Schema Item iDentifiers (SID) are globally unique unsigned +integers used to identify YANG items. SIDs are used instead of names +to save space in constrained applications such as COREconf. This +plugin is used to automatically generate and updated .sid files used +to persist and distribute SID assignments. + +Options for generating, updating and checking .sid files: + +**-\-sid-generate-file** +: This option is used to generate a new .sid file from a YANG module. + + Two arguments are required to generate a .sid file; the SID range + assigned to the YANG module and its definition file. The SID range + specified is a sub-range within a range obtained from a registrar + or a sub-range within the experimental range (i.e., 60000 to + 99999). The SID range consists of the first SID of the range, + followed by a colon, followed by the number of SID allocated to + the YANG module. The filename consists of the module name, + followed by an @ symbol, followed by the module revision, followed + by the \".yang\" extension. + + This example shows how to generate the file *toaster@2009-11-20.sid*. + + $ pyang --sid-generate-file 20000:100 toaster@2009-11-20.yang + +**-\-sid-update-file** +: Each time new items are added to a YANG module by the introduction + of a new revision of this module, its included sub-modules or + imported modules, the associated .sid file need to be + updated. This is done by using the **-\-sid-update-file** option. + + Two arguments are required to generate a .sid file for an updated + YANG module; the previous .sid file generated for the YANG module + and the definition file of the updated module. Both filenames + follow the usual naming conversion consisting of the module name, + followed by an @ symbol, followed by the module revision, followed + by the extension. + + This example shows how to generate the file + *toaster@2009-12-28.sid* based on the SIDs already present in + *toaster@2009-11-20.sid*. + + $ pyang --sid-update-file toaster@2009-11-20.sid \ + toaster@2009-12-28.yang + +**-\-sid-check-file** +: The **-\-sid-check-file** option can be used at any time to verify + if a .sid file need to be updated. + + Two arguments are required to verify a .sid file; the filename of + the .sid file to be checked and the corresponding definition file. + + For example: + + $ pyang --sid-check-file toaster@2009-12-28.sid \ + toaster@2009-12-28.yang + +**-\-sid-list** +: The **-\-sid-list** option can be used before any of the previous + options to obtains the list of SIDs assigned or validated. For + example: + + $ pyang --sid-list --sid-generate-file 20000:100 \ + toaster@2009-11-20.yang + +**-\-sid-extra-range** +: If needed, an extra SID range can be assigned to an existing YANG module + during its update with the **-\-sid-extra-range** option. + + For example, this command generates the file + *toaster@2009-12-28.sid* using the initial range(s) present in + *toaster@2009-11-20.sid* and the extra range specified in the + command line. + + $ pyang --sid-update-file toaster@2009-11-20.sid \ + toaster@2009-12-28.yang --sid-extra-range 20100:100 + +*count* +: The number of SID required when generating or updating a .sid file can + be computed by specifying \"*count*\" as SID range. + + For example: + + $ pyang --sid-generate-file count \ + toaster@2009-11-20.yang + + or: + + $ pyang --sid-update-file toaster@2009-11-20.sid \ + toaster@2009-12-28.yang --sid-extra-range count + +# CAPABILITY OUTPUT> + +The *capability* output prints a capability URL for each module of the +input data model, taking into account features and deviations, as +described in section 5.6.4 of **RFC 6020**. + +Options for the *capability* output format: + +**-\-capability-entity** +: Write ampersands in the output as XML entities (\"&amp;\"). + +# DEPEND OUTPUT + +The *depend* output generates a Makefile dependency rule for files +based on a YANG module. This is useful if files are generated from +the module. For example, suppose a .c file is generated from each +YANG module. If the YANG module imports other modules, or includes +submodules, the .c file needs to be regenerated if any of the imported +or included modules change. Such a dependency rule can be generated +like this: + + $ pyang -f depend --depend-target mymod.c \ + --depend-extension .yang mymod.yang + mymod.c : ietf-yang-types.yang my-types.yang + +Options for the *depend* output format: + +**-\-depend-target** +: Makefile rule target. Default is the module name. + +**-\-depend-extension** +: YANG module file name extension. Default is no extension. + +**-\-depend-no-submodules** +: Do not generate dependencies for included submodules. + +**-\-depend-from-submodules** +: Generate dependencies taken from all included submodules. + +**-\-depend-recurse** +: Recurse into imported modules and generate dependencies + for their imported modules etc. + +**-\-depend-include-path** +: Include file path in the prerequisites. Note that if no + **-\-depend-extension** has been given, the prerequisite is the + filename as found, i.e., ending in \".yang\" or \".yin\". + +**-\-depend-ignore-module** +: Name of YANG module or submodule to ignore in the prerequisites. + This option can be given multiple times. + +# DSDL Output + +The *dsdl* output takes a data model consisting of one or more YANG +modules and generates a hybrid DSDL schema as described in **RFC +6110**. The hybrid schema is primarily intended as an interim product +used by **yang2dsdl**(1). + +The *dsdl* plugin also supports +metadata annotations, if they are defined and used as described in +**RFC 7952**. + +Options for the *dsdl* output format: + +**-\-dsdl-no-documentation** +: Do not print Dublin Core metadata terms + +**-\-dsdl-record-defs** +: Record translations of all top-level typedefs and groupings in the + output schema, even if they are not used. This is useful for + translating library modules. + +# JSONXSL OUTPUT + +The *jsonxsl* output generates an XSLT 1.0 stylesheet that can be used +for transforming an XML instance document into JSON text as specified +in **RFC 7951**. The XML document must be a valid instance of the data +model which is specified as one or more input YANG modules on the +command line (or via a <hello> message, see the **-\-hello** +option). + +The *jsonxsl* plugin also converts metadata annotations, if they are +defined and used as described in **RFC 7952**. + +The data tree(s) must be wrapped at least in either <nc:data> or +<nc:config> element, where \"nc\" is the namespace prefix for the +standard NETCONF URI \"urn:ietf:params:xml:ns:netconf:base:1.0\", or the +XML instance document has to be a complete NETCONF RPC request/reply +or notification. Translation of RPCs and notifications defined by the +data model is also supported. + +The generated stylesheet accepts the following parameters that modify +its behaviour: + +- *compact*: setting this parameter to 1 results in a compact + representation of the JSON text, i.e., without any whitespace. The + default is 0 which means that the JSON output is pretty-printed. + +- *ind-step*: indentation step, i.e., the number of spaces to use for + each level. The default value is 2 spaces. Note that this setting is + only useful for pretty-printed output (compact=0). + +The stylesheet also includes the file *jsonxsl-templates.xsl* which is +a part of **pyang** distribution. + +# JSTREE OUTPUT + +The *jstree* output grenerates an HTML/JavaScript page that presents a +tree-navigator to the given YANG module(s). + +jstree output specific option: + +**-\-jstree-no-path** +: Do not include paths in the output. This option makes the page + less wide. + +# JTOX OUTPUT + +The *jtox* output generates a driver file which can be used as one of +the inputs to **json2xml** for transforming a JSON document to XML as +specified in **RFC 7951**. + +The *jtox* output itself is a JSON document containing a concise +representation of the data model which is specified as one or more +input YANG modules on the command line (or via a <hello> +message, see the **-\-hello** option). + +See **json2xml** manual page for more information. + +# OMNI OUTPUT + +The plugin generates an applescript file that draws a diagram in +OmniGraffle. Requires OmniGraffle 6. Usage: + + $ pyang -f omni foo.yang -o foo.scpt + $ osascript foo.scpt + +omni output specific option: + +**-\-omni-path** *path* +: Subtree to print. The *path* is a slash (\"/\") separated path to + a subtree to print. For example \"/nacm/groups\". + +# NAME OUTPUT + +The *name* output prints the name of each module in the input data +model. For submodules, it also shows the name of the main module to +which the submodule belongs. + +name output specific option: + +**-\-name-print-revision** +: Print the name and revision in name@revision format. + +# SAMPLE-XML-SKELETON OUTPUT + +The *sample-xml-skeleton* output generates an XML instance document +with sample elements for all nodes in the data model, according to the +following rules: + +- An element is present for every leaf, container or anyxml. + +- At least one element is present for every leaf-list or + list. The number of entries in the sample is min(1, + +- For a choice node, sample element(s) are present for + each case. + +- Leaf, leaf-list and anyxml elements are empty (but see + the **-\-sample-xml-skeleton-defaults** option + below). + +Note that the output document will most likely be invalid and needs +manual editing. + +Options specific to the *sample-xml-skeleton* output format: + +**-\-sample-xml-skeleton-annotations** +: Add XML comments to the sample documents with hints about expected + contents, for example types of leaf nodes, permitted number of + list entries etc. + +**-\-sample-xml-skeleton-defaults** +: Add leaf elements with defined defaults to the output with their + default value. Without this option, the default elements are + omitted. + +**-\-sample-xml-skeleton-doctype=**_type_ +: Type of the sample XML document. Supported values for *type* are + **data** (default) and **config**. This option determines the document + element of the output XML document (<data> or <config> + in the NETCONF namespace) and also affects the contents: for + **config**, only data nodes representing configuration are included. + +**-\-sample-xml-skeleton-path=**_path_ +: Subtree of the sample XML document to generate, including all + ancestor elements. The *path* is a slash (\"/\") separated list of + data node names that specifies the path to a subtree to print. For + example \"/nacm/rule-list/rule/rpc-name\". + +# TREE OUTPUT + +The *tree* output prints the resulting schema tree from one or more +modules. Use **pyang -\-tree-help** to print a description on the +symbols used by this format. + +Tree output specific options: + +**-\-tree-help** +: Print help on symbols used in the tree output and exit. + +**-\-tree-depth** *depth* +: Levels of the tree to print. + +**-\-tree-path** *path* +: Subtree to print. The *path* is a slash (\"/\") separated path to a + subtree to print. For example \"/nacm/groups\". All ancestors and + the selected subtree are printed. + +**-\-tree-print-groupings** +: Print the top-level groupings defined in the module. + +**-\-tree-print-structures** +: Print the ietf-yang-structure-ext:structure structures defined in + the module. + +**-\-tree-print-yang-data** +: Print the ietf-restconf:yang-data structures defined in the + module. + +**-\-tree-line-length** *maxlen* +: Try to break lines so they are no longer than *maxlen*. This is + a best effort algorithm. + +**-\-tree-module-name-prefix** *maxlen* +: Use the module name (instead of the prefix) to prefix + parameters and types. + +# FLATTEN OUTPUT + +The *flatten* output flattens provided +YANG module and outputs the schema nodes and some of their +properties in CSV format. + +Flatten output specific options: + +**-\-flatten-no-header** +: Do not emit the CSV header. + +**-\-flatten-keyword** +: Output the keyword. + This will resolve as container, leaf, etc. + +**-\-flatten-type** +: Output the top-level type. + This will resolve to a module-prefixed type. + +**-\-flatten-primitive-type** +: Output the primitive type. + This resolves to a YANG type such as uint64. + +**-\-flatten-flag** +: Output flag property. + Derives a flag - for instance rw/ro for config, or x for RPC. + +**-\-flatten-description** +: Output the description. + +**-\-flatten-keys** +: Output whether the XPath is identified as a key. + *key* or null will be output per XPath. + +**-\-flatten-keys-in-xpath** +: Output the XPath with keys in path. + +**-\-flatten-prefix-in-xpath** +: Output the XPath with prefixes instead of modules. + +**-\-flatten-qualified-in-xpath** +: Output the qualified XPath i.e., /module1:root/module1:node/module2:node/... + +**-\-flatten-qualified-module-and-prefix-path** +: Output an XPath with both module and prefix i.e., /module1:prefix1:root/... + This is NOT a colloquial syntax of XPath. Emitted separately. + +**-\-flatten-deviated** +: Flatten all data keywords instead of only data definition keywords. + +**-\-flatten-filter-keyword** *keyword* +: Filter output to only desired keywords. Keywords specified are + what will be displayed in output. Can be specified more than + once. + +**-\-flatten-filter-primitive** *primitive_type* +: Filter output to only desired primitive types. Primitives + specified are what will be displayed in output. Can be specified + more than once. + +**-\-flatten-filter-flag** *choice* +: Filter output to flag. + + - *rw* for configuration data. + + - *ro* for non-configuration data, output parameters to rpcs and + actions, and notification parameters. + + - *w* for input parameters to rpcs and actions. + + - *u* for uses of a grouping. + + - *x* for rpcs and actions. + + - *n* for notifications. + +**-\-flatten-csv-dialect** *dialect* +: CSV dialect for output. + *dialect* is one of **excel**, **excel-tab**, or **unix**. + +**-\-flatten-ignore-no-primitive** +: Ignore error if primitive is missing. + +**-\-flatten-status** +: Output the status statement value. + +**-\-flatten-resolve-leafref** +: Output the XPath of the leafref target. + +# UML OUTPUT + +The *uml* output prints an output that can be used as input-file to +**plantuml** (http://plantuml.sourceforge.net) in order to +generate a UML diagram. Note that it requires **graphviz** +(http://www.graphviz.org/). + +For large diagrams you may need to increase the Java heap-size +by the -XmxSIZEm option, to java. For example: **java + -Xmx1024m -jar plantuml.jar ....** + +Options for the *UML* output format: + +**-\-uml-classes-only** +: Generate UML with classes only, no attributes + +**-\-uml-split-pages=**_layout_ +: Generate UML output split into pages, NxN, example 2x2. + One .png file per page will be rendered. + +**-\-uml-output-directory=**_directory_ +: Put the generated .png files(s) in the specified output directory. + Default is \"img/\" + +**-\-uml-title=**_title_ +: Set the title of the generated UML diagram, (default is + YANG module name). + +**-\-uml-header=**_header_ +: Set the header of the generated UML diagram. + +**-\-uml-footer=**_footer_ +: Set the footer of the generated UML diagram. + +**-\-uml-long-identifers** +: Use complete YANG schema identifiers for UML class names. + +**-\-uml-no=**_arglist_ +: Render the diagram with groupings inlined. + +**-\-uml-inline-augments** +: Render the diagram with augments inlined. + +**-\-uml-max-enums=*number*** +: Maximum of enum items rendered. + +**-\-uml-filter-file=*file*** +: NOT IMPLEMENTED: Only paths in the filter file will be included in + the diagram. A default filter file is generated by option + -\-filter. + +# YANG OUTPUT + +Options for the *yang* output format: + +**-\-yang-canonical** +: Generate all statements in the canonical order. + +**-\-yang-remove-unused-imports** +: Remove unused import statements from the output. + +**-\-yang-remove-comments** +: Remove all comments from the output. + +**-\-yang-line-length** *len* +: Try to format each line with a maximum line length of *len*. Does + not reformat long lines within strings. + +# YIN OUTPUT + +Options for the *yin* output format: + +**-\-yin-canonical** +: Generate all statements in the canonical order. + +**-\-yin-pretty-strings** +: Pretty print strings, i.e., print with extra whitespace in the + string. This is not strictly correct, since the whitespace is + significant within the strings in XML, but the output is more + readable. + +# YANG XPATH EXTENSIONS + +This section describes XPath functions that can be used in +\"must\", \"when\", or \"path\" expressions in YANG modules, in +addition to the core XPath 1.0 functions. + +**pyang** can be instructed to reject the usage +of these functions with the parameter +**-\-strict**. + +**Function:** *node-set* **deref**(*node-set*) +: The **deref** function follows the reference + defined by the first node in document order in the argument + node-set, and returns the nodes it refers to. + + If the first argument node is an **instance-identifier**, + the function returns a node-set that contains the single node that + the instance identifier refers to, if it exists. If no such node + exists, an empty node-set is returned. + + If the first argument node is a **leafref**, the function + returns a node-set that contains the nodes that the leafref refers + to. + + If the first argument node is of any other type, an empty node-set + is returned. + + The following example shows how a leafref can be written with + and without the **deref** function: + + /* without deref */ + + leaf my-ip { + type leafref { + path "/server/ip"; + } + } + leaf my-port { + type leafref { + path "/server[ip = current()/../my-ip]/port"; + } + } + + /* with deref */ + + leaf my-ip { + type leafref { + path "/server/ip"; + } + } + leaf my-port { + type leafref { + path "deref(../my-ip)/../port"; + } + } + +# EXAMPLES + +The following example validates the standard YANG modules with +derived types: + + $ pyang ietf-yang-types.yang ietf-inet-types.yang + +The following example converts the ietf-yang-types module into YIN: + + $ pyang -f yin -o ietf-yang-types.yin ietf-yang-types.yang + +The following example converts the ietf-netconf-monitoring module into +a UML diagram: + + $ pyang -f uml ietf-netconf-monitoring.yang > \ + ietf-netconf-monitoring.uml + $ java -jar plantuml.jar ietf-netconf-monitoring.uml + $ open img/ietf-netconf-monitoring.png + +# ENVIRONMENT VARIABLES + +**pyang** searches for referred modules in the colon (:) separated +path defined by the environment variable **\$YANG_MODPATH** and in the +directory **\$YANG_INSTALL**/yang/modules. + +**pyang** searches for plugins in the colon (:) separated path +defined by the environment variable +**\$PYANG_PLUGINDIR**. + +# BUGS + +The XPath arguments for the *must* and *when* statements are checked +only for basic syntax errors. + +# AUTHORS + +See the file CONTRIBUTORS at https://github.com/mbj4668/pyang. diff --git a/doc/yang2dsdl.1.md b/doc/yang2dsdl.1.md new file mode 100644 index 00000000..d9bc5320 --- /dev/null +++ b/doc/yang2dsdl.1.md @@ -0,0 +1,273 @@ +--- +title: YANG2DSDL +section: 1 +header: User Manual +footer: yang2dsdl-%VERSION% +date: %DATE% +--- +# NAME + +yang2dsdl - translates YANG data models to DSDL schemas and validates +instance documents. + +# SYNOPSIS + +**yang2dsdl** [-t *target*] [-d *dir*] [-b *basename*] [-j] [-x] [-c] +[-v *instance*] *file*... + +**yang2dsdl** -L [-t *target*] [-d *dir*] [-b *basename*] [-j] [-x] + [-c] [-v *instance*] *file*... + +**yang2dsdl** -s [-t *target*] [-d *dir*] [-b *basename*] [-j] [-x] [-c] +[-v *instance*] + +**yang2dsdl** -h + +# DESCRIPTION + +This shell script facilitates the translation of a data model +described by one or more input YANG modules to DSDL schemas (RELAX NG, +Schematron and DSRL) for a selected instance XML document type, as +described in **RFC 6110**. Optionally, +the script can validate an instance document of the given type against +the schemas. + +The input YANG module(s) may be given either directly as *file* +parameter(s) on the command line, or indirectly through a server +<hello> message which also declares capabilities and features +supported by the server. The latter alternative is indicated by the +**-L** switch, and only one *file* parameter may be given in this +case. + +Input YANG module(s) may be expressed in YANG or YIN syntax. The +output DSDL schemas are written to the directory *dir* (current +directory by default). Unless the option **-s** is used, this +directory must be writable. + +Metadata annotations are also supported, if they are defined and used +as described in **RFC 7952**. + + +The script can be executed by any shell interpreter compatible with +POSIX.2, such as **bash**(1) or **dash**(1). + +The *target* argument specifies the type of the target instance +document. Supported values are: + +data +: Datastore contents (configuration and state + data) encapsulated in <nc:data> document + element. + +config +: A configuration datastore contents encapsulated in + <nc:config> document element. + +get-reply +: A complete NETCONF message containing a reply to the + <nc:get> operation. + +get-data-reply +: A complete NETCONF message containing a reply to the + <ncds:get-data> operation. + +get-config-reply +: A complete NETCONF message containing a reply to the + <nc:get-config> operation. + +edit-config +: A complete NETCONF message containing an <nc:edit-config> + request. Only the RELAX NG schema is generated for this target. + +rpc +: An RPC request defined in an input YANG module. + +rpc-reply +: An RPC reply defined in an input YANG module. + +notification +: An event notification defined in an input YANG module. + + +The output schemas are contained in the following four files whose +names depend on the arguments *basename* and *target*: + +*basename*-*target*.rng +: RELAX NG schema for the target document type. + +*basename*-gdefs-config.rng, *basename*-gdefs-edit.rng, *basename*-gdefs.rng +: Auxiliary RELAX NG schema containing global named pattern + definitions. The first is generated for "config" and + "get-config-reply" targets, the second for "edit-config" and the + third for the remaining targets. + +*basename*-*target*.sch +: Schematron schema for the target document type. Not generated for + the "edit-config" target. + +*basename*-*target*.dsrl +: DSRL schema for the target document type. Not generated for the + "edit-config" target. + +Optional validation of an XML document stored in the file +*instance* proceeds as follows: + +1. Grammatical and datatype constraints are checked using the RELAX NG + schema. + +2. The DSRL schema is used for adding default values together with + ancestor containers to the instance document where necessary. + +3. Semantic constraints are checked using the Schematron schema. The + skeleton implementation of **ISO Schematron** by Rick Jelliffe is + included in the distribution and used for this purpose. + +Steps 3 and 3 are not performed for the "edit-config" target, or if +step 1 reports any errors. + +Option **-s** may be used together with **-v** for validating an +instance document without generating the schemas. This assumes that +the schemas are already present in the directory selected by the +**-d** option (current directory by default). In this case, the +basename of the schemas must be specified using **-b** *basename* and +the input YANG modules need not be given. Also, if the DSRL or +Schematron schema is missing, the corresponding step is skipped. + +The script uses programs from the libxml2 suite - **xmllint**(1) for +RELAX NG validation and **xsltproc**(1) for performing XSLT +transformations. Alternatively, **jing**(1) can be used for RELAX NG +validation (option **-j**). If necessary, the script could be easily +modified for use with other RELAX NG validators and/or XSLT1 +processors supporting EXSLT. + +# OPTIONS + +**-b** *basename* +: Specifies the basename of files in which the output schemas are + stored. The default is the concatenation of the names of all input + YANG modules connected with the underscore character "_". This + option is mandatory if **-s** is used. + +**-d** *dir* +: Specifies the directory for output files. By default they are + stored in the current directory. + +**-h** +: Displays help screen and exits. + +**-j** +: Uses **jing**(1) for RELAX NG validation + instead of the default **xmllint**(1). + +**-L** +: Interpret the *file* parameter as the name of a file containing a + server <hello> message. In this case, exactly one *file* + parameter must be given. + +**-s** +: Performs just validation, without (re)generating the schemas. This + option is only allowed together with **-v** and **-b** *basename* + must also be specified. + +**-t** *target* +: Specifies the target XML document type using one of the following + strings as explained above: **data** (default), **config**, + **get-reply**, **get-data-reply**, **get-config-reply**, + **edit-config**, **rpc**, **rpc-reply** or **notification**. + +**-v** *instance* +: Validates an instance XML document contained in file *instance*. + +**-x** +: Try to translate modules written in unsupported YANG versions. If + the module doesn't use any constructs introduced after YANG + version 1, this may work. This option may produce unexpected + results. Use at own risk. + +**-c** +: Use only definitions with status "current" in the YANG module. + +# FILES + +/usr/local/share/yang/xslt/gen-relaxng.xsl +: XSLT stylesheet generating RELAX NG schemas. + +/usr/local/share/yang/xslt/gen-schematron.xsl +: XSLT stylesheet generating DSRL schemas. + +/usr/local/share/yang/xslt/gen-common.xsl +: Common templates for all three XSLT generators. + +/usr/local/share/yang/xslt/dsrl2xslt.xsl +: Translates a subset of DSRL containing only specification of + default contents to an XSLT stylesheet. + +/usr/local/share/yang/xslt/svrl2text.xsl +: Translates an SVRL report to plain text. + +/usr/local/share/yang/schema/relaxng-lib.rng +: RELAX NG library of common NETCONF elements. + +/usr/local/share/yang/schema/edit-config-attributes.rng +: RELAX NG definitions of <edit-config> attributes. + +# ENVIRONMENT VARIABLES + +**PYANG_XSLT_DIR** +: Alternative directory for XSLT stylesheets. The default is + installation dependent. + +**PYANG_RNG_LIBDIR** +: Alternative directory for the RELAX NG library. The default is + installation dependent. + +**XSLT_OPTS** +: Options to pass to the XSLT processor when generating the DSDL + schemas. This is mainly useful for debugging. + +# EXAMPLES + + $ yang2dsdl -v dhcp-data.xml dhcp.yang + +This command generates the DSDL schemas for the datastore contents +(default *data* target) as defined by dhcp.yang module and validates +an instance document stored in the dhcp-data.xml file. + + $ yang2dsdl -t rpc rpc-rock.yang + +This command generates DSDL schemas for the choice of input +parts (requests) of all RPC operations defined in the module +rpc-rock.yang. + +# DIAGNOSTICS + +**yang2dsdl** return codes have the following meaning: + +0 +: No error (normal termination) + +1 +: Error in input parameters + +2 +: Error in DSDL schema generation + +3 +: Instance validation failed + + +# BUGS + +1. The logic of command-line arguments may not be able to distinguish + replies to different RPC requests, for example if the replies have + the same top-level element. + +# SEE ALSO + +**pyang**(1), **xsltproc**(1), **xmllint**(1), **RFC 61110**. + + +# AUTHOR + +**Ladislav Lhotka** <lhotka@nic.cz>\ +CZ.NIC From 1b1c3e0d312d148e57f9e6bfa3a9bc0712aa5893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Wed, 1 Nov 2023 10:06:34 +0100 Subject: [PATCH 24/41] fixed markdown --- doc/Makefile | 4 ++-- doc/json2xml.1.md | 4 ++-- doc/pyang.1.md | 4 ++-- doc/yang2dsdl.1.md | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 089fd005..3ab418c8 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -13,6 +13,6 @@ clean: ../man/man1/%.1: %.1.md cat $< | \ - sed -e 's/%VERSION%/$(VERSION)/g' \ - -e 's/%DATE%/$(DATE)/g' | \ + sed -e 's/_VERSION_/$(VERSION)/g' \ + -e 's/_DATE_/$(DATE)/g' | \ pandoc - -s -t man -o $@ diff --git a/doc/json2xml.1.md b/doc/json2xml.1.md index 27a10493..1f06b6bc 100644 --- a/doc/json2xml.1.md +++ b/doc/json2xml.1.md @@ -2,8 +2,8 @@ title: JSON2XML section: 1 header: User Manual -footer: json2xml-%VERSION% -date: %DATE% +footer: json2xml-_VERSION_ +date: _DATE_ --- # NAME diff --git a/doc/pyang.1.md b/doc/pyang.1.md index d3188516..e0fa484b 100644 --- a/doc/pyang.1.md +++ b/doc/pyang.1.md @@ -2,8 +2,8 @@ title: PYANG section: 1 header: User Manual -footer: pyang-%VERSION% -date: %DATE% +footer: pyang-_VERSION_ +date: _DATE_ --- # NAME pyang - validate and convert YANG modules to various formats diff --git a/doc/yang2dsdl.1.md b/doc/yang2dsdl.1.md index d9bc5320..997c231f 100644 --- a/doc/yang2dsdl.1.md +++ b/doc/yang2dsdl.1.md @@ -2,8 +2,8 @@ title: YANG2DSDL section: 1 header: User Manual -footer: yang2dsdl-%VERSION% -date: %DATE% +footer: yang2dsdl-_VERSION_ +date: _DATE_ --- # NAME From 4ba83e71e6dbb1a6046ae55af3c283e60b48af77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Wed, 1 Nov 2023 10:03:14 +0100 Subject: [PATCH 25/41] Fixes #650 - bad expansion of multiple related augments --- pyang/statements.py | 41 ++++++++++++------ test/test_issues/test_i650/Makefile | 4 ++ test/test_issues/test_i650/a.yang | 64 +++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 test/test_issues/test_i650/Makefile create mode 100644 test/test_issues/test_i650/a.yang diff --git a/pyang/statements.py b/pyang/statements.py index 44cfa9c0..80249eaa 100644 --- a/pyang/statements.py +++ b/pyang/statements.py @@ -155,6 +155,7 @@ class Abort(Exception): # second expansion: expand augmentations into i_children 'expand_2', + 'expand_3', # unique name check phase: 'unique_name', @@ -216,6 +217,7 @@ class Abort(Exception): lambda ctx, s: v_inherit_properties(ctx, s), ('expand_2', 'augment'):lambda ctx, s: v_expand_2_augment(ctx, s), + ('expand_3', 'augment'):lambda ctx, s: v_expand_3_augment(ctx, s), ('unique_name', 'module'): \ lambda ctx, s: v_unique_name_defintions(ctx, s), @@ -252,10 +254,11 @@ class Abort(Exception): _v_i_children = { 'unique_name':True, 'expand_2':True, + 'expand_3':True, 'reference_1':True, 'reference_2':True, } -"""Phases in this dict are run over the stmts which has i_children. +"""Phases in this dict are run over the stmts that have i_children. Note that the tests are not run in grouping definitions.""" _v_i_children_keywords = { @@ -1464,6 +1467,8 @@ def v_expand_1_children(ctx, stmt): v_inherit_properties(ctx, stmt) for a in s.search('augment'): v_expand_2_augment(ctx, a) + for a in s.search('augment'): + v_expand_3_augment(ctx, a) elif s.keyword in data_keywords and hasattr(stmt, 'i_children'): stmt.i_children.append(s) @@ -1726,18 +1731,19 @@ def walk(s, config_value, allow_explicit): def v_expand_2_augment(ctx, stmt): """ - One-pass augment expansion algorithm: First observation: since we - validate each imported module, all nodes that are augmented by - other modules already exist. For each node in the path to the - target node, if it does not exist, it might get created by an - augment later in this module. This only applies to nodes defined - in our namespace (since all other modules already are validated). - For each such node, we add a temporary Statement instance, and - store a pointer to it. If we find such a temporary node in the - nodes we add, we replace it with our real node, and delete it from - the list of temporary nodes created. When we're done with all - augment statements, the list of temporary nodes should be empty, - otherwise it is an error. + First pass of two-pass augment expansion algorithm. + + First observation: since we validate each imported module, all + nodes that are augmented by other modules already exist. For each + node in the path to the target node, if it does not exist, it + might get created by an augment later in this module. This only + applies to nodes defined in our namespace (since all other modules + already are validated). For each such node, we add a temporary + Statement instance, and store a pointer to it. If we find such a + temporary node in the nodes we add, we replace it with our real + node, and delete it from the list of temporary nodes created. + When we're done with all augment statements, the list of temporary + nodes should be empty, otherwise it is an error. """ if hasattr(stmt, 'i_target_node'): # already expanded @@ -1868,6 +1874,15 @@ def is_expected_keyword(parent, child): stmt.i_target_node.substmts.append(s) s.parent = stmt.i_target_node +def v_expand_3_augment(ctx, stmt): + """ + Second pass of two-pass augment expansion algorithm. + + Find the (possibly expanded) target nodes again. The reason for + this is that stmt.i_target_node may point to a __tmp_augment__ node. + """ + stmt.i_target_node = find_target_node(ctx, stmt, is_augment=True) + def create_new_case(ctx, choice, child, expand=True): new_case = new_statement(child.top, choice, child.pos, 'case', child.arg) v_init_stmt(ctx, new_case) diff --git a/test/test_issues/test_i650/Makefile b/test/test_issues/test_i650/Makefile new file mode 100644 index 00000000..6ff2b0a2 --- /dev/null +++ b/test/test_issues/test_i650/Makefile @@ -0,0 +1,4 @@ +test: test1 + +test1: + $(PYANG) -Werror a.yang diff --git a/test/test_issues/test_i650/a.yang b/test/test_issues/test_i650/a.yang new file mode 100644 index 00000000..e8c1ac51 --- /dev/null +++ b/test/test_issues/test_i650/a.yang @@ -0,0 +1,64 @@ +module a { + yang-version 1.1; + namespace "urn:a"; + + prefix ex; + + container interfaces { + + list interface { + key "name"; + + leaf name { + type string; + } + + leaf type { + type string; + mandatory true; + } + + } + + } + + + augment '/ex:interfaces/ex:interface/ex:frame-processing/ex:inline-frame-processingx/ex:inline-frame-processing/ex:ingress-rule/ex:rule/ex:flexible-match' { + + when + "../../../../ex:type = 'value'"; + + } + + augment '/ex:interfaces/ex:interface' { + + choice frame-processing { + + case inline-frame-processingx { + + container inline-frame-processing { + + container ingress-rule { + + list rule { + key "name"; + + leaf name { + type string; + } + + container flexible-match { + } + } + } + } + } + } + } + + + + + + +} From dc9755382194d59484f439b557b6110b138a3bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Fri, 3 Nov 2023 09:59:05 +0100 Subject: [PATCH 26/41] Fixes #729, see #193, #836 - handle 1.1 scoping rules in XPath evaluations --- pyang/statements.py | 11 ++++- pyang/util.py | 19 +++++---- test/test_issues/test_i193/Makefile | 14 +++++++ test/test_issues/test_i193/x-base.yang | 7 ++++ test/test_issues/test_i193/x-base2.yang | 10 +++++ test/test_issues/test_i193/x-profiles.yang | 14 +++++++ test/test_issues/test_i193/y-base.yang | 7 ++++ test/test_issues/test_i193/y-base2.yang | 10 +++++ test/test_issues/test_i193/y-profiles.yang | 16 +++++++ test/test_issues/test_i193/y1-base.yang | 6 +++ test/test_issues/test_i193/y1-base2.yang | 9 ++++ test/test_issues/test_i193/y1-profiles.yang | 15 +++++++ test/test_issues/test_i193/z-base.yang | 7 ++++ test/test_issues/test_i193/z-base2.yang | 13 ++++++ test/test_issues/test_i193/z-profiles.yang | 16 +++++++ test/test_issues/test_i729/Makefile | 14 +++++++ test/test_issues/test_i729/v1.1/bgp.yang | 27 ++++++++++++ .../test_i729/v1.1/native-sub.yang | 42 +++++++++++++++++++ test/test_issues/test_i729/v1.1/native.yang | 19 +++++++++ test/test_issues/test_i729/v1/bgp.yang | 26 ++++++++++++ test/test_issues/test_i729/v1/native-sub.yang | 41 ++++++++++++++++++ test/test_issues/test_i729/v1/native.yang | 18 ++++++++ 22 files changed, 351 insertions(+), 10 deletions(-) create mode 100644 test/test_issues/test_i193/Makefile create mode 100644 test/test_issues/test_i193/x-base.yang create mode 100644 test/test_issues/test_i193/x-base2.yang create mode 100644 test/test_issues/test_i193/x-profiles.yang create mode 100644 test/test_issues/test_i193/y-base.yang create mode 100644 test/test_issues/test_i193/y-base2.yang create mode 100644 test/test_issues/test_i193/y-profiles.yang create mode 100644 test/test_issues/test_i193/y1-base.yang create mode 100644 test/test_issues/test_i193/y1-base2.yang create mode 100644 test/test_issues/test_i193/y1-profiles.yang create mode 100644 test/test_issues/test_i193/z-base.yang create mode 100644 test/test_issues/test_i193/z-base2.yang create mode 100644 test/test_issues/test_i193/z-profiles.yang create mode 100644 test/test_issues/test_i729/Makefile create mode 100644 test/test_issues/test_i729/v1.1/bgp.yang create mode 100644 test/test_issues/test_i729/v1.1/native-sub.yang create mode 100644 test/test_issues/test_i729/v1.1/native.yang create mode 100644 test/test_issues/test_i729/v1/bgp.yang create mode 100644 test/test_issues/test_i729/v1/native-sub.yang create mode 100644 test/test_issues/test_i729/v1/native.yang diff --git a/pyang/statements.py b/pyang/statements.py index 80249eaa..4852e1d2 100644 --- a/pyang/statements.py +++ b/pyang/statements.py @@ -438,13 +438,18 @@ def v_init_module(ctx, stmt): if stmt.keyword == 'module': prefix = stmt.search_one('prefix') stmt.i_modulename = stmt.arg + mod = stmt else: belongs_to = stmt.search_one('belongs-to') if belongs_to is not None and belongs_to.arg is not None: prefix = belongs_to.search_one('prefix') stmt.i_modulename = belongs_to.arg + mod = ctx.get_module(stmt.i_modulename) + if mod is None: + mod = stmt else: stmt.i_modulename = "" + mod = None if prefix is not None and prefix.arg is not None: stmt.i_prefixes[prefix.arg] = (stmt.arg, None) @@ -484,11 +489,14 @@ def v_init_module(ctx, stmt): stmt.i_undefined_augment_nodes = {} # next, set the attribute 'i_module' in each statement to point to the # module where the statement is defined. if the module is a submodule, - # 'i_module' will point to the main module. + # 'i_main_module' will point to the main module, except if a submodule is + # validated stand-alone (then in points to the submodule) # 'i_orig_module' will point to the real module / submodule. + # 'i_module' will point to the main module. def set_i_module(s): s.i_orig_module = s.top s.i_module = s.top + s.i_main_module = mod return iterate_stmt(stmt, set_i_module) @@ -2972,6 +2980,7 @@ class Statement(object): 'i_config', # True or False 'i_module', 'i_orig_module', + 'i_main_module', 'i_not_implemented', # if set (True) this statement is not implemented, # either a false if-feature or status diff --git a/pyang/util.py b/pyang/util.py index b7542b9e..8143405d 100644 --- a/pyang/util.py +++ b/pyang/util.py @@ -69,11 +69,12 @@ def get_latest_revision(module): return max(revisions) if revisions else 'unknown' +# module is the (sub)module where the statement is defined def prefix_to_modulename_and_revision(module, prefix, pos, errors): - if prefix == '': - return module.arg, None - if prefix == module.i_prefix: - return module.arg, None + if prefix == '' or prefix == module.i_prefix: + if module.i_version == '1': + return module.arg, None + return module.i_main_module.arg, None try: (modulename, revision) = module.i_prefixes[prefix] except KeyError: @@ -86,12 +87,12 @@ def prefix_to_modulename_and_revision(module, prefix, pos, errors): del module.i_unused_prefixes[prefix] return modulename, revision - +# module is the (sub)module where the statement is defined def prefix_to_module(module, prefix, pos, errors): - if prefix == '': - return module - if prefix == module.i_prefix: - return module + if prefix == '' or prefix == module.i_prefix: + if module.i_version == '1': + return module + return module.i_main_module modulename, revision = \ prefix_to_modulename_and_revision(module, prefix, pos, errors) if modulename is None: diff --git a/test/test_issues/test_i193/Makefile b/test/test_issues/test_i193/Makefile new file mode 100644 index 00000000..28be3390 --- /dev/null +++ b/test/test_issues/test_i193/Makefile @@ -0,0 +1,14 @@ +test: test1 test2 test3 test4 + +test1: + $(PYANG) -Werror x-base.yang + +test2: + $(PYANG) -Werror y-base.yang + +test3: + $(PYANG) -Werror z-base.yang + +test4: + $(PYANG) -Werror --print-error-code y1-base.yang 2>&1 \ + | grep XPATH_NODE_NOT_FOUND2 >/dev/null || exit 1 diff --git a/test/test_issues/test_i193/x-base.yang b/test/test_issues/test_i193/x-base.yang new file mode 100644 index 00000000..bf1c2039 --- /dev/null +++ b/test/test_issues/test_i193/x-base.yang @@ -0,0 +1,7 @@ +module x-base { + yang-version 1.1; + namespace "http://example.com/x-base"; + prefix x-b; + include x-base2; + include x-profiles; +} diff --git a/test/test_issues/test_i193/x-base2.yang b/test/test_issues/test_i193/x-base2.yang new file mode 100644 index 00000000..c6eac12d --- /dev/null +++ b/test/test_issues/test_i193/x-base2.yang @@ -0,0 +1,10 @@ +submodule x-base2 { + yang-version 1.1; + belongs-to x-base { + prefix x-b; + } + container configs { + container profiles { + } + } +} diff --git a/test/test_issues/test_i193/x-profiles.yang b/test/test_issues/test_i193/x-profiles.yang new file mode 100644 index 00000000..7c8c6b77 --- /dev/null +++ b/test/test_issues/test_i193/x-profiles.yang @@ -0,0 +1,14 @@ +submodule x-profiles { + yang-version 1.1; + belongs-to x-base { + prefix x-b; + } + augment "/x-b:configs/x-b:profiles" { + list profile { + key name; + leaf name { + type string; + } + } + } +} diff --git a/test/test_issues/test_i193/y-base.yang b/test/test_issues/test_i193/y-base.yang new file mode 100644 index 00000000..99727032 --- /dev/null +++ b/test/test_issues/test_i193/y-base.yang @@ -0,0 +1,7 @@ +module y-base { + yang-version 1.1; + namespace "http://example.com/y-base"; + prefix y-b; + include y-base2; + include y-profiles; +} diff --git a/test/test_issues/test_i193/y-base2.yang b/test/test_issues/test_i193/y-base2.yang new file mode 100644 index 00000000..d14b82cf --- /dev/null +++ b/test/test_issues/test_i193/y-base2.yang @@ -0,0 +1,10 @@ +submodule y-base2 { + yang-version 1.1; + belongs-to y-base { + prefix y-b; + } + container configs { + container profiles { + } + } +} diff --git a/test/test_issues/test_i193/y-profiles.yang b/test/test_issues/test_i193/y-profiles.yang new file mode 100644 index 00000000..86fc03fd --- /dev/null +++ b/test/test_issues/test_i193/y-profiles.yang @@ -0,0 +1,16 @@ +submodule y-profiles { + yang-version 1.1; + belongs-to y-base { + prefix y-b; + } + + container y { + must "/y-b:configs/y-b:profiles"; + list profile { + key name; + leaf name { + type string; + } + } + } +} diff --git a/test/test_issues/test_i193/y1-base.yang b/test/test_issues/test_i193/y1-base.yang new file mode 100644 index 00000000..59453046 --- /dev/null +++ b/test/test_issues/test_i193/y1-base.yang @@ -0,0 +1,6 @@ +module y1-base { + namespace "http://example.com/y1-base"; + prefix y-b; + include y1-base2; + include y1-profiles; +} diff --git a/test/test_issues/test_i193/y1-base2.yang b/test/test_issues/test_i193/y1-base2.yang new file mode 100644 index 00000000..741a6c42 --- /dev/null +++ b/test/test_issues/test_i193/y1-base2.yang @@ -0,0 +1,9 @@ +submodule y1-base2 { + belongs-to y1-base { + prefix y-b; + } + container configs { + container profiles { + } + } +} diff --git a/test/test_issues/test_i193/y1-profiles.yang b/test/test_issues/test_i193/y1-profiles.yang new file mode 100644 index 00000000..2a87bcef --- /dev/null +++ b/test/test_issues/test_i193/y1-profiles.yang @@ -0,0 +1,15 @@ +submodule y1-profiles { + belongs-to y1-base { + prefix y-b; + } + + container y { + must "/y-b:configs/y-b:profiles"; + list profile { + key name; + leaf name { + type string; + } + } + } +} diff --git a/test/test_issues/test_i193/z-base.yang b/test/test_issues/test_i193/z-base.yang new file mode 100644 index 00000000..f0c827b7 --- /dev/null +++ b/test/test_issues/test_i193/z-base.yang @@ -0,0 +1,7 @@ +module z-base { + yang-version 1.1; + namespace "http://example.com/z-base"; + prefix z-b; + include z-base2; + include z-profiles; +} diff --git a/test/test_issues/test_i193/z-base2.yang b/test/test_issues/test_i193/z-base2.yang new file mode 100644 index 00000000..0aa5034a --- /dev/null +++ b/test/test_issues/test_i193/z-base2.yang @@ -0,0 +1,13 @@ +submodule z-base2 { + yang-version 1.1; + belongs-to z-base { + prefix z-b; + } + container configs { + container profiles { + leaf foo { + type string; + } + } + } +} diff --git a/test/test_issues/test_i193/z-profiles.yang b/test/test_issues/test_i193/z-profiles.yang new file mode 100644 index 00000000..2754a2d5 --- /dev/null +++ b/test/test_issues/test_i193/z-profiles.yang @@ -0,0 +1,16 @@ +submodule z-profiles { + yang-version 1.1; + belongs-to z-base { + prefix z-b; + } + augment "/z-b:configs/z-b:profiles" { + list profile { + key name; + leaf name { + type leafref { + path "../../foo"; + } + } + } + } +} diff --git a/test/test_issues/test_i729/Makefile b/test/test_issues/test_i729/Makefile new file mode 100644 index 00000000..1faba374 --- /dev/null +++ b/test/test_issues/test_i729/Makefile @@ -0,0 +1,14 @@ +test: test1 test2 test3 test4 + +test1: + $(PYANG) -Werror -p v1.1 v1.1/native.yang + +test2: + $(PYANG) -Werror -p v1.1 v1.1/bgp.yang + +test3: + $(PYANG) -Werror -p v1 v1/native.yang + +test4: + $(PYANG) -Werror -p v1 --print-error-code v1/bgp.yang 2>&1 \ + | grep LEAFREF_IDENTIFIER_NOT_FOUND >/dev/null || exit 1 diff --git a/test/test_issues/test_i729/v1.1/bgp.yang b/test/test_issues/test_i729/v1.1/bgp.yang new file mode 100644 index 00000000..ccf86d0c --- /dev/null +++ b/test/test_issues/test_i729/v1.1/bgp.yang @@ -0,0 +1,27 @@ +module bgp { + yang-version 1.1; + namespace "http://example.com/bgp"; + prefix ios-bgp; + + import native { + prefix ios; + } + + + grouping config-bgp-grouping { + list bgp { + key "id"; + leaf id { + type string; + } + + container interface { + uses ios:interface-with-dependency-grouping; + } + } + } + + augment "/ios:native/ios:router" { + uses config-bgp-grouping; + } +} diff --git a/test/test_issues/test_i729/v1.1/native-sub.yang b/test/test_issues/test_i729/v1.1/native-sub.yang new file mode 100644 index 00000000..7398784b --- /dev/null +++ b/test/test_issues/test_i729/v1.1/native-sub.yang @@ -0,0 +1,42 @@ +submodule native-sub { + yang-version 1.1; + belongs-to native { + prefix ii; + } + + grouping interface-with-dependency-grouping { + choice interface-choice { + leaf GigabitEthernet { + description + "Service-Context Virtual Interface Compress"; + type leafref { + path "/ii:native/ii:interface/ii:GigabitEthernet/ii:name"; + } + } + } + } + + grouping config-interface-grouping { + container interface { + description + "Configure Interfaces"; + list GigabitEthernet { + description + "Service-Context Virtual Interface Compress"; + key "name"; + leaf name { + type uint16; + } + uses interface-common-grouping; + } + } + } + + grouping interface-common-grouping { + container switchport-conf { + leaf switchport { + type boolean; + } + } + } +} diff --git a/test/test_issues/test_i729/v1.1/native.yang b/test/test_issues/test_i729/v1.1/native.yang new file mode 100644 index 00000000..46e72b63 --- /dev/null +++ b/test/test_issues/test_i729/v1.1/native.yang @@ -0,0 +1,19 @@ +module native { + yang-version 1.1; + namespace "http://example.com/native"; + prefix ios; + + include native-sub; + + container native { + container router; + container ip { + container routing-conf { + leaf routing { + type string; + } + } + } + uses config-interface-grouping; + } +} diff --git a/test/test_issues/test_i729/v1/bgp.yang b/test/test_issues/test_i729/v1/bgp.yang new file mode 100644 index 00000000..68491376 --- /dev/null +++ b/test/test_issues/test_i729/v1/bgp.yang @@ -0,0 +1,26 @@ +module bgp { + namespace "http://example.com/bgp"; + prefix ios-bgp; + + import native { + prefix ios; + } + + + grouping config-bgp-grouping { + list bgp { + key "id"; + leaf id { + type string; + } + + container interface { + uses ios:interface-with-dependency-grouping; + } + } + } + + augment "/ios:native/ios:router" { + uses config-bgp-grouping; + } +} diff --git a/test/test_issues/test_i729/v1/native-sub.yang b/test/test_issues/test_i729/v1/native-sub.yang new file mode 100644 index 00000000..abd19fac --- /dev/null +++ b/test/test_issues/test_i729/v1/native-sub.yang @@ -0,0 +1,41 @@ +submodule native-sub { + belongs-to native { + prefix ii; + } + + grouping interface-with-dependency-grouping { + choice interface-choice { + leaf GigabitEthernet { + description + "Service-Context Virtual Interface Compress"; + type leafref { + path "/ii:native/ii:interface/ii:GigabitEthernet/ii:name"; + } + } + } + } + + grouping config-interface-grouping { + container interface { + description + "Configure Interfaces"; + list GigabitEthernet { + description + "Service-Context Virtual Interface Compress"; + key "name"; + leaf name { + type uint16; + } + uses interface-common-grouping; + } + } + } + + grouping interface-common-grouping { + container switchport-conf { + leaf switchport { + type boolean; + } + } + } +} diff --git a/test/test_issues/test_i729/v1/native.yang b/test/test_issues/test_i729/v1/native.yang new file mode 100644 index 00000000..cf9418be --- /dev/null +++ b/test/test_issues/test_i729/v1/native.yang @@ -0,0 +1,18 @@ +module native { + namespace "http://example.com/native"; + prefix ios; + + include native-sub; + + container native { + container router; + container ip { + container routing-conf { + leaf routing { + type string; + } + } + } + uses config-interface-grouping; + } +} From 987f59c07ae21b388e0221904111140b935a9568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Wed, 1 Nov 2023 09:57:38 +0100 Subject: [PATCH 27/41] Updates for 2.6.0 release --- CHANGELOG.md | 26 + CONTRIBUTORS | 8 +- man/man1/json2xml.1 | 225 ++-- man/man1/pyang.1 | 2876 +++++++++++++++++------------------------- man/man1/yang2dsdl.1 | 674 ++++------ pyang/__init__.py | 4 +- 6 files changed, 1541 insertions(+), 2272 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aa0d8e8..88dfa155 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +* 2.6.0 - 2023-11-03 +``` + lots of improvements to the UML plugin + thanks to Nick Hancock + lots of improvements to build and test + thanks to @ubaumann + fix invalid regular expression on Windows + thanks to Jan Kundrát + fix script issues on Windows + thanks to Jan Kundrát + fix validation of when expressions for 1.1 modules + thanks to Derek Ingrouville + fixes for revision-date in depend output + thanks to Slavomir Mazur + + #845 - sid item status + #844 - tree max line length issue + #837 - test fixes + #821 - typo in jstree output + #818 - issue with decimal64 defaults in json2xml + #809 - revision-date parsed wrong if multiple "@" found in path + thanks to Michael Littlejohn + #729 - handle name scoping of 1.1 submodules in XPath expressions + #516 - crash in tree output +``` + * 2.5.3 - 2022-03-30 ``` added support for checking 'ancestor' and 'ancestor-or-self' XPATH axes diff --git a/CONTRIBUTORS b/CONTRIBUTORS index bbf9082f..1871c0dc 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -11,17 +11,22 @@ Fred Gan Joe Gladston Pravin Gohite Yan Gorelik +Nick Hancock Giles Heron +Derek Ingrouville Jozef Janitor Robin Jarry Mahesh Jethanandani Denys Knertser Mallikarjunarao Kosuri Miroslav Kovac +Jan Kundrát Balázs Lengyel +Michael Littlejohn Miroslav Los Ladislav Lhotka William Lupton +Slavomir Mazur Glenn Matthews Paul Merlo Ganesh Nalawade @@ -40,6 +45,7 @@ Nick Weeds Jonathan Yang Quentin Young Huaian Zhou +@cygnus2048 @gribok @lemikev -@cygnus2048 \ No newline at end of file +@ubaumann diff --git a/man/man1/json2xml.1 b/man/man1/json2xml.1 index 7f4a27f9..463c7c1f 100644 --- a/man/man1/json2xml.1 +++ b/man/man1/json2xml.1 @@ -1,167 +1,92 @@ -'\" t -.\" Title: json2xml -.\" Author: Ladislav Lhotka -.\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 2022-03-30 -.\" Manual: pyang manual -.\" Source: json2xml-2.5.3 -.\" Language: English +.\" Automatically generated by Pandoc 2.9.2.1 .\" -.TH "JSON2XML" "1" "2022\-03\-30" "json2xml\-2\&.5\&.3" "pyang manual" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -json2xml \- translates JSON documents conforming to a YANG data model into XML\&. -.SH "SYNOPSIS" -.HP \w'\fBjson2xml\fR\ 'u -\fBjson2xml\fR [\-t\ \fItarget\fR] [\-o\ \fIoutput_file\fR] \fIdriver_file\fR \fIjson_file\fR -.HP \w'\fBjson2xml\fR\ 'u -\fBjson2xml\fR \-h | \-\-help -.SH "DESCRIPTION" -.PP -This program translates -\fIjson_file\fR -into XML using the procedure specified in -\m[blue]\fBRFC 7951\fR\m[]\&\s-2\u[1]\d\s+2\&. -.PP -The translation uses a second input file, -\fIdriver_file\fR, which contains a concise JSON representation of the YANG data model to which -\fIjson_file\fR -should conform, at least structurally\&. Normally, -\fIdriver_file\fR -is obtained as the -\fIjtox\fR -output of -\fBpyang\fR\&. -.PP -Using "\-" (hyphen) in place of -\fIjson_file\fR -instructs the program to read a JSON document from the standard input\&. -.PP -The -\fItarget\fR -argument specifies the document (root) element for the output XML document\&. This encapsulation is necessary because the input JSON document may contain multiple JSON objects at the top level\&. Supported values for the -\fItarget\fR -argument are: -.PP +.TH "JSON2XML" "1" "2023-11-03" "json2xml-2.6.0" "User Manual" +.hy +.SH NAME +.PP +json2xml - translates JSON documents conforming to a YANG data model +into XML. +.SH SYNOPSIS +.PP +\f[B]json2xml\f[R] [-t target] [-o \f[I]output_file\f[R]] +\f[I]driver_file\f[R] \f[I]json_file\f[R] +.PP +\f[B]json2xml\f[R] -h | --help +.SH DESCRIPTION +.PP +This program translates \f[I]json_file\f[R] into XML using the procedure +specified in \f[B]RFC 7951\f[R]. +.PP +The translation uses a second input file, \f[I]driver_file\f[R], which +contains a concise JSON representation of the YANG data model to which +\f[I]json_file\f[R] should conform, at least structurally. +Normally, \f[I]driver_file\f[R] is obtained as the \f[I]jtox\f[R] output +of \f[B]pyang\f[R]. +.PP +Using \[dq]-\[dq] (hyphen) in place of \f[I]json_file\f[R] instructs the +program to read a JSON document from the standard input. +.PP +The \f[I]target\f[R] argument specifies the document (root) element for +the output XML document. +This encapsulation is necessary because the input JSON document may +contain multiple JSON objects at the top level. +Supported values for the \f[I]target\f[R] argument are: +.TP data -.RS 4 -The document element will be \&. This is the default\&. -.RE -.PP +The document element will be . +This is the default. +.TP config -.RS 4 -The document element will be \&. -.RE -.PP -The XML prefix "nc" represents the standard NETCONF namespace with URI "urn:ietf:params:xml:ns:netconf:base:1\&.0"\&. -.SH "OPTIONS" -.PP -\fB\-t\fR \fItarget\fR, \fB\-\-target\fR \fItarget\fR -.RS 4 -Specifies the target type of the output XML document, i\&.e\&. its document element\&. The default is -\fBdata\fR\&. -.RE -.PP -\fB\-o\fR \fIoutput_file\fR, \fB\-\-output\fR \fIoutput_file\fR -.RS 4 -Write output to -\fIoutput_file\fR -instead of the standard output\&. -.RE -.PP -\fB\-h\fR, \fB\-\-help\fR -.RS 4 -Displays help screen and exits\&. -.RE -.SH "EXAMPLE" -.sp -.if n \{\ -.RS 4 -.\} -.nf -$ pyang \-f jtox \-o dhcp\&.jtox dhcp\&.yang -.fi -.if n \{\ -.RE -.\} -.sp -.if n \{\ -.RS 4 -.\} +The document element will be . +.PP +The XML prefix \[dq]nc\[dq] represents the standard NETCONF namespace +with URI \[dq]urn:ietf:params:xml:ns:netconf:base:1.0\[dq]. +.SH OPTIONS +.TP +\f[B]-t\f[R] \f[I]target\f[R], \f[B]target\f[R] \f[I]target\f[R] +Specifies the target type of the output XML document, i.e., its document +element. +The default is \f[B]data\f[R]. +.TP +\f[B]-o\f[R] \f[I]output_file\f[R], \f[B]--output\f[R] \f[I]output_file\f[R] +Write output to \f[I]output_file\f[R] instead of the standard output. +.TP +\f[B]-h\f[R], \f[B]--help\f[R] +Displays help screen and exits. +.SH EXAMPLES +.IP .nf -$ json2xml \-o dhcp\-data\&.xml dhcp\&.jtox dhcp\-data\&.json +\f[C] +$ pyang -f jtox -o dhcp.jtox dhcp.yang + +$ json2xml -o dhcp-data.xml dhcp.jtox dhcp-data.json +\f[R] .fi -.if n \{\ -.RE -.\} .PP -The first command generates the driver file -dhcp\&.jtox, which is then used for translating JSON file -dhcp\-data\&.json -to XML file -dhcp\-data\&.xml\&. -.SH "DIAGNOSTICS" -.PP -\fBjson2xml\fR -return codes have the following meaning: +The first command generates the driver file dhcp.jtox, which is then +used for translating JSON file dhcp-data.json to XML file dhcp-data.xml. +.SH DIAGNOSTICS .PP +\f[B]json2xml\f[R] return codes have the following meaning: +.TP 0 -.RS 4 No error (normal termination) -.RE -.PP +.TP 1 -.RS 4 One of the input files cannot be read -.RE -.PP +.TP 2 -.RS 4 Error in command line arguments -.RE -.PP +.TP 3 -.RS 4 JSON to XML translation failed -.RE -.SH "SEE ALSO" +.SH SEE ALSO .PP -\m[blue]\fBRFC 7951\fR\m[]\&\s-2\u[1]\d\s+2, -\fBpyang\fR(1), -\m[blue]\fBJSON\fR\m[]\&\s-2\u[2]\d\s+2\&. -.SH "AUTHOR" +\f[B]RFC 7951\f[R], \f[B]pyang\f[R](1) +.SH AUTHOR .PP -\fBLadislav Lhotka\fR <\&lhotka@nic\&.cz\&> -.br -CZ\&.NIC -.RS 4 -.RE -.SH "NOTES" -.IP " 1." 4 -RFC 7951 -.RS 4 -\%http://tools.ietf.org/html/rfc7951 -.RE -.IP " 2." 4 -JSON -.RS 4 -\%http://www.json.org/ -.RE +\f[B]Ladislav Lhotka\f[R] +.PD 0 +.P +.PD +CZ.NIC diff --git a/man/man1/pyang.1 b/man/man1/pyang.1 index 12634c18..606b96f3 100644 --- a/man/man1/pyang.1 +++ b/man/man1/pyang.1 @@ -1,1820 +1,1304 @@ -'\" t -.\" Title: pyang -.\" Author: Martin Björklund -.\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 2022-03-30 -.\" Manual: pyang manual -.\" Source: pyang-2.5.3 -.\" Language: English +.\" Automatically generated by Pandoc 2.9.2.1 .\" -.TH "PYANG" "1" "2022\-03\-30" "pyang\-2\&.5\&.3" "pyang manual" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -pyang \- validate and convert YANG modules to various formats -.SH "SYNOPSIS" -.HP \w'\fBpyang\fR\ 'u -\fBpyang\fR [\-\-verbose] [\-\-canonical] [\-\-strict] [\-\-lint] [\-\-ietf] [\-\-lax\-quote\-checks] [\-\-lax\-xpath\-checks] [\-\-features\ \fIfeatures\fR] [\-\-exclude\-features\ \fIfeatures\fR] [\-\-max\-status\ \fImaxstatus\fR] [\-\-hello] [\-\-implicit\-hello\-deviations] [\-\-check\-update\-from\ \fIoldfile\fR] [\-o\ \fIoutfile\fR] [\-t\ \fItransform\fR] [\-f\ \fIformat\fR] [\-p\ \fIpath\fR] [\-W\ \fIwarning\fR] [\-E\ \fIerror\fR] \fIfile\fR... -.HP \w'\fBpyang\fR\ 'u -\fBpyang\fR [\-\-sid\-list] \-\-sid\-generate\-file {count | \fIentry\-point:size\fR} \fIyang\-filename\fR -.HP \w'\fBpyang\fR\ 'u -\fBpyang\fR [\-\-sid\-list] \-\-sid\-update\-file \fIsid\-filename\fR \fIyang\-filename\fR [\-\-sid\-extra\-range\ {count\ |\ \fIentry\-point:size\fR}] -.HP \w'\fBpyang\fR\ 'u -\fBpyang\fR [\-\-sid\-list] \-\-sid\-check\-file \fIsid\-filename\fR \fIyang\-filename\fR -.HP \w'\fBpyang\fR\ 'u -\fBpyang\fR \-h | \-\-help -.HP \w'\fBpyang\fR\ 'u -\fBpyang\fR \-v | \-\-version -.PP -One or more -\fIfile\fR -parameters may be given on the command line\&. They denote either YANG modules to be processed (in YANG or YIN syntax) or, using the -\fB\-\-hello\fR -switch, a server message conforming to -\m[blue]\fBRFC 6241\fR\m[]\&\s-2\u[1]\d\s+2 -and -\m[blue]\fBRFC 6020\fR\m[]\&\s-2\u[2]\d\s+2, which completely defines the data model \- supported YANG modules as well as features and capabilities\&. In the latter case, only one -\fIfile\fR -parameter may be present\&. -.PP -If no files are given, -\fBpyang\fR -reads input from stdin, which must be one module or a server message\&. -.SH "DESCRIPTION" -.PP -The -\fBpyang\fR -program is used to validate YANG modules (\m[blue]\fBRFC 6020\fR\m[]\&\s-2\u[2]\d\s+2 -and -\m[blue]\fBRFC 7950\fR\m[]\&\s-2\u[3]\d\s+2)\&. It is also used to convert YANG modules into equivalent YIN modules\&. From a valid module a hybrid DSDL schema (\m[blue]\fBRFC 6110\fR\m[]\&\s-2\u[4]\d\s+2) can be generated\&. -.PP -If no -\fIformat\fR -is given, the specified modules are validated, and the program exits with exit code 0 if all modules are valid\&. -.SH "OPTIONS" -.PP -\fB\-h\fR \fB\-\-help\fR -.RS 4 -Print a short help text and exit\&. -.RE -.PP -\fB\-v\fR \fB\-\-version\fR -.RS 4 -Print the version number and exit\&. -.RE -.PP -\fB\-e\fR \fB\-\-list\-errors\fR -.RS 4 -Print a listing of all error codes and messages pyang might generate, and then exit\&. -.RE -.PP -\fB\-\-print\-error\-code\fR -.RS 4 -On errors, print the symbolic error code instead of the error message\&. -.RE -.PP -\fB\-\-print\-error\-basename\fR -.RS 4 -On errors, print only the base file name independent of its module path location\&. -.RE -.PP -\fB\-Werror\fR -.RS 4 -Treat warnings as errors\&. -.RE -.PP -\fB\-Wnone\fR -.RS 4 -Do not print any warnings\&. -.RE -.PP -\fB\-W\fR \fIerrorcode\fR -.RS 4 -Treat -\fIerrorcode\fR -as a warning, even if -\fB\-Werror\fR -is given\&. -\fIerrorcode\fR -must be a warning or a minor error\&. -.sp -Use -\fB\-\-list\-errors\fR -to get a listing of all errors and warnings\&. -.sp -The following example treats all warnings except the warning for unused imports as errors: -.sp -.if n \{\ -.RS 4 -.\} +.TH "PYANG" "1" "2023-11-03" "pyang-2.6.0" "User Manual" +.hy +.SH NAME +.PP +pyang - validate and convert YANG modules to various formats +.SH SYNOPSIS +.PP +\f[B]pyang\f[R] [--verbose] [--canonical] [--strict] [--lint] [--ietf] +[--lax-quote-checks] [--lax-xpath-checks] [--features +\f[I]features\f[R]] [--exclude-features \f[I]features\f[R]] +[--max-status \f[I]maxstatus\f[R]] [--hello] +[--implicit-hello-deviations] [--check-update-from \f[I]oldfile\f[R]] +[-o \f[I]outfile\f[R]] [-t \f[I]transform\f[R]] [-f \f[I]format\f[R]] +[-p \f[I]path\f[R]] [-W \f[I]warning\f[R]] [-E \f[I]error\f[R]] +\f[I]file\f[R]\&... +.PP +\f[B]pyang\f[R] [--sid-list] --sid-generate-file {count | +\f[I]entry-point:size\f[R]} \f[I]yang-filename\f[R] +.PP +\f[B]pyang\f[R] [--sid-list] --sid-update-file \f[I]sid-filename\f[R] +\f[I]yang-filename\f[R] [--sid-extra-range count +\f[I]entry-point:size\f[R]] +.PP +\f[B]pyang\f[R] [--sid-list] --sid-check-file \f[I]sid-filename\f[R] +\f[I]yang-filename\f[R] +.PP +\f[B]pyang\f[R] -h | --help +.PP +\f[B]pyang\f[R] -v --version +.PP +One or more \f[I]file\f[R] parameters may be given on the command line. +They denote either YANG modules to be processed (in YANG or YIN syntax) +or, using the \f[B]--hello\f[R] switch, a server message +conforming to \f[B]RFC 6241\f[R] and \f[B]RFC 6020\f[R], which +completely defines the data model - supported YANG modules as well as +features and capabilities. +In the latter case, only one \f[I]file\f[R] parameter may be present. +.PP +If no files are given, \f[B]pyang\f[R] reads input from stdin, which +must be one module or a server message. +.SH DESCRIPTION +.PP +The \f[B]pyang\f[R] program is used to validate YANG modules (\f[B]RFC +6020\f[R] and \f[B]RFC 7950\f[R]). +It is also used to convert YANG modules into equivalent YIN modules. +From a valid module a hybrid DSDL schema (\f[B]RFC 6110\f[R]) can be +generated. +.PP +If no \f[I]format\f[R] is given, the specified modules are validated, +and the program exits with exit code 0 if all modules are valid. +.SH OPTIONS +.TP +\f[B]-h\f[R], \f[B]--help\f[R] +Print a short help text and exit. +.TP +\f[B]-v\f[R], \f[B]--version\f[R] +Print the version number and exit. +.TP +\f[B]-e\f[R], \f[B]--list-errors\f[R] +Print a listing of all error codes and messages pyang might generate, +and then exit. +.TP +\f[B]--print-error-code\f[R] +On errors, print the symbolic error code instead of the error message. +.TP +\f[B]--print-error-basename\f[R] +On errors, print only the base file name independent of its module path +location. +.TP +\f[B]-Werror\f[R] +Treat warnings as errors. +.TP +\f[B]-Wnone\f[R] +Do not print any warnings. +.TP +\f[B]-W\f[R] \f[I]errorcode\f[R] +Treat \f[I]errorcode\f[R] as a warning, even if \f[B]-Werror\f[R] is +given. +\f[I]errorcode\f[R] must be a warning or a minor error. +.RS +.PP +Use \f[B]--list-errors\f[R] to get a listing of all errors and warnings. +.PP +The following example treats all warnings except the warning for unused +imports as errors: +.IP .nf -$ pyang \-\-Werror \-W UNUSED_IMPORT +\f[C] +$ pyang --Werror -W UNUSED_IMPORT +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]-E\f[R] \f[I]errorcode\f[R] +Treat the warning \f[I]errorcode\f[R] as an error. +.RS +.PP +Use \f[B]--list-errors\f[R] to get a listing of all errors and warnings. .PP -\fB\-E\fR \fIerrorcode\fR -.RS 4 -Treat the warning -\fIerrorcode\fR -as an error\&. -.sp -Use -\fB\-\-list\-errors\fR -to get a listing of all errors and warnings\&. -.sp -The following example treats only the warning for unused import as an error: -.sp -.if n \{\ -.RS 4 -.\} +The following example treats only the warning for unused import as an +error: +.IP .nf -$ pyang \-\-Werror \-W UNUSED_IMPORT +\f[C] +$ pyang --Werror -W UNUSED_IMPORT +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]--ignore-error\f[R] \f[I]errorcode\f[R] +Ignore error \f[I]errorcode\f[R]. +.RS +.PP +Use with care. +Plugins that dont expect to be invoked if there are errors present may +crash. +.PP +Use \f[B]--list-errors\f[R] to get a listing of all errors and warnings. .PP -\fB\-\-ignore\-error\fR \fIerrorcode\fR -.RS 4 -Ignore error -\fIerrorcode\fR\&. -.sp -Use with care\&. Plugins that don\*(Aqt expect to be invoked if there are errors present may crash\&. -.sp -Use -\fB\-\-list\-errors\fR -to get a listing of all errors and warnings\&. -.sp The following example ignores syntax errors in patterns: -.sp -.if n \{\ -.RS 4 -.\} +.IP .nf -$ pyang \-\-ignore\-error PATTERN_ERROR +\f[C] +$ pyang --ignore-error PATTERN_ERROR +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]--msg-template\f[R] \f[I]msg-template\f[R] +Print out error message in defined \f[I]msg-template\f[R]. +.RS +.PP +Template used to display error messages. +This is a python new-style format string used to format the message +information with keys file, line, code, type, and msg. .PP -\fB\-\-msg\-template\fR \fImsg\-template\fR -.RS 4 -Print out error message in defined -\fImsg\-template\fR\&. -.sp -Template used to display error messages\&. This is a python new\-style format string used to format the message information with keys file, line, code, type, and msg\&. -.sp The following example create a msg template in defined pattern: -.sp -.if n \{\ -.RS 4 -.\} +.IP .nf -$ pyang \-\-msg\-template=\*(Aq{file} || {line} || {type} || {level} || {code} || {msg}\*(Aq +\f[C] +$ pyang --msg-template={file} || {line} || {type} || {level} + || {code} || {msg} +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]--ignore-errors\f[R] +Ignore all errors. +Use with care. +Plugins that dont expect to be invoked if there are errors present may +crash. +.TP +\f[B]--keep-comments\f[R] +This parameter has effect only if a plugin can handle comments. +.TP +\f[B]--canonical\f[R] +Validate the module(s) according to the canonical YANG order. +.TP +\f[B]--verify-revision-history\f[R] +Ensure that the revision history in the given module(s) is correct, by +checking that it can find the old revisions of the module(s) in the YANG +module search path. +.TP +\f[B]--strict\f[R] +Force strict YANG compliance. +Currently this checks that the deref() function is not used in XPath +expressions and leafrefs. +.TP +\f[B]--lint\f[R] +Validate the module(s) according to the generic YANG guideline as +specified in \f[B]RFC 8407\f[R]. +In addition, it checks that the module is in canonical order. +.TP +\f[B]--ietf\f[R] +Validate the module(s) like \f[B]--lint\f[R], and in addition verifies +that the namespace and module name follow the IETF conventions, and that +the module has the correct license text and \f[B]RFC 2119\f[R] / +\f[B]RFC 8174\f[R] boilerplate text. +.TP +\f[B]--lax-quote-checks\f[R] +Lax checks of backslashes in double quoted strings in YANG version 1 +modules. +\f[B]RFC 6020\f[R] does not clearly define how to handle backslahes +within double quoted strings, when the character after the backslash is +not one of the characters listed in Section 6.1.3 in \f[B]RFC 6020\f[R]. +.RS +.PP +Earlier versions of pyang silently accepted such escape sequences, but +the current version treats this as an error, just like it is defined in +YANG 1.1 \f[B]RFC 7950\f[R]. +Passing this flag to pyang makes pyang silently accept such escape +sequences. +.RE +.TP +\f[B]--lax-xpath-checks\f[R] +Lax checks of XPath expressions. +Specifically, do not generate an error if an XPath expression uses a +variable or an unknown function. +.TP +\f[B]-L\f[R] \f[B]--hello\f[R] +Interpret the input file or standard input as a server message. +In this case, no more than one \f[I]file\f[R] parameter may be given. +.TP +\f[B]--implicit-hello-deviations\f[R] +Attempt to parse all deviations from a supplied message. +Not all implementations provide deviations explicitly as modules. +This flag enables more logic to attempt to derive all deviations from +the message. +.TP +\f[B]--trim-yin\f[R] +In YIN input modules, remove leading and trailing whitespace from every +line in the arguments of the following statements: contact, description, +error-message, organization and reference. +This way, the XML-indented argument texts look tidy after translating +the module to the compact YANG syntax. +.TP +\f[B]--max-line-length\f[R] \f[I]maxlen\f[R] +Give a warning if any line is longer than \f[I]maxlen\f[R]. +The value 0 means no check (default). +.TP +\f[B]--max-identifier-length\f[R] \f[I]maxlen\f[R] +Give a error if any identifier is longer than_maxlen_. +.TP +\f[B]-t\f[R] \f[B]--transform\f[R] \f[I]transform\f[R] +Transform the module(s) after parsing them but before outputting them. +Multiple transformations can be given, and will be performed in the +order that they were specified. +The supported transformations are listed in TRANSFORMATIONS below. +.TP +\f[B]-f\f[R] \f[B]--format\f[R] \f[I]format\f[R] +Convert the module(s) into \f[I]format\f[R]. +Some translators require a single module, and some can translate +multiple modules at one time. +If no \f[I]outfile\f[R] file is specified, the result is printed on +stdout. +The supported formats are listed in OUTPUT FORMATS below. +.TP +\f[B]-o\f[R] \f[B]--output\f[R] \f[I]outfile\f[R] +Write the output to the file \f[I]outfile\f[R] instead of stdout. +.TP +\f[B]-F\f[R] \f[B]--features\f[R] \f[I]features\f[R] +\f[I]features\f[R] is a string of the form +\f[I]modulename\f[R]:[\f[I]feature\f[R](,\f[I]feature\f[R])*] +.RS +.PP +This option is used to prune the data model by removing all nodes that +are defined with a \[dq]if-feature\[dq] that is not listed as +\f[I]feature\f[R]. +This option affects all output formats. .PP -\fB\-\-ignore\-errors\fR -.RS 4 -Ignore all errors\&. Use with care\&. Plugins that don\*(Aqt expect to be invoked if there are errors present may crash\&. -.RE -.PP -\fB\-\-keep\-comments\fR -.RS 4 -This parameter has effect only if a plugin can handle comments\&. -.RE -.PP -\fB\-\-canonical\fR -.RS 4 -Validate the module(s) according to the canonical YANG order\&. -.RE -.PP -\fB\-\-verify\-revision\-history\fR -.RS 4 -Ensure that the revision history in the given module(s) is correct, by checking that it can find the old revisions of the module(s) in the YANG module search path\&. -.RE -.PP -\fB\-\-strict\fR -.RS 4 -Force strict YANG compliance\&. Currently this checks that the deref() function is not used in XPath expressions and leafrefs\&. -.RE -.PP -\fB\-\-lint\fR -.RS 4 -Validate the module(s) according to the generic YANG guideline as specified in -\m[blue]\fBRFC 8407\fR\m[]\&\s-2\u[5]\d\s+2\&. In addition, it checks that the module is in canonical order\&. -.RE -.PP -\fB\-\-ietf\fR -.RS 4 -Validate the module(s) like -\fB\-\-lint\fR, and in addition verifies that the namespace and module name follow the IETF conventions, and that the module has the correct license text and -\m[blue]\fBRFC 2119\fR\m[]\&\s-2\u[6]\d\s+2 -/ -\m[blue]\fBRFC 8174\fR\m[]\&\s-2\u[7]\d\s+2 -boilerplate text\&. -.RE -.PP -\fB\-\-lax\-quote\-checks\fR -.RS 4 -Lax checks of backslashes in double quoted strings in YANG version 1 modules\&. -\m[blue]\fBRFC 6020\fR\m[]\&\s-2\u[2]\d\s+2 -does not clearly define how to handle backslahes within double quoted strings, when the character after the backslash is not one of the characters listed in Section 6\&.1\&.3 in -\m[blue]\fBRFC 6020\fR\m[]\&\s-2\u[2]\d\s+2\&. -.sp -Earlier versions of pyang silently accepted such escape sequences, but the current version treats this as an error, just like it is defined in YANG 1\&.1 (\m[blue]\fBRFC 7950\fR\m[]\&\s-2\u[3]\d\s+2)\&. Passing this flag to pyang makes pyang silently accept such escape sequences\&. -.RE -.PP -\fB\-\-lax\-xpath\-checks\fR -.RS 4 -Lax checks of XPath expressions\&. Specifically, do not generate an error if an XPath expression uses a variable or an unknown function\&. -.RE -.PP -\fB\-L\fR \fB\-\-hello\fR -.RS 4 -Interpret the input file or standard input as a server message\&. In this case, no more than one -\fIfile\fR -parameter may be given\&. -.RE -.PP -\fB\-\-implicit\-hello\-deviations\fR -.RS 4 -Attempt to parse all deviations from a supplied message\&. Not all implementations provide deviations explicitly as modules\&. This flag enables more logic to attempt to derive all deviations from the message\&. -.RE +This option can be given multiple times, and may also be combined with +\f[B]--hello\f[R]. +The \f[B]--features\f[R] option overrides any supported features for a +module that are taken from the hello file. .PP -\fB\-\-trim\-yin\fR -.RS 4 -In YIN input modules, remove leading and trailing whitespace from every line in the arguments of the following statements: \*(Aqcontact\*(Aq, \*(Aqdescription\*(Aq, \*(Aqerror\-message\*(Aq, \*(Aqorganization\*(Aq and \*(Aqreference\*(Aq\&. This way, the XML\-indented argument texts look tidy after translating the module to the compact YANG syntax\&. -.RE +If this option is not given, nothing is pruned, i.e., it works as if all +features were explicitly listed. .PP -\fB\-\-max\-line\-length\fR \fImaxlen\fR -.RS 4 -Give a warning if any line is longer than -\fImaxlen\fR\&. The value 0 means no check (default)\&. -.RE +The \f[B]--exclude-features\f[R] option can be used for excluding a list +of named features. +\f[B]--features\f[R] and \f[B]--exclude-features\f[R] cant both be +specified for a given module. .PP -\fB\-\-max\-identifier\-length\fR \fImaxlen\fR -.RS 4 -Give a error if any identifier is longer than -\fImaxlen\fR\&. +For example, to view the tree output for a module with all if-featured +nodes removed, do: +.IP +.nf +\f[C] +$ pyang -f tree --features mymod: mymod.yang +\f[R] +.fi .RE +.TP +\f[B]-X\f[R] \f[B]--exclude-features\f[R] \f[I]features\f[R] +\f[I]features\f[R] is a string of the form +\f[I]modulename\f[R]:[\f[I]feature\f[R](,\f[I]feature\f[R])*] +.RS .PP -\fB\-t\fR \fB\-\-transform\fR \fItransform\fR -.RS 4 -Transform the module(s) after parsing them but before outputting them\&. Multiple transformations can be given, and will be performed in the order that they were specified\&. The supported transformations are listed in -TRANSFORMATIONS -below\&. -.RE +This option is used to prune the data model by removing all nodes that +are defined with a \[dq]if-feature\[dq] that is listed as +\f[I]feature\f[R]. +This option affects all output formats. .PP -\fB\-f\fR \fB\-\-format\fR \fIformat\fR -.RS 4 -Convert the module(s) into -\fIformat\fR\&. Some translators require a single module, and some can translate multiple modules at one time\&. If no -\fIoutfile\fR -file is specified, the result is printed on stdout\&. The supported formats are listed in -OUTPUT FORMATS -below\&. -.RE +This option can be given multiple times. +It cant be combined with \f[B]--hello\f[R]. .PP -\fB\-o\fR \fB\-\-output\fR \fIoutfile\fR -.RS 4 -Write the output to the file -\fIoutfile\fR -instead of stdout\&. -.RE +The \f[B]--features\f[R] option can be used for including all features +or a list of named features. +\f[B]--features\f[R] and \f[B]--exclude-features\f[R] cant both be +specified for a given module. .PP -\fB\-F\fR \fB\-\-features\fR \fIfeatures\fR -.RS 4 -\fIfeatures\fR -is a string of the form -\fImodulename\fR:[\fIfeature\fR(,\fIfeature\fR)*] -.sp -This option is used to prune the data model by removing all nodes that are defined with a "if\-feature" that is not listed as -\fIfeature\fR\&. This option affects all output formats\&. -.sp -This option can be given multiple times, and may also be combined with -\fB\-\-hello\fR\&. The -\fB\-\-features\fR -option overrides any supported features for a module that are taken from the hello file\&. -.sp -If this option is not given, nothing is pruned, i\&.e\&., it works as if all features were explicitly listed\&. -.sp -The -\fB\-\-exclude\-features\fR -option can be used for excluding a list of named features\&. -\fB\-\-features\fR -and -\fB\-\-exclude\-features\fR -can\*(Aqt both be specified for a given module\&. -.sp -For example, to view the tree output for a module with all if\-feature\*(Aqd nodes removed, do: -.sp -.if n \{\ -.RS 4 -.\} +For example, to view the tree output for a module with if-featured nodes +for the specified feature removed, do: +.IP .nf -$ pyang \-f tree \-\-features mymod: mymod\&.yang +\f[C] +$ pyang -f tree --exclude-features mymod:myfeat mymod.yang +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]--max-status\f[R] \f[I]maxstatus\f[R] +\f[I]maxstatus\f[R] is one of:\f[I]current\f[R],\f[I]deprecated\f[R], or +\f[I]obsolete\f[R]. +.RS .PP -\fB\-X\fR \fB\-\-exclude\-features\fR \fIfeatures\fR -.RS 4 -\fIfeatures\fR -is a string of the form -\fImodulename\fR:[\fIfeature\fR(,\fIfeature\fR)*] -.sp -This option is used to prune the data model by removing all nodes that are defined with a "if\-feature" that is listed as -\fIfeature\fR\&. This option affects all output formats\&. -.sp -This option can be given multiple times\&. It can\*(Aqt be combined with -\fB\-\-hello\fR\&. -.sp -The -\fB\-\-features\fR -option can be used for including all features or a list of named features\&. -\fB\-\-features\fR -and -\fB\-\-exclude\-features\fR -can\*(Aqt both be specified for a given module\&. -.sp -For example, to view the tree output for a module with if\-feature\*(Aqd nodes for the specified feature removed, do: -.sp -.if n \{\ -.RS 4 -.\} -.nf -$ pyang \-f tree \-\-exclude\-features mymod:myfeat mymod\&.yang -.fi -.if n \{\ -.RE -.\} +This option is used to prune the data model by removing all nodes that +are defined with a \[dq]status\[dq] that is less than the given +\f[I]maxstatus\f[R]. +This option affects all output formats. .RE +.TP +\f[B]--deviation-module\f[R] \f[I]file\f[R] +This option is used to apply the deviations defined in \f[I]file\f[R]. +This option affects all output formats. +.RS .PP -\fB\-\-max\-status\fR \fImaxstatus\fR -.RS 4 -\fImaxstatus\fR -is one of: -\fIcurrent\fR, -\fIdeprecated\fR, or -\fIobsolete\fR\&. -.sp -This option is used to prune the data model by removing all nodes that are defined with a "status" that is less than the given -\fImaxstatus\fR\&. This option affects all output formats\&. -.RE +This option can be given multiple times. .PP -\fB\-\-deviation\-module\fR \fIfile\fR -.RS 4 -This option is used to apply the deviations defined in -\fIfile\fR\&. This option affects all output formats\&. -.sp -This option can be given multiple times\&. -.sp -For example, to view the tree output for a module with some deviations applied, do: -.sp -.if n \{\ -.RS 4 -.\} +For example, to view the tree output for a module with some deviations +applied, do: +.IP .nf -$ pyang \-f tree \-\-deviation\-module mymod\-devs\&.yang mymod\&.yang +\f[C] +$ pyang -f tree --deviation-module mymod-devs.yang mymod.yang +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]-p\f[R] \f[B]--path\f[R] \f[I]path\f[R] +\f[I]path\f[R] is a colon (:) separated list of directories to search +for imported modules. +This option may be given multiple times. +.RS +.PP +By default, all directories (except \[dq].\[dq]) found in the path are +recursively scanned for modules. +This behavior can be disabled by giving the option +\f[B]--no-path-recurse\f[R]. .PP -\fB\-p\fR \fB\-\-path\fR \fIpath\fR -.RS 4 -\fIpath\fR -is a colon (:) separated list of directories to search for imported modules\&. This option may be given multiple times\&. -.sp -By default, all directories (except "\&.") found in the path are recursively scanned for modules\&. This behavior can be disabled by giving the option -\fB\-\-no\-path\-recurse\fR\&. -.sp The following directories are always added to the search path: -.sp -.RS 4 -.ie n \{\ -\h'-04' 1.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 1." 4.2 -.\} +.IP "1." 3 current directory +.IP "2." 3 +\f[B]$YANG_MODPATH\f[R] +.IP "3." 3 +\f[B]$HOME\f[R]/yang/modules +.IP "4." 3 +\f[B]\f[BI]Y\f[B]\f[BI]A\f[B]\f[BI]N\f[B]\f[BI]G\f[B]_\f[BI]I\f[B]\f[BI]N\f[B]\f[BI]S\f[B]\f[BI]T\f[B]\f[BI]A\f[B]\f[BI]L\f[B]\f[BI]L\f[B]\[u2005]*\[u2005]\[u2005]*\[u2005]/\f[BI]y\f[B]\f[BI]a\f[B]\f[BI]n\f[B]\f[BI]g\f[B]/\f[BI]m\f[B]\f[BI]o\f[B]\f[BI]d\f[B]\f[BI]u\f[B]\f[BI]l\f[B]\f[BI]e\f[B]\f[BI]s\f[B]\f[BI]O\f[B]\f[BI]R\f[B]\f[BI]i\f[B]\f[BI]f\f[B]\[u2005]*\[u2005]*YANG_INSTALL\f[R] +is unset /yang/modules (on Unix +systems: /usr/share/yang/modules) +.RE +.TP +\f[B]--no-path-recurse\f[R] +If this parameter is given, directories in the search path are not +recursively scanned for modules. +.TP +\f[B]--plugindir\f[R] \f[I]plugindir\f[R] +Load all YANG plugins found in the directory \f[I]plugindir\f[R]. +This option may be given multiple times. +.RS +.PP +List of directories to search for pyang plugins. +The following directories are always added to the search path: +.IP "1." 3 +pyang/plugins from where pyang is installed +.IP "2." 3 +\f[B]$PYANG_PLUGINPATH\f[R] .RE -.sp -.RS 4 -.ie n \{\ -\h'-04' 2.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 2." 4.2 -.\} -\fB$YANG_MODPATH\fR -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04' 3.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 3." 4.2 -.\} -\fB$HOME\fR/yang/modules -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04' 4.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 4." 4.2 -.\} -\fB$YANG_INSTALL\fR/yang/modules -OR if -\fB$YANG_INSTALL\fR -is unset -/yang/modules -(on Unix systems: -/usr/share/yang/modules) -.RE -.RE -.PP -\fB\-\-no\-path\-recurse\fR -.RS 4 -If this parameter is given, directories in the search path are not recursively scanned for modules\&. -.RE -.PP -\fB\-\-plugindir\fR \fIplugindir\fR -.RS 4 -Load all YANG plugins found in the directory -\fIplugindir\fR\&. This option may be given multiple times\&. -.sp -list of directories to search for pyang plugins\&. The following directories are always added to the search path: -.sp -.RS 4 -.ie n \{\ -\h'-04' 1.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 1." 4.2 -.\} -pyang/plugins -from where pyang is installed -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04' 2.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 2." 4.2 -.\} -\fB$PYANG_PLUGINPATH\fR -.RE -.RE -.PP -\fB\-\-check\-update\-from\fR \fIoldfile\fR -.RS 4 +.TP +\f[B]--check-update-from\f[R] \f[I]oldfile\f[R] Checks that a new revision of a module follows the update rules given in -\m[blue]\fBRFC 6020\fR\m[]\&\s-2\u[2]\d\s+2 -and -\m[blue]\fBRFC 7950\fR\m[]\&\s-2\u[3]\d\s+2\&. -\fIoldfile\fR -is the old module and -\fIfile\fR -is the new version of the module\&. -.sp -If the old module imports or includes any modules or submodules, it is important that the the old versions of these modules and submodules are found\&. By default, the directory where -\fIoldfile\fR -is found is used as the only directory in the search path for old modules\&. Use the option -\fB\-\-check\-update\-from\-path\fR -to control this path\&. -.RE -.PP -\fB\-P\fR \fB\-\-check\-update\-from\-path\fR \fIoldpath\fR -.RS 4 -\fIoldpath\fR -is a colon (:) separated list of directories to search for imported modules\&. This option may be given multiple times\&. -.RE -.PP -\fB\-D\fR \fB\-\-check\-update\-from\-deviation\-module\fR \fIolddeviation\fR -.RS 4 -\fIolddeviation\fR -is an old deviation module of the old module -\fIoldfile\fR\&. This option may be given multiple times\&. For example, to check updates of a module with some deviations applied, do: -.sp -.if n \{\ -.RS 4 -.\} +\f[B]RFC 6020\f[R] and \f[B]RFC 7950\f[R]. +\f[I]oldfile\f[R] is the old module and \f[I]file\f[R] is the new +version of the module. +.RS +.PP +If the old module imports or includes any modules or submodules, it is +important that the the old versions of these modules and submodules are +found. +By default, the directory where \f[I]oldfile\f[R] is found is used as +the only directory in the search path for old modules. +Use the option +.RE +.TP +\f[B]--check-update-from-path\f[R] +to control this path. +.TP +\f[B]-P\f[R] \f[B]--check-update-from-path\f[R] \f[I]oldpath\f[R] +\f[I]oldpath\f[R] is a colon (:) separated list of directories to search +for imported modules. +This option may be given multiple times. +.TP +\f[B]-D\f[R] \f[B]--check-update-from-deviation-module\f[R] \f[I]olddeviation\f[R] +\f[I]olddeviation\f[R] is an old deviation module of the old module +\f[I]oldfile\f[R]. +This option may be given multiple times. +For example, to check updates of a module with some deviations applied, +do: +.RS +.IP .nf -$ pyang \-\-check\-update\-from\-deviation\-module oldmod\-devs\&.yang \-\-check\-update\-from oldmod\&.yang \e - \-\-deviation\-module newmod\-devs\&.yang newmod\&.yang +\f[C] +$ pyang --check-update-from-deviation-module oldmod-devs.yang \[rs] + --check-update-from oldmod.yang \[rs] + --deviation-module newmod-devs.yang newmod.yang +\f[R] .fi -.if n \{\ .RE -.\} -.RE -.PP -\fIfile\&.\&.\&.\fR -.RS 4 -These are the names of the files containing the modules to be validated, or the module to be converted\&. -.RE -.SH "TRANSFORMATIONS" -.PP -Installed -\fBpyang\fR -transformations are (like output formats) plugins and therefore may define their own options, or add new transformations to the -\fB\-t\fR -option\&. These options and transformations are listed in -\fBpyang \-h\fR\&. -.PP -\fIedit\fR -.RS 4 -Modify the supplied module(s) in various ways\&. This transform will usually be used with the -\fIyang\fR -output format\&. -.RE -.SH "EDIT TRANSFORM" -.PP -The -\fIedit\fR -transform modifies the supplied module(s) in various ways\&. It can, for example, replace top\-level -\fIdescription\fR -statements, update -\fIinclude\fR -statements and manage -\fIrevision\fR -statements\&. Unless otherwise noted below, it only modifies -\fIexisting\fR -statements\&. -.PP -Each -\fIedit\fR -transform string (non\-date) option value is either a plain string (which is taken literally) or a -\fI+\fR\-separated list of directives (whose expansions are concatenated with double\-linebreak separators, i\&.e\&. each directive results in one or more paragraphs)\&. -.PP -Each directive is either of the form -\fI@filename\fR -(which is replaced with the contents of the file; there is no search path; trailing whitespace is discarded) or of the form -\fI%keyword\fR\&. Any unrecognized directives are treated as plain strings\&. The following -\fI%\fR\-directives are currently supported: -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -\fI%SUMMARY\fR -: This expands to a "summary" of the original argument value\&. It\*(Aqs intended for use with top\-level -\fIdescription\fR -statements that typically consist of a hand\-crafted summary followed by copyrights, license and other boiler\-plate text\&. The summary is the text up to but not including the first line that (ignoring leading and trailing whitespace) starts with the word -\fICopyright\fR -followed by a space\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -\fI%SUBST/old/new\fR -: This expands to the original argument value with all instances of -\fIold\fR -replaced with -\fInew\fR\&. There is no provision for replacing characters that contain forward slashes, and there is no terminating slash\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -\fI%DELETE\fR -: This clears the output buffer and suppresses a check that would normally prevent overwriting an existing value (unless that value is the literal string -\fBTBD\fR)\&. -.RE -.PP -In the examples given below, it\*(Aqs assumed that there are -\fICONTACT\fR, -\fICONTEXT\fR, -\fILICENSE\fR, -\fIORGANIZATION\fR, -\fIREFERENCE\fR -and -\fIREVISION\fR -files in a top\-level project directory (which in this case is the parent of the directory in which -\fBpyang\fR -is being run)\&. These examples illustrate how the -\fIedit\fR -transform might be used with the -\fIyang\fR -output format to prepare YANG files for publication\&. +.TP +\f[I]file\&...\f[R] +These are the names of the files containing the modules to be validated, +or the module to be converted. +.SH TRANSFORMATIONS +.PP +Installed \f[B]pyang\f[R] transformations are (like output formats) +plugins and therefore may define their own options, or add new +transformations to the \f[B]-t\f[R] option. +These options and transformations are listed in \f[B]pyang -h\f[R]. +.TP +\f[I]edit\f[R] +Modify the supplied module(s) in various ways. +This transform will usually be used with the \f[I]yang\f[R] output +format. +.SH EDIT TRANSFORM +.PP +The \f[I]edit\f[R] transform modifies the supplied module(s) in various +ways. +It can, for example, replace top-level \f[I]description\f[R] statements, +update \f[I]include\f[R] statements and manage \f[I]revision\f[R] +statements. +Unless otherwise noted below, it only modifies \f[I]existing\f[R] +statements. +.PP +Each \f[I]edit\f[R] transform string (non-date) option value is either a +plain string (which is taken literally) or a \f[I]+\f[R]-separated list +of directives (whose expansions are concatenated with double-linebreak +separators, i.e., each directive results in one or more paragraphs). +.PP +Each directive is either of the form \f[I]\[at]filename\f[R] (which is +replaced with the contents of the file; there is no search path; +trailing whitespace is discarded) or of the form \f[I]%keyword\f[R]. +Any unrecognized directives are treated as plain strings. +The following \f[I]%\f[R]-directives are currently supported: +.IP \[bu] 2 +\f[I]%SUMMARY\f[R] : This expands to a \[dq]summary\[dq] of the original +argument value. +It\[cq]s intended for use with top-level \f[I]description\f[R] +statements that typically consist of a hand-crafted summary followed by +copyrights, license and other boiler-plate text. +The summary is the text up to but not including the first line that +(ignoring leading and trailing whitespace) starts with the word +\f[I]Copyright\f[R] followed by a space. +.IP \[bu] 2 +\f[I]%SUBST/old/new\f[R] : This expands to the original argument value +with all instances of \f[I]old\f[R] replaced with \f[I]new\f[R]. +There is no provision for replacing characters that contain forward +slashes, and there is no terminating slash. +.IP \[bu] 2 +\f[I]%DELETE\f[R] : This clears the output buffer and suppresses a check +that would normally prevent overwriting an existing value (unless that +value is the literal string \f[B]TBD\f[R]). +.PP +In the examples given below, it\[cq]s assumed that there are +\f[I]CONTACT\f[R], \f[I]CONTEXT\f[R], \f[I]LICENSE\f[R], +\f[I]ORGANIZATION\f[R], \f[I]REFERENCE\f[R] and \f[I]REVISION\f[R] files +in a top-level project directory (which in this case is the parent of +the directory in which \f[B]pyang\f[R] is being run). +These examples illustrate how the \f[I]edit\f[R] transform might be used +with the \f[I]yang\f[R] output format to prepare YANG files for +publication. .PP Edit transform specific options: +.TP +\f[B]--edit-yang-version\f[R] \f[I]version\f[R] +Set the YANG version (i.e., the \f[I]yang-version\f[R] statement\[cq]s +argument) to \f[I]version\f[R]. +This does nothing if the YANG module doesn\[cq]t already have a +\f[I]yang-version\f[R] statement. +.RS +.PP +Example: \f[B]--edit-yang-version 1.1\f[R]. +.RE +.TP +\f[B]--edit-namespace\f[R] \f[I]namespace\f[R] +Set the YANG namespace (i.e., the \f[I]namespace\f[R] statement\[cq]s +argument) to \f[I]namespace\f[R]. +This does nothing if the YANG module doesn\[cq]t already have a +\f[I]namespace\f[R] statement. +.RS +.PP +Example: \f[B]--edit-namespace %SUBST/acme-pacific-org/apo\f[R] +.RE +.TP +\f[B]--edit-update-import-dates\f[R] +Update any \f[I]import\f[R] (or \f[I]include\f[R]) +\f[I]revision-date\f[R] statements to match imported (or included) +modules and submodules. +If there isn\[cq]t already a \f[I]revision-date\f[R] statement, it will +be added. +.TP +\f[B]--edit-delete-import-dates\f[R] +Delete any \f[I]import\f[R] (or \f[I]include\f[R]) +\f[I]revision-date\f[R] statements. +.TP +\f[B]--edit-organization\f[R] \f[I]organization\f[R] +Set the organization (i.e., the \f[I]organization\f[R] statement\[cq]s +argument) to \f[I]organization\f[R]. +This does nothing if the YANG module doesn\[cq]t already have an +\f[I]organization\f[R] statement. +.RS +.PP +Example: \f[B]--edit-organization \[at]../ORGANIZATION\f[R] +.RE +.TP +\f[B]--edit-contact\f[R] \f[I]contact\f[R] +Set the contact info (i.e., the \f[I]contact\f[R] statement\[cq]s +argument) to \f[I]contact\f[R]. +This does nothing if the YANG module doesn\[cq]t already have a +\f[I]contact\f[R] statement. +.RS +.PP +Example: \f[B]--edit-contact \[at]../CONTACT\f[R] +.RE +.TP +\f[B]--edit-description\f[R] \f[I]description\f[R] +Set the top-level description (i.e., the top-level \f[I]description\f[R] +statement\[cq]s argument) to \f[I]description\f[R]. +This does nothing if the YANG module doesn\[cq]t already have a +\f[I]description\f[R] statement. +.RS +.PP +Example: \f[B]--edit-description +%SUMMARY+\[at]../LICENSE+\[at]../CONTEXT\f[R] +.RE +.TP +\f[B]--edit-delete-revisions-after\f[R] \f[I]prevdate\f[R] +Delete any \f[I]revision\f[R] statements after (i.e., that are more +recent than) the supplied \f[I]yyyy-mm-dd\f[R] revision date. +A typical use case is to supply the date of the previous release: any +revisions since then will be internal (e.g., developers often feel that +they should add revision statements for git commits) and are not wanted +in the next released version. +.RS +.PP +Example: \f[B]--edit-delete-revisions-after 2019-03-15\f[R] +.RE +.TP +\f[B]--edit-revision-date\f[R] \f[I]date\f[R] +Set the most recent revision date to the supplied \f[I]yyyy-mm-dd\f[R] +revision date. +This does nothing if the YANG module doesn\[cq]t already have at least +one \f[I]revision\f[R] statement. +If necessary, a new \f[I]revision\f[R] statement will be inserted before +any (remaining) existing revisions. +.RS +.PP +Example: \f[B]--edit-revision-date 2020-03-15\f[R] +.RE +.TP +\f[B]--edit-revision-description\f[R] \f[I]description\f[R] +Set the most recent revision description to \f[I]description\f[R]. +.RS +.PP +Example: \f[B]--edit-revision-description=%DELETE+\[at]../REVISION\f[R] +.RE +.TP +\f[B]--edit-revision-reference\f[R] \f[I]reference\f[R] +Set the most recent revision reference to \f[I]reference\f[R]. +.RS +.PP +Example: \f[B]--edit-revision-reference=%DELETE+\[at]../REFERENCE\f[R] +.RE +.SH OUTPUT FORMATS +.PP +Installed \f[B]pyang\f[R] plugins may define their own options, or add +new formats to the \f[B]-f\f[R] option. +These options and formats are listed in \f[B]pyang -h\f[R]. +.TP +\f[I]capability\f[R] +Capability URIs for each module of the data model. +.TP +\f[I]depend\f[R] +Makefile dependency rule for the module. +.TP +\f[I]dsdl\f[R] +Hybrid DSDL schema, see \f[B]RFC 6110\f[R]. +.TP +\f[I]identifiers\f[R] +All identifiers in the module. +.TP +\f[I]jsonxsl\f[R] +XSLT stylesheet for transforming XML instance documents to JSON. +.TP +\f[I]jstree\f[R] +HTML/JavaScript tree navigator. +.TP +\f[I]jtox\f[R] +Driver file for transforming JSON instance documents to XML. +.TP +\f[I]name\f[R] +Module name, and the name of the main module for a submodule. +.TP +\f[I]omni\f[R] +An applescript file that draws a diagram in \f[B]OmniGraffle\f[R]. +.TP +\f[I]sample-xml-skeleton\f[R] +Skeleton of a sample XML instance document. +.TP +\f[I]tree\f[R] +Tree structure of the module. +.TP +\f[I]flatten\f[R] +Print the schema nodes in CSV form. +.TP +\f[I]uml\f[R] +UML file that can be read by \f[B]plantuml\f[R] to generate UML +diagrams. +.TP +\f[I]yang\f[R] +Normal YANG syntax. +.TP +\f[I]yin\f[R] +The XML syntax of YANG. +.SH LINT CHECKER +.PP +The \f[I]lint\f[R] option validates that the module follows the generic +conventions and rules given in \f[B]RFC 8407\f[R]. +In addition, it checks that the module is in canonical order. +.PP +Options for the \f[I]lint\f[R] checker: +.TP +\f[B]--lint-namespace-prefix\f[R] \f[I]prefix\f[R] +Validate that the module\[cq]s namespace is of the form: +\[dq]\[dq]. +.TP +\f[B]--lint-modulename-prefix\f[R] \f[I]prefix\f[R] +Validate that the module\[cq]s name starts with \f[I]prefix\f[R]. +.TP +\f[B]--lint-ensure-hyphenated-names\f[R] +Validate that all identifiers use hyphenated style, i.e., no uppercase +letters or underscores. +.SH YANG SCHEMA ITEM IDENTIFIERS (SID) +.PP +YANG Schema Item iDentifiers (SID) are globally unique unsigned integers +used to identify YANG items. +SIDs are used instead of names to save space in constrained applications +such as COREconf. +This plugin is used to automatically generate and updated .sid files +used to persist and distribute SID assignments. +.PP +Options for generating, updating and checking .sid files: +.TP +\f[B]--sid-generate-file\f[R] +This option is used to generate a new .sid file from a YANG module. +.RS +.PP +Two arguments are required to generate a .sid file; the SID range +assigned to the YANG module and its definition file. +The SID range specified is a sub-range within a range obtained from a +registrar or a sub-range within the experimental range (i.e., 60000 to +99999). +The SID range consists of the first SID of the range, followed by a +colon, followed by the number of SID allocated to the YANG module. +The filename consists of the module name, followed by an \[at] symbol, +followed by the module revision, followed by the \[dq].yang\[dq] +extension. .PP -\fB\-\-edit\-yang\-version\fR \fIversion\fR -.RS 4 -Set the YANG version (i\&.e\&., the -\fIyang\-version\fR -statement\*(Aqs argument) to -\fIversion\fR\&. This does nothing if the YANG module doesn\*(Aqt already have a -\fIyang\-version\fR -statement\&. -.sp -Example: -\fB\-\-edit\-yang\-version 1\&.1\fR\&. -.RE -.PP -\fB\-\-edit\-namespace\fR \fInamespace\fR -.RS 4 -Set the YANG namespace (i\&.e\&., the -\fInamespace\fR -statement\*(Aqs argument) to -\fInamespace\fR\&. This does nothing if the YANG module doesn\*(Aqt already have a -\fInamespace\fR -statement\&. -.sp -Example: -\fB\-\-edit\-namespace %SUBST/acme\-pacific\-org/apo\fR -.RE -.PP -\fB\-\-edit\-update\-import\-dates\fR -.RS 4 -Update any -\fIimport\fR -(or -\fIinclude\fR) -\fIrevision\-date\fR -statements to match imported (or included) modules and submodules\&. If there isn\*(Aqt already a -\fIrevision\-date\fR -statement, it will be added\&. -.RE -.PP -\fB\-\-edit\-delete\-import\-dates\fR -.RS 4 -Delete any -\fIimport\fR -(or -\fIinclude\fR) -\fIrevision\-date\fR -statements\&. -.RE -.PP -\fB\-\-edit\-organization\fR \fIorganization\fR -.RS 4 -Set the organization (i\&.e\&. the -\fIorganization\fR -statement\*(Aqs argument) to -\fIorganization\fR\&. This does nothing if the YANG module doesn\*(Aqt already have an -\fIorganization\fR -statement\&. -.sp -Example: -\fB\-\-edit\-organization @\&.\&./ORGANIZATION\fR -.RE -.PP -\fB\-\-edit\-contact\fR \fIcontact\fR -.RS 4 -Set the contact info (i\&.e\&. the -\fIcontact\fR -statement\*(Aqs argument) to -\fIcontact\fR\&. This does nothing if the YANG module doesn\*(Aqt already have a -\fIcontact\fR -statement\&. -.sp -Example: -\fB\-\-edit\-contact @\&.\&./CONTACT\fR -.RE -.PP -\fB\-\-edit\-description\fR \fIdescription\fR -.RS 4 -Set the top\-level description (i\&.e\&. the top\-level -\fIdescription\fR -statement\*(Aqs argument) to -\fIdescription\fR\&. This does nothing if the YANG module doesn\*(Aqt already have a -\fIdescription\fR -statement\&. -.sp -Example: -\fB\-\-edit\-description %SUMMARY+@\&.\&./LICENSE+@\&.\&./CONTEXT\fR -.RE -.PP -\fB\-\-edit\-delete\-revisions\-after\fR \fIprevdate\fR -.RS 4 -Delete any -\fIrevision\fR -statements after (i\&.e\&. that are more recent than) the supplied -\fIyyyy\-mm\-dd\fR -revision date\&. A typical use case is to supply the date of the previous release: any revisions since then will be internal (e\&.g\&. developers often feel that they should add revision statements for git commits) and are not wanted in the next released version\&. -.sp -Example: -\fB\-\-edit\-delete\-revisions\-after 2019\-03\-15\fR -.RE -.PP -\fB\-\-edit\-revision\-date\fR \fIdate\fR -.RS 4 -Set the most recent revision date to the supplied -\fIyyyy\-mm\-dd\fR -revision date\&. This does nothing if the YANG module doesn\*(Aqt already have at least one -\fIrevision\fR -statement\&. If necessary, a new -\fIrevision\fR -statement will be inserted before any (remaining) existing revisions\&. -.sp -Example: -\fB\-\-edit\-revision\-date 2020\-03\-15\fR -.RE -.PP -\fB\-\-edit\-revision\-description\fR \fIdescription\fR -.RS 4 -Set the most recent revision description to -\fIdescription\fR\&. -.sp -Example: -\fB\-\-edit\-revision\-description=%DELETE+@\&.\&./REVISION\fR -.RE -.PP -\fB\-\-edit\-revision\-reference\fR \fIreference\fR -.RS 4 -Set the most recent revision reference to -\fIreference\fR\&. -.sp -Example: -\fB\-\-edit\-revision\-reference=%DELETE+@\&.\&./REFERENCE\fR -.RE -.SH "OUTPUT FORMATS" -.PP -Installed -\fBpyang\fR -plugins may define their own options, or add new formats to the -\fB\-f\fR -option\&. These options and formats are listed in -\fBpyang \-h\fR\&. -.PP -\fIcapability\fR -.RS 4 -Capability URIs for each module of the data model\&. -.RE -.PP -\fIdepend\fR -.RS 4 -Makefile dependency rule for the module\&. -.RE -.PP -\fIdsdl\fR -.RS 4 -Hybrid DSDL schema, see -\m[blue]\fBRFC 6110\fR\m[]\&\s-2\u[4]\d\s+2\&. -.RE -.PP -\fIidentifiers\fR -.RS 4 -All identifiers in the module\&. -.RE -.PP -\fIjsonxsl\fR -.RS 4 -XSLT stylesheet for transforming XML instance documents to JSON\&. -.RE -.PP -\fIjstree\fR -.RS 4 -HTML/JavaScript tree navigator\&. -.RE -.PP -\fIjtox\fR -.RS 4 -Driver file for transforming JSON instance documents to XML\&. -.RE -.PP -\fIname\fR -.RS 4 -Module name, and the name of the main module for a submodule\&. -.RE -.PP -\fIomni\fR -.RS 4 -An applescript file that draws a diagram in -\fBOmniGraffle\fR\&. -.RE -.PP -\fIsample\-xml\-skeleton\fR -.RS 4 -Skeleton of a sample XML instance document\&. -.RE -.PP -\fItree\fR -.RS 4 -Tree structure of the module\&. -.RE -.PP -\fIflatten\fR -.RS 4 -Print the schema nodes in CSV form\&. -.RE -.PP -\fIuml\fR -.RS 4 -UML file that can be read by -\fBplantuml\fR -to generate UML diagrams\&. -.RE -.PP -\fIyang\fR -.RS 4 -Normal YANG syntax\&. -.RE -.PP -\fIyin\fR -.RS 4 -The XML syntax of YANG\&. -.RE -.SH "LINT CHECKER" -.PP -The -\fIlint\fR -option validates that the module follows the generic conventions and rules given in -\m[blue]\fBRFC 8407\fR\m[]\&\s-2\u[5]\d\s+2\&. In addition, it checks that the module is in canonical order\&. -.PP -Options for the -\fIlint\fR -checker: -.PP -\fB\-\-lint\-namespace\-prefix\fR \fIprefix\fR -.RS 4 -Validate that the module\*(Aqs namespace is of the form: ""\&. -.RE -.PP -\fB\-\-lint\-modulename\-prefix\fR \fIprefix\fR -.RS 4 -Validate that the module\*(Aqs name starts with -\fIprefix\fR\&. -.RE -.PP -\fB\-\-lint\-ensure\-hyphenated\-names\fR -.RS 4 -Validate that all identifiers use hyphenated style, i\&.e\&., no uppercase letters or underscores\&. -.RE -.SH "YANG SCHEMA ITEM IDENTIFIERS (SID)" -.PP -YANG Schema Item iDentifiers (SID) are globally unique unsigned integers used to identify YANG items\&. SIDs are used instead of names to save space in constrained applications such as COREconf\&. This plugin is used to automatically generate and updated \&.sid files used to persist and distribute SID assignments\&. -.PP -Options for generating, updating and checking \&.sid files: -.PP -\fB\-\-sid\-generate\-file\fR -.RS 4 -This option is used to generate a new \&.sid file from a YANG module\&. -.sp -Two arguments are required to generate a \&.sid file; the SID range assigned to the YANG module and its definition file\&. The SID range specified is a sub\-range within a range obtained from a registrar or a sub\-range within the experimental range (i\&.e\&. 60000 to 99999)\&. The SID range consists of the first SID of the range, followed by a colon, followed by the number of SID allocated to the YANG module\&. The filename consists of the module name, followed by an @ symbol, followed by the module revision, followed by the "\&.yang" extension\&. -.sp This example shows how to generate the file -\fItoaster@2009\-11\-20\&.sid\fR\&. -.sp -.if n \{\ -.RS 4 -.\} +\f[I]toaster\[at]2009-11-20.sid\f[R]. +.IP .nf -$ pyang \-\-sid\-generate\-file 20000:100 toaster@2009\-11\-20\&.yang +\f[C] +$ pyang --sid-generate-file 20000:100 toaster\[at]2009-11-20.yang +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]--sid-update-file\f[R] +Each time new items are added to a YANG module by the introduction of a +new revision of this module, its included sub-modules or imported +modules, the associated .sid file need to be updated. +This is done by using the \f[B]--sid-update-file\f[R] option. +.RS +.PP +Two arguments are required to generate a .sid file for an updated YANG +module; the previous .sid file generated for the YANG module and the +definition file of the updated module. +Both filenames follow the usual naming conversion consisting of the +module name, followed by an \[at] symbol, followed by the module +revision, followed by the extension. .PP -\fB\-\-sid\-update\-file\fR -.RS 4 -Each time new items are added to a YANG module by the introduction of a new revision of this module, its included sub\-modules or imported modules, the associated \&.sid file need to be updated\&. This is done by using the -\fB\-\-sid\-update\-file\fR -option\&. -.sp -Two arguments are required to generate a \&.sid file for an updated YANG module; the previous \&.sid file generated for the YANG module and the definition file of the updated module\&. Both filenames follow the usual naming conversion consisting of the module name, followed by an @ symbol, followed by the module revision, followed by the extension\&. -.sp This example shows how to generate the file -\fItoaster@2009\-12\-28\&.sid\fR -based on the SIDs already present in -\fItoaster@2009\-11\-20\&.sid\fR\&. -.sp -.if n \{\ -.RS 4 -.\} +\f[I]toaster\[at]2009-12-28.sid\f[R] based on the SIDs already present +in \f[I]toaster\[at]2009-11-20.sid\f[R]. +.IP .nf -$ pyang \-\-sid\-update\-file toaster@2009\-11\-20\&.sid \e -toaster@2009\-12\-28\&.yang +\f[C] +$ pyang --sid-update-file toaster\[at]2009-11-20.sid \[rs] + toaster\[at]2009-12-28.yang +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]--sid-check-file\f[R] +The \f[B]--sid-check-file\f[R] option can be used at any time to verify +if a .sid file need to be updated. +.RS +.PP +Two arguments are required to verify a .sid file; the filename of the +\&.sid file to be checked and the corresponding definition file. .PP -\fB\-\-sid\-check\-file\fR -.RS 4 -The -\fB\-\-sid\-check\-file\fR -option can be used at any time to verify if a \&.sid file need to be updated\&. -.sp -Two arguments are required to verify a \&.sid file; the filename of the \&.sid file to be checked and the corresponding definition file\&. -.sp For example: -.sp -.if n \{\ -.RS 4 -.\} +.IP .nf -$ pyang \-\-sid\-check\-file toaster@2009\-12\-28\&.sid \e -toaster@2009\-12\-28\&.yang +\f[C] +$ pyang --sid-check-file toaster\[at]2009-12-28.sid \[rs] + toaster\[at]2009-12-28.yang +\f[R] .fi -.if n \{\ -.RE -.\} .RE -.PP -\fB\-\-sid\-list\fR -.RS 4 -The -\fB\-\-sid\-list\fR -option can be used before any of the previous options to obtains the list of SIDs assigned or validated\&. For example: -.sp -.if n \{\ -.RS 4 -.\} +.TP +\f[B]--sid-list\f[R] +The \f[B]--sid-list\f[R] option can be used before any of the previous +options to obtains the list of SIDs assigned or validated. +For example: +.RS +.IP .nf -$ pyang \-\-sid\-list \-\-sid\-generate\-file 20000:100 \e -toaster@2009\-11\-20\&.yang +\f[C] +$ pyang --sid-list --sid-generate-file 20000:100 \[rs] + toaster\[at]2009-11-20.yang +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[B]--sid-extra-range\f[R] +If needed, an extra SID range can be assigned to an existing YANG module +during its update with the \f[B]--sid-extra-range\f[R] option. +.RS .PP -\fB\-\-sid\-extra\-range\fR -.RS 4 -If needed, an extra SID range can be assigned to an existing YANG module during its update with the -\fB\-\-sid\-extra\-range\fR -option\&. -.sp For example, this command generates the file -\fItoaster@2009\-12\-28\&.sid\fR -using the initial range(s) present in -\fItoaster@2009\-11\-20\&.sid\fR -and the extra range specified in the command line\&. -.sp -.if n \{\ -.RS 4 -.\} +\f[I]toaster\[at]2009-12-28.sid\f[R] using the initial range(s) present +in \f[I]toaster\[at]2009-11-20.sid\f[R] and the extra range specified in +the command line. +.IP .nf -$ pyang \-\-sid\-update\-file toaster@2009\-11\-20\&.sid \e -toaster@2009\-12\-28\&.yang \-\-sid\-extra\-range 20100:100 +\f[C] +$ pyang --sid-update-file toaster\[at]2009-11-20.sid \[rs] + toaster\[at]2009-12-28.yang --sid-extra-range 20100:100 +\f[R] .fi -.if n \{\ -.RE -.\} .RE +.TP +\f[I]count\f[R] +The number of SID required when generating or updating a .sid file can +be computed by specifying \[dq]\f[I]count\f[R]\[dq] as SID range. +.RS .PP -\fIcount\fR -.RS 4 -The number of SID required when generating or updating a \&.sid file can be computed by specifying "\fIcount\fR" as SID range\&. -.sp For example: -.sp -.if n \{\ -.RS 4 -.\} +.IP .nf -$ pyang \-\-sid\-generate\-file count toaster@2009\-11\-20\&.yang +\f[C] +$ pyang --sid-generate-file count \[rs] + toaster\[at]2009-11-20.yang +\f[R] .fi -.if n \{\ -.RE -.\} +.PP or: -.sp -.if n \{\ -.RS 4 -.\} +.IP .nf -$ pyang \-\-sid\-update\-file toaster@2009\-11\-20\&.sid \e -toaster@2009\-12\-28\&.yang \-\-sid\-extra\-range count +\f[C] +$ pyang --sid-update-file toaster\[at]2009-11-20.sid \[rs] + toaster\[at]2009-12-28.yang --sid-extra-range count +\f[R] .fi -.if n \{\ -.RE -.\} -.RE -.SH "CAPABILITY OUTPUT" -.PP -The -\fIcapability\fR -output prints a capability URL for each module of the input data model, taking into account features and deviations, as described in section 5\&.6\&.4 of -\m[blue]\fBRFC 6020\fR\m[]\&\s-2\u[2]\d\s+2\&. -.PP -Options for the -\fIcapability\fR -output format: -.PP -\fB\-\-capability\-entity\fR -.RS 4 -Write ampersands in the output as XML entities ("&")\&. .RE -.SH "DEPEND OUTPUT" -.PP -The -\fIdepend\fR -output generates a Makefile dependency rule for files based on a YANG module\&. This is useful if files are generated from the module\&. For example, suppose a \&.c file is generated from each YANG module\&. If the YANG module imports other modules, or includes submodules, the \&.c file needs to be regenerated if any of the imported or included modules change\&. Such a dependency rule can be generated like this: -.sp -.if n \{\ -.RS 4 -.\} +.SH CAPABILITY OUTPUT> +.PP +The \f[I]capability\f[R] output prints a capability URL for each module +of the input data model, taking into account features and deviations, as +described in section 5.6.4 of \f[B]RFC 6020\f[R]. +.PP +Options for the \f[I]capability\f[R] output format: +.TP +\f[B]--capability-entity\f[R] +Write ampersands in the output as XML entities (\[dq]&\[dq]). +.SH DEPEND OUTPUT +.PP +The \f[I]depend\f[R] output generates a Makefile dependency rule for +files based on a YANG module. +This is useful if files are generated from the module. +For example, suppose a .c file is generated from each YANG module. +If the YANG module imports other modules, or includes submodules, the .c +file needs to be regenerated if any of the imported or included modules +change. +Such a dependency rule can be generated like this: +.IP .nf -$ pyang \-f depend \-\-depend\-target mymod\&.c \e - \-\-depend\-extension \&.yang mymod\&.yang - mymod\&.c : ietf\-yang\-types\&.yang my\-types\&.yang +\f[C] +$ pyang -f depend --depend-target mymod.c \[rs] + --depend-extension .yang mymod.yang +mymod.c : ietf-yang-types.yang my-types.yang +\f[R] .fi -.if n \{\ -.RE -.\} -.PP -Options for the -\fIdepend\fR -output format: -.PP -\fB\-\-depend\-target\fR -.RS 4 -Makefile rule target\&. Default is the module name\&. -.RE -.PP -\fB\-\-depend\-extension\fR -.RS 4 -YANG module file name extension\&. Default is no extension\&. -.RE -.PP -\fB\-\-depend\-no\-submodules\fR -.RS 4 -Do not generate dependencies for included submodules\&. -.RE -.PP -\fB\-\-depend\-from\-submodules\fR -.RS 4 -Generate dependencies taken from all included submodules\&. -.RE .PP -\fB\-\-depend\-recurse\fR -.RS 4 -Recurse into imported modules and generate dependencies for their imported modules etc\&. -.RE -.PP -\fB\-\-depend\-include\-path\fR -.RS 4 -Include file path in the prerequisites\&. Note that if no -\fB\-\-depend\-extension\fR -has been given, the prerequisite is the filename as found, i\&.e\&., ending in "\&.yang" or "\&.yin"\&. -.RE -.PP -\fB\-\-depend\-ignore\-module\fR -.RS 4 -Name of YANG module or submodule to ignore in the prerequisites\&. This option can be given multiple times\&. -.RE -.SH "DSDL OUTPUT" -.PP -The -\fIdsdl\fR -output takes a data model consisting of one or more YANG modules and generates a hybrid DSDL schema as described in -\m[blue]\fBRFC 6110\fR\m[]\&\s-2\u[4]\d\s+2\&. The hybrid schema is primarily intended as an interim product used by -\fByang2dsdl\fR(1)\&. -.PP -The -\fIdsdl\fR -plugin also supports metadata annotations, if they are defined and used as described in -\m[blue]\fBRFC 7952\fR\m[]\&\s-2\u[8]\d\s+2\&. -.PP -Options for the -\fIdsdl\fR -output format: -.PP -\fB\-\-dsdl\-no\-documentation\fR -.RS 4 -Do not print documentation annotations -.RE -.PP -\fB\-\-dsdl\-no\-dublin\-core\fR -.RS 4 +Options for the \f[I]depend\f[R] output format: +.TP +\f[B]--depend-target\f[R] +Makefile rule target. +Default is the module name. +.TP +\f[B]--depend-extension\f[R] +YANG module file name extension. +Default is no extension. +.TP +\f[B]--depend-no-submodules\f[R] +Do not generate dependencies for included submodules. +.TP +\f[B]--depend-from-submodules\f[R] +Generate dependencies taken from all included submodules. +.TP +\f[B]--depend-recurse\f[R] +Recurse into imported modules and generate dependencies for their +imported modules etc. +.TP +\f[B]--depend-include-path\f[R] +Include file path in the prerequisites. +Note that if no \f[B]--depend-extension\f[R] has been given, the +prerequisite is the filename as found, i.e., ending in \[dq].yang\[dq] +or \[dq].yin\[dq]. +.TP +\f[B]--depend-ignore-module\f[R] +Name of YANG module or submodule to ignore in the prerequisites. +This option can be given multiple times. +.SH DSDL Output +.PP +The \f[I]dsdl\f[R] output takes a data model consisting of one or more +YANG modules and generates a hybrid DSDL schema as described in \f[B]RFC +6110\f[R]. +The hybrid schema is primarily intended as an interim product used by +\f[B]yang2dsdl\f[R](1). +.PP +The \f[I]dsdl\f[R] plugin also supports metadata annotations, if they +are defined and used as described in \f[B]RFC 7952\f[R]. +.PP +Options for the \f[I]dsdl\f[R] output format: +.TP +\f[B]--dsdl-no-documentation\f[R] Do not print Dublin Core metadata terms -.RE -.PP -\fB\-\-dsdl\-record\-defs\fR -.RS 4 -Record translations of all top\-level typedefs and groupings in the output schema, even if they are not used\&. This is useful for translating library modules\&. -.RE -.SH "JSONXSL OUTPUT" -.PP -The -\fIjsonxsl\fR -output generates an XSLT 1\&.0 stylesheet that can be used for transforming an XML instance document into JSON text as specified in -\m[blue]\fBRFC 7951\fR\m[]\&\s-2\u[9]\d\s+2\&. The XML document must be a valid instance of the data model which is specified as one or more input YANG modules on the command line (or via a message, see the -\fB\-\-hello\fR -option)\&. -.PP -The -\fIjsonxsl\fR -plugin also converts metadata annotations, if they are defined and used as described in -\m[blue]\fBRFC 7952\fR\m[]\&\s-2\u[8]\d\s+2\&. -.PP -The data tree(s) must be wrapped at least in either or element, where "nc" is the namespace prefix for the standard NETCONF URI "urn:ietf:params:xml:ns:netconf:base:1\&.0", or the XML instance document has to be a complete NETCONF RPC request/reply or notification\&. Translation of RPCs and notifications defined by the data model is also supported\&. -.PP -The generated stylesheet accepts the following parameters that modify its behaviour: -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -\fIcompact\fR: setting this parameter to 1 results in a compact representation of the JSON text, i\&.e\&. without any whitespace\&. The default is 0 which means that the JSON output is pretty\-printed\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -\fIind\-step\fR: indentation step, i\&.e\&. the number of spaces to use for each level\&. The default value is 2 spaces\&. Note that this setting is only useful for pretty\-printed output (compact=0)\&. -.RE -.PP -The stylesheet also includes the file -jsonxsl\-templates\&.xsl -which is a part of -\fBpyang\fR -distribution\&. -.SH "JSTREE OUTPUT" -.PP -The -\fIjstree\fR -output grenerates an HTML/JavaScript page that presents a tree\-navigator to the given YANG module(s)\&. +.TP +\f[B]--dsdl-record-defs\f[R] +Record translations of all top-level typedefs and groupings in the +output schema, even if they are not used. +This is useful for translating library modules. +.SH JSONXSL OUTPUT +.PP +The \f[I]jsonxsl\f[R] output generates an XSLT 1.0 stylesheet that can +be used for transforming an XML instance document into JSON text as +specified in \f[B]RFC 7951\f[R]. +The XML document must be a valid instance of the data model which is +specified as one or more input YANG modules on the command line (or via +a message, see the \f[B]--hello\f[R] option). +.PP +The \f[I]jsonxsl\f[R] plugin also converts metadata annotations, if they +are defined and used as described in \f[B]RFC 7952\f[R]. +.PP +The data tree(s) must be wrapped at least in either or + element, where \[dq]nc\[dq] is the namespace prefix for the +standard NETCONF URI \[dq]urn:ietf:params:xml:ns:netconf:base:1.0\[dq], +or the XML instance document has to be a complete NETCONF RPC +request/reply or notification. +Translation of RPCs and notifications defined by the data model is also +supported. +.PP +The generated stylesheet accepts the following parameters that modify +its behaviour: +.IP \[bu] 2 +\f[I]compact\f[R]: setting this parameter to 1 results in a compact +representation of the JSON text, i.e., without any whitespace. +The default is 0 which means that the JSON output is pretty-printed. +.IP \[bu] 2 +\f[I]ind-step\f[R]: indentation step, i.e., the number of spaces to use +for each level. +The default value is 2 spaces. +Note that this setting is only useful for pretty-printed output +(compact=0). +.PP +The stylesheet also includes the file \f[I]jsonxsl-templates.xsl\f[R] +which is a part of \f[B]pyang\f[R] distribution. +.SH JSTREE OUTPUT +.PP +The \f[I]jstree\f[R] output grenerates an HTML/JavaScript page that +presents a tree-navigator to the given YANG module(s). .PP jstree output specific option: -.PP -\fB\-\-jstree\-no\-path\fR -.RS 4 -Do not include paths in the output\&. This option makes the page less wide\&. -.RE -.SH "JTOX OUTPUT" -.PP -The -\fIjtox\fR -output generates a driver file which can be used as one of the inputs to -\fBjson2xml\fR -for transforming a JSON document to XML as specified in -\m[blue]\fBRFC 7951\fR\m[]\&\s-2\u[9]\d\s+2\&. -.PP -The -\fIjtox\fR -output itself is a JSON document containing a concise representation of the data model which is specified as one or more input YANG modules on the command line (or via a message, see the -\fB\-\-hello\fR -option)\&. -.PP -See -\fBjson2xml\fR -manual page for more information\&. -.SH "OMNI OUTPUT" -.PP -The plugin generates an applescript file that draws a diagram in OmniGraffle\&. Requires OmniGraffle 6\&. Usage: -.sp .if n \{\ .RS 4 .\} .nf $ pyang \-f omni foo\&.yang \-o foo\&.scpt $ osascript foo\&.scpt .fi .if n \{\ .RE .\} +.TP +\f[B]--jstree-no-path\f[R] +Do not include paths in the output. +This option makes the page less wide. +.SH JTOX OUTPUT +.PP +The \f[I]jtox\f[R] output generates a driver file which can be used as +one of the inputs to \f[B]json2xml\f[R] for transforming a JSON document +to XML as specified in \f[B]RFC 7951\f[R]. +.PP +The \f[I]jtox\f[R] output itself is a JSON document containing a concise +representation of the data model which is specified as one or more input +YANG modules on the command line (or via a message, see the +\f[B]--hello\f[R] option). +.PP +See \f[B]json2xml\f[R] manual page for more information. +.SH OMNI OUTPUT +.PP +The plugin generates an applescript file that draws a diagram in +OmniGraffle. +Requires OmniGraffle 6. +Usage: +.IP +.nf +\f[C] + $ pyang -f omni foo.yang -o foo.scpt + $ osascript foo.scpt +\f[R] +.fi .PP omni output specific option: -.PP -\fB\-\-omni\-path\fR \fIpath\fR -.RS 4 -Subtree to print\&. The -\fIpath\fR -is a slash ("/") separated path to a subtree to print\&. For example "/nacm/groups"\&. -.RE -.SH "NAME OUTPUT" -.PP -The -\fIname\fR -output prints the name of each module in the input data model\&. For submodules, it also shows the name of the main module to which the submodule belongs\&. +.TP +\f[B]--omni-path\f[R] \f[I]path\f[R] +Subtree to print. +The \f[I]path\f[R] is a slash (\[dq]/\[dq]) separated path to a subtree +to print. +For example \[dq]/nacm/groups\[dq]. +.SH NAME OUTPUT +.PP +The \f[I]name\f[R] output prints the name of each module in the input +data model. +For submodules, it also shows the name of the main module to which the +submodule belongs. .PP name output specific option: -.PP -\fB\-\-name\-print\-revision\fR -.RS 4 -Print the name and revision in name@revision format\&. -.RE -.SH "SAMPLE-XML-SKELETON OUTPUT" -.PP -The -\fIsample\-xml\-skeleton\fR -output generates an XML instance document with sample elements for all nodes in the data model, according to the following rules: -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -An element is present for every leaf, container or anyxml\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -At least one element is present for every leaf\-list or list\&. The number of entries in the sample is min(1, min\-elements)\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -For a choice node, sample element(s) are present for each case\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -Leaf, leaf\-list and anyxml elements are empty (but see the -\fB\-\-sample\-xml\-skeleton\-defaults\fR -option below)\&. -.RE -.PP -Note that the output document will most likely be invalid and needs manual editing\&. -.PP -Options specific to the -\fIsample\-xml\-skeleton\fR -output format: -.PP -\fB\-\-sample\-xml\-skeleton\-annotations\fR -.RS 4 -Add XML comments to the sample documents with hints about expected contents, for example types of leaf nodes, permitted number of list entries etc\&. -.RE -.PP -\fB\-\-sample\-xml\-skeleton\-defaults\fR -.RS 4 -Add leaf elements with defined defaults to the output with their default value\&. Without this option, the default elements are omitted\&. -.RE -.PP -\fB\-\-sample\-xml\-skeleton\-doctype=\fR\fB\fItype\fR\fR -.RS 4 -Type of the sample XML document\&. Supported values for -\fItype\fR -are -data -(default) and -config\&. This option determines the document element of the output XML document ( or in the NETCONF namespace) and also affects the contents: for -config, only data nodes representing configuration are included\&. -.RE -.PP -\fB\-\-sample\-xml\-skeleton\-path=\fR\fB\fIpath\fR\fR -.RS 4 -Subtree of the sample XML document to generate, including all ancestor elements\&. The -\fIpath\fR -is a slash ("/") separated list of data node names that specifies the path to a subtree to print\&. For example "/nacm/rule\-list/rule/rpc\-name"\&. -.RE -.SH "TREE OUTPUT" -.PP -The -\fItree\fR -output prints the resulting schema tree from one or more modules\&. Use -\fBpyang \-\-tree\-help\fR -to print a description on the symbols used by this format\&. +.TP +\f[B]--name-print-revision\f[R] +Print the name and revision in name\[at]revision format. +.SH SAMPLE-XML-SKELETON OUTPUT +.PP +The \f[I]sample-xml-skeleton\f[R] output generates an XML instance +document with sample elements for all nodes in the data model, according +to the following rules: +.IP \[bu] 2 +An element is present for every leaf, container or anyxml. +.IP \[bu] 2 +At least one element is present for every leaf-list or list. +The number of entries in the sample is min(1, +.IP \[bu] 2 +For a choice node, sample element(s) are present for each case. +.IP \[bu] 2 +Leaf, leaf-list and anyxml elements are empty (but see the +\f[B]--sample-xml-skeleton-defaults\f[R] option below). +.PP +Note that the output document will most likely be invalid and needs +manual editing. +.PP +Options specific to the \f[I]sample-xml-skeleton\f[R] output format: +.TP +\f[B]--sample-xml-skeleton-annotations\f[R] +Add XML comments to the sample documents with hints about expected +contents, for example types of leaf nodes, permitted number of list +entries etc. +.TP +\f[B]--sample-xml-skeleton-defaults\f[R] +Add leaf elements with defined defaults to the output with their default +value. +Without this option, the default elements are omitted. +.TP +\f[B]--sample-xml-skeleton-doctype=\f[R]_type_ +Type of the sample XML document. +Supported values for \f[I]type\f[R] are \f[B]data\f[R] (default) and +\f[B]config\f[R]. +This option determines the document element of the output XML document +( or in the NETCONF namespace) and also affects the +contents: for \f[B]config\f[R], only data nodes representing +configuration are included. +.TP +\f[B]--sample-xml-skeleton-path=\f[R]_path_ +Subtree of the sample XML document to generate, including all ancestor +elements. +The \f[I]path\f[R] is a slash (\[dq]/\[dq]) separated list of data node +names that specifies the path to a subtree to print. +For example \[dq]/nacm/rule-list/rule/rpc-name\[dq]. +.SH TREE OUTPUT +.PP +The \f[I]tree\f[R] output prints the resulting schema tree from one or +more modules. +Use \f[B]pyang --tree-help\f[R] to print a description on the symbols +used by this format. .PP Tree output specific options: -.PP -\fB\-\-tree\-help\fR -.RS 4 -Print help on symbols used in the tree output and exit\&. -.RE -.PP -\fB\-\-tree\-depth\fR \fIdepth\fR -.RS 4 -Levels of the tree to print\&. -.RE -.PP -\fB\-\-tree\-path\fR \fIpath\fR -.RS 4 -Subtree to print\&. The -\fIpath\fR -is a slash ("/") separated path to a subtree to print\&. For example "/nacm/groups"\&. All ancestors and the selected subtree are printed\&. -.RE -.PP -\fB\-\-tree\-print\-groupings\fR -.RS 4 -Print the top\-level groupings defined in the module\&. -.RE -.PP -\fB\-\-tree\-print\-structures\fR -.RS 4 -Print the ietf\-yang\-structure\-ext:structure structures defined in the module\&. -.RE -.PP -\fB\-\-tree\-print\-yang\-data\fR -.RS 4 -Print the ietf\-restconf:yang\-data structures defined in the module\&. -.RE -.PP -\fB\-\-tree\-line\-length\fR \fImaxlen\fR -.RS 4 -Try to break lines so they are no longer than -\fImaxlen\fR\&. This is a best effort algorithm\&. -.RE -.PP -\fB\-\-tree\-module\-name\-prefix\fR \fImaxlen\fR -.RS 4 -Use the module name (instead of the prefix) to prefix parameters and types\&. -.RE -.SH "FLATTEN OUTPUT" -.PP -The -\fIflatten\fR -output flattens provided YANG module and outputs the schema nodes and some of their properties in CSV format\&. +.TP +\f[B]--tree-help\f[R] +Print help on symbols used in the tree output and exit. +.TP +\f[B]--tree-depth\f[R] \f[I]depth\f[R] +Levels of the tree to print. +.TP +\f[B]--tree-path\f[R] \f[I]path\f[R] +Subtree to print. +The \f[I]path\f[R] is a slash (\[dq]/\[dq]) separated path to a subtree +to print. +For example \[dq]/nacm/groups\[dq]. +All ancestors and the selected subtree are printed. +.TP +\f[B]--tree-print-groupings\f[R] +Print the top-level groupings defined in the module. +.TP +\f[B]--tree-print-structures\f[R] +Print the ietf-yang-structure-ext:structure structures defined in the +module. +.TP +\f[B]--tree-print-yang-data\f[R] +Print the ietf-restconf:yang-data structures defined in the module. +.TP +\f[B]--tree-line-length\f[R] \f[I]maxlen\f[R] +Try to break lines so they are no longer than \f[I]maxlen\f[R]. +This is a best effort algorithm. +.TP +\f[B]--tree-module-name-prefix\f[R] \f[I]maxlen\f[R] +Use the module name (instead of the prefix) to prefix parameters and +types. +.SH FLATTEN OUTPUT +.PP +The \f[I]flatten\f[R] output flattens provided YANG module and outputs +the schema nodes and some of their properties in CSV format. .PP Flatten output specific options: -.PP -\fB\-\-flatten\-no\-header\fR -.RS 4 -Do not emit the CSV header\&. -.RE -.PP -\fB\-\-flatten\-keyword\fR -.RS 4 -Output the keyword\&. This will resolve as container, leaf, etc\&. -.RE -.PP -\fB\-\-flatten\-type\fR -.RS 4 -Output the top\-level type\&. This will resolve to a module\-prefixed type\&. -.RE -.PP -\fB\-\-flatten\-primitive\-type\fR -.RS 4 -Output the primitive type\&. This resolves to a YANG type such as uint64\&. -.RE -.PP -\fB\-\-flatten\-flag\fR -.RS 4 -Output flag property\&. Derives a flag \- for instance rw/ro for config, or x for RPC\&. -.RE -.PP -\fB\-\-flatten\-description\fR -.RS 4 -Output the description\&. -.RE -.PP -\fB\-\-flatten\-keys\fR -.RS 4 -Output whether the XPath is identified as a key\&. -\fIkey\fR -or null will be output per XPath\&. -.RE -.PP -\fB\-\-flatten\-keys\-in\-xpath\fR -.RS 4 -Output the XPath with keys in path\&. -.RE -.PP -\fB\-\-flatten\-prefix\-in\-xpath\fR -.RS 4 -Output the XPath with prefixes instead of modules\&. -.RE -.PP -\fB\-\-flatten\-qualified\-in\-xpath\fR -.RS 4 -Output the qualified XPath i\&.e\&. /module1:root/module1:node/module2:node/\&.\&.\&. -.RE -.PP -\fB\-\-flatten\-qualified\-module\-and\-prefix\-path\fR -.RS 4 -Output an XPath with both module and prefix i\&.e\&. /module1:prefix1:root/\&.\&.\&. This is -\fINOT\fR -a colloquial syntax of XPath\&. Emitted separately\&. -.RE -.PP -\fB\-\-flatten\-deviated\fR -.RS 4 -Output deviated nodes in the schema as well\&. -.RE -.PP -\fB\-\-flatten\-data\-keywords\fR -.RS 4 -Flatten all data keywords instead of only data definition keywords\&. -.RE -.PP -\fB\-\-flatten\-filter\-keyword\fR \fIkeyword\fR -.RS 4 -Filter output to only desired keywords\&. Keywords specified are what will be displayed in output\&. Can be specified more than once\&. -.RE -.PP -\fB\-\-flatten\-filter\-primitive\fR \fIprimitive_type\fR -.RS 4 -Filter output to only desired primitive types\&. Primitives specified are what will be displayed in output\&. Can be specified more than once\&. -.RE -.PP -\fB\-\-flatten\-filter\-flag\fR \fIchoice\fR -.RS 4 -Filter output to flag\&. -\fIrw\fR -for configuration data\&. -\fIro\fR -for non\-configuration data, output parameters to rpcs and actions, and notification parameters\&. -\fIw\fR -for input parameters to rpcs and actions\&. -\fIu\fR -for uses of a grouping\&. -\fIx\fR -for rpcs and actions\&. -\fIn\fR -for notifications\&. -.RE -.PP -\fB\-\-flatten\-csv\-dialect\fR \fIdialect\fR -.RS 4 -CSV dialect for output\&. excel | excel\-tab | unix -.RE -.PP -\fB\-\-flatten\-ignore\-no\-primitive\fR -.RS 4 -Ignore error if primitive is missing\&. -.RE -.PP -\fB\-\-flatten\-status\fR -.RS 4 -Output the status statement value\&. -.RE -.PP -\fB\-\-flatten\-resolve\-leafref\fR -.RS 4 -Output the XPath of the leafref target\&. -.RE -.SH "UML OUTPUT" -.PP -The -\fIuml\fR -output prints an output that can be used as input\-file to -\fBplantuml\fR -(http://plantuml\&.sourceforge\&.net) in order to generate a UML diagram\&. Note that it requires -\fBgraphviz\fR -(http://www\&.graphviz\&.org/)\&. -.PP -For large diagrams you may need to increase the Java heap\-size by the \-XmxSIZEm option, to java\&. For example: -\fBjava \-Xmx1024m \-jar plantuml\&.jar \&.\&.\&.\&.\fR -.PP -Options for the -\fIUML\fR -output format: -.PP -\fB\-\-uml\-classes\-only\fR -.RS 4 +.TP +\f[B]--flatten-no-header\f[R] +Do not emit the CSV header. +.TP +\f[B]--flatten-keyword\f[R] +Output the keyword. +This will resolve as container, leaf, etc. +.TP +\f[B]--flatten-type\f[R] +Output the top-level type. +This will resolve to a module-prefixed type. +.TP +\f[B]--flatten-primitive-type\f[R] +Output the primitive type. +This resolves to a YANG type such as uint64. +.TP +\f[B]--flatten-flag\f[R] +Output flag property. +Derives a flag - for instance rw/ro for config, or x for RPC. +.TP +\f[B]--flatten-description\f[R] +Output the description. +.TP +\f[B]--flatten-keys\f[R] +Output whether the XPath is identified as a key. +\f[I]key\f[R] or null will be output per XPath. +.TP +\f[B]--flatten-keys-in-xpath\f[R] +Output the XPath with keys in path. +.TP +\f[B]--flatten-prefix-in-xpath\f[R] +Output the XPath with prefixes instead of modules. +.TP +\f[B]--flatten-qualified-in-xpath\f[R] +Output the qualified XPath i.e., +/module1:root/module1:node/module2:node/\&... +.TP +\f[B]--flatten-qualified-module-and-prefix-path\f[R] +Output an XPath with both module and prefix i.e., +/module1:prefix1:root/\&... This is NOT a colloquial syntax of XPath. +Emitted separately. +.TP +\f[B]--flatten-deviated\f[R] +Flatten all data keywords instead of only data definition keywords. +.TP +\f[B]--flatten-filter-keyword\f[R] \f[I]keyword\f[R] +Filter output to only desired keywords. +Keywords specified are what will be displayed in output. +Can be specified more than once. +.TP +\f[B]--flatten-filter-primitive\f[R] \f[I]primitive_type\f[R] +Filter output to only desired primitive types. +Primitives specified are what will be displayed in output. +Can be specified more than once. +.TP +\f[B]--flatten-filter-flag\f[R] \f[I]choice\f[R] +Filter output to flag. +.RS +.IP \[bu] 2 +\f[I]rw\f[R] for configuration data. +.IP \[bu] 2 +\f[I]ro\f[R] for non-configuration data, output parameters to rpcs and +actions, and notification parameters. +.IP \[bu] 2 +\f[I]w\f[R] for input parameters to rpcs and actions. +.IP \[bu] 2 +\f[I]u\f[R] for uses of a grouping. +.IP \[bu] 2 +\f[I]x\f[R] for rpcs and actions. +.IP \[bu] 2 +\f[I]n\f[R] for notifications. +.RE +.TP +\f[B]--flatten-csv-dialect\f[R] \f[I]dialect\f[R] +CSV dialect for output. +\f[I]dialect\f[R] is one of \f[B]excel\f[R], \f[B]excel-tab\f[R], or +\f[B]unix\f[R]. +.TP +\f[B]--flatten-ignore-no-primitive\f[R] +Ignore error if primitive is missing. +.TP +\f[B]--flatten-status\f[R] +Output the status statement value. +.TP +\f[B]--flatten-resolve-leafref\f[R] +Output the XPath of the leafref target. +.SH UML OUTPUT +.PP +The \f[I]uml\f[R] output prints an output that can be used as input-file +to \f[B]plantuml\f[R] (http://plantuml.sourceforge.net) in order to +generate a UML diagram. +Note that it requires \f[B]graphviz\f[R] (http://www.graphviz.org/). +.PP +For large diagrams you may need to increase the Java heap-size by the +-XmxSIZEm option, to java. +For example: \f[B]java -Xmx1024m -jar plantuml.jar \&....\f[R] +.PP +Options for the \f[I]UML\f[R] output format: +.TP +\f[B]--uml-classes-only\f[R] Generate UML with classes only, no attributes -.RE -.PP -\fB\-\-uml\-split\-pages=\fR\fB\fIlayout\fR\fR -.RS 4 -Generate UML output split into pages, NxN, example 2x2\&. One \&.png file per page will be rendered\&. -.RE -.PP -\fB\-\-uml\-output\-directory=\fR\fB\fIdirectory\fR\fR -.RS 4 -Put the generated \&.png files(s) in the specified output directory\&. Default is "img/" -.RE -.PP -\fB\-\-uml\-title=\fR\fB\fItitle\fR\fR -.RS 4 -Set the title of the generated UML diagram, (default is YANG module name)\&. -.RE -.PP -\fB\-\-uml\-header=\fR\fB\fIheader\fR\fR -.RS 4 -Set the header of the generated UML diagram\&. -.RE -.PP -\fB\-\-uml\-footer=\fR\fB\fIfooter\fR\fR -.RS 4 -Set the footer of the generated UML diagram\&. -.RE -.PP -\fB\-\-uml\-long\-identifers\fR -.RS 4 -Use complete YANG schema identifiers for UML class names\&. -.RE -.PP -\fB\-\-uml\-no=\fR\fB\fIarglist\fR\fR -.RS 4 -This option suppresses specified arguments in the generated UML diagram\&. Valid arguments are: uses, leafref, identity, identityref, typedef, annotation, import, circles, stereotypes\&. Annotation suppresses YANG constructs rendered as annotations, examples module info, config statements for containers\&. Example \-\-uml\-no=circles,stereotypes,typedef,import -.RE -.PP -\fB\-\-uml\-truncate=\fR\fB\fIelemlist\fR\fR -.RS 4 -Leafref attributes and augment elements can have long paths making the classes too wide\&. This option will only show the tail of the path\&. Example \-\-uml\-truncate=augment,leafref\&. -.RE -.PP -\fB\-\-uml\-inline\-groupings\fR -.RS 4 -Render the diagram with groupings inlined\&. -.RE -.PP -\fB\-\-uml\-inline\-augments\fR -.RS 4 -Render the diagram with augments inlined\&. -.RE -.PP -\fB\-\-uml\-max\-enums=\fR\fB\fInumber\fR\fR -.RS 4 -Maximum of enum items rendered\&. -.RE -.PP -\fB\-\-uml\-filter\-file=\fR\fB\fIfile\fR\fR -.RS 4 -NOT IMPLEMENTED: Only paths in the filter file will be included in the diagram\&. A default filter file is generated by option \-\-filter\&. -.RE -.SH "YANG OUTPUT" -.PP -Options for the -\fIyang\fR -output format: -.PP -\fB\-\-yang\-canonical\fR -.RS 4 -Generate all statements in the canonical order\&. -.RE -.PP -\fB\-\-yang\-remove\-unused\-imports\fR -.RS 4 -Remove unused import statements from the output\&. -.RE -.PP -\fB\-\-yang\-remove\-comments\fR -.RS 4 -Remove all comments from the output\&. -.RE -.PP -\fB\-\-yang\-line\-length\fR \fIlen\fR -.RS 4 -Try to format each line with a maximum line length of -\fIlen\fR\&. Does not reformat long lines within strings\&. -.RE -.SH "YIN OUTPUT" -.PP -Options for the -\fIyin\fR -output format: -.PP -\fB\-\-yin\-canonical\fR -.RS 4 -Generate all statements in the canonical order\&. -.RE -.PP -\fB\-\-yin\-pretty\-strings\fR -.RS 4 -Pretty print strings, i\&.e\&. print with extra whitespace in the string\&. This is not strictly correct, since the whitespace is significant within the strings in XML, but the output is more readable\&. -.RE -.SH "YANG EXTENSIONS" -.PP -This section describes XPath functions that can be used in "must", "when", or "path" expressions in YANG modules, in addition to the core XPath 1\&.0 functions\&. -.PP -\fBpyang\fR -can be instructed to reject the usage of these functions with the parameter -\fI\-\-strict\fR\&. -.PP -\fBFunction:\fR\fInode\-set\fR\fBderef\fR(\fInode\-set\fR) -.PP -The -\fBderef\fR -function follows the reference defined by the first node in document order in the argument node\-set, and returns the nodes it refers to\&. -.PP -If the first argument node is an -\fBinstance\-identifier\fR, the function returns a node\-set that contains the single node that the instance identifier refers to, if it exists\&. If no such node exists, an empty node\-set is returned\&. -.PP -If the first argument node is a -\fBleafref\fR, the function returns a node\-set that contains the nodes that the leafref refers to\&. -.PP -If the first argument node is of any other type, an empty node\-set is returned\&. -.PP -The following example shows how a leafref can be written with and without the -\fBderef\fR -function: -.sp -.if n \{\ -.RS 4 -.\} +.TP +\f[B]--uml-split-pages=\f[R]_layout_ +Generate UML output split into pages, NxN, example 2x2. +One .png file per page will be rendered. +.TP +\f[B]--uml-output-directory=\f[R]_directory_ +Put the generated .png files(s) in the specified output directory. +Default is \[dq]img/\[dq] +.TP +\f[B]--uml-title=\f[R]_title_ +Set the title of the generated UML diagram, (default is YANG module +name). +.TP +\f[B]--uml-header=\f[R]_header_ +Set the header of the generated UML diagram. +.TP +\f[B]--uml-footer=\f[R]_footer_ +Set the footer of the generated UML diagram. +.TP +\f[B]--uml-long-identifers\f[R] +Use complete YANG schema identifiers for UML class names. +.TP +\f[B]--uml-no=\f[R]_arglist_ +Render the diagram with groupings inlined. +.TP +\f[B]--uml-inline-augments\f[R] +Render the diagram with augments inlined. +.TP +\f[B]--uml-max-enums=\f[BI]number\f[B]\f[R] +Maximum of enum items rendered. +.TP +\f[B]--uml-filter-file=\f[BI]file\f[B]\f[R] +NOT IMPLEMENTED: Only paths in the filter file will be included in the +diagram. +A default filter file is generated by option --filter. +.SH YANG OUTPUT +.PP +Options for the \f[I]yang\f[R] output format: +.TP +\f[B]--yang-canonical\f[R] +Generate all statements in the canonical order. +.TP +\f[B]--yang-remove-unused-imports\f[R] +Remove unused import statements from the output. +.TP +\f[B]--yang-remove-comments\f[R] +Remove all comments from the output. +.TP +\f[B]--yang-line-length\f[R] \f[I]len\f[R] +Try to format each line with a maximum line length of \f[I]len\f[R]. +Does not reformat long lines within strings. +.SH YIN OUTPUT +.PP +Options for the \f[I]yin\f[R] output format: +.TP +\f[B]--yin-canonical\f[R] +Generate all statements in the canonical order. +.TP +\f[B]--yin-pretty-strings\f[R] +Pretty print strings, i.e., print with extra whitespace in the string. +This is not strictly correct, since the whitespace is significant within +the strings in XML, but the output is more readable. +.SH YANG XPATH EXTENSIONS +.PP +This section describes XPath functions that can be used in +\[dq]must\[dq], \[dq]when\[dq], or \[dq]path\[dq] expressions in YANG +modules, in addition to the core XPath 1.0 functions. +.PP +\f[B]pyang\f[R] can be instructed to reject the usage of these functions +with the parameter \f[B]--strict\f[R]. +.TP +\f[B]Function:\f[R] \f[I]node-set\f[R] \f[B]deref\f[R](\f[I]node-set\f[R]) +The \f[B]deref\f[R] function follows the reference defined by the first +node in document order in the argument node-set, and returns the nodes +it refers to. +.RS +.PP +If the first argument node is an \f[B]instance-identifier\f[R], the +function returns a node-set that contains the single node that the +instance identifier refers to, if it exists. +If no such node exists, an empty node-set is returned. +.PP +If the first argument node is a \f[B]leafref\f[R], the function returns +a node-set that contains the nodes that the leafref refers to. +.PP +If the first argument node is of any other type, an empty node-set is +returned. +.PP +The following example shows how a leafref can be written with and +without the \f[B]deref\f[R] function: +.IP .nf +\f[C] /* without deref */ -leaf my\-ip { +leaf my-ip { type leafref { - path "/server/ip"; + path \[dq]/server/ip\[dq]; } } -leaf my\-port { +leaf my-port { type leafref { - path "/server[ip = current()/\&.\&./my\-ip]/port"; + path \[dq]/server[ip = current()/../my-ip]/port\[dq]; } } /* with deref */ -leaf my\-ip { +leaf my-ip { type leafref { - path "/server/ip"; + path \[dq]/server/ip\[dq]; } } -leaf my\-port { +leaf my-port { type leafref { - path "deref(\&.\&./my\-ip)/\&.\&./port"; + path \[dq]deref(../my-ip)/../port\[dq]; } } - +\f[R] .fi -.if n \{\ .RE -.\} -.SH "EXAMPLE" -.PP -The following example validates the standard YANG modules with derived types: -.sp -.if n \{\ -.RS 4 -.\} +.SH EXAMPLES +.PP +The following example validates the standard YANG modules with derived +types: +.IP .nf -$ pyang ietf\-yang\-types\&.yang ietf\-inet\-types\&.yang +\f[C] +$ pyang ietf-yang-types.yang ietf-inet-types.yang +\f[R] .fi -.if n \{\ -.RE -.\} .PP -The following example converts the ietf\-yang\-types module into YIN: -.sp -.if n \{\ -.RS 4 -.\} +The following example converts the ietf-yang-types module into YIN: +.IP .nf -$ pyang \-f yin \-o ietf\-yang\-types\&.yin ietf\-yang\-types\&.yang +\f[C] +$ pyang -f yin -o ietf-yang-types.yin ietf-yang-types.yang +\f[R] .fi -.if n \{\ -.RE -.\} .PP -The following example converts the ietf\-netconf\-monitoring module into a UML diagram: -.sp -.if n \{\ -.RS 4 -.\} +The following example converts the ietf-netconf-monitoring module into a +UML diagram: +.IP .nf - $ pyang \-f uml ietf\-netconf\-monitoring\&.yang > \e - ietf\-netconf\-monitoring\&.uml - $ java \-jar plantuml\&.jar ietf\-netconf\-monitoring\&.uml - $ open img/ietf\-netconf\-monitoring\&.png - +\f[C] +$ pyang -f uml ietf-netconf-monitoring.yang > \[rs] + ietf-netconf-monitoring.uml +$ java -jar plantuml.jar ietf-netconf-monitoring.uml +$ open img/ietf-netconf-monitoring.png +\f[R] .fi -.if n \{\ -.RE -.\} -.SH "ENVIRONMENT VARIABLES" -.PP -pyang searches for referred modules in the colon (:) separated path defined by the environment variable -\fB$YANG_MODPATH\fR -and in the directory -\fB$YANG_INSTALL\fR/yang/modules\&. -.PP -pyang searches for plugins in the colon (:) separated path defined by the environment variable -\fB$PYANG_PLUGINDIR\fR\&. -.SH "BUGS" -.sp -.RS 4 -.ie n \{\ -\h'-04' 1.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 1." 4.2 -.\} -The XPath arguments for the -\fImust\fR -and -\fIwhen\fR -statements are checked only for basic syntax errors\&. -.RE -.SH "AUTHORS" +.SH ENVIRONMENT VARIABLES .PP -\fBMartin Björklund\fR <\&mbj@tail\-f\&.com\&> -.br -Tail\-f Systems -.RS 4 -.RE +\f[B]pyang\f[R] searches for referred modules in the colon (:) separated +path defined by the environment variable \f[B]$YANG_MODPATH\f[R] and in +the directory \f[B]$YANG_INSTALL\f[R]/yang/modules. .PP -\fBLadislav Lhotka\fR <\&lhotka@nic\&.cz\&> -.br -CZ\&.NIC -.RS 4 -.RE +\f[B]pyang\f[R] searches for plugins in the colon (:) separated path +defined by the environment variable \f[B]$PYANG_PLUGINDIR\f[R]. +.SH BUGS .PP -\fBStefan Wallin\fR <\&stefan@tail\-f\&.com\&> -.br -Tail\-f Systems -.RS 4 -.RE -.SH "NOTES" -.IP " 1." 4 -RFC 6241 -.RS 4 -\%http://tools.ietf.org/html/rfc6241 -.RE -.IP " 2." 4 -RFC 6020 -.RS 4 -\%http://tools.ietf.org/html/rfc6020 -.RE -.IP " 3." 4 -RFC 7950 -.RS 4 -\%http://tools.ietf.org/html/rfc7950 -.RE -.IP " 4." 4 -RFC 6110 -.RS 4 -\%http://tools.ietf.org/html/rfc6110 -.RE -.IP " 5." 4 -RFC 8407 -.RS 4 -\%http://tools.ietf.org/html/rfc8407 -.RE -.IP " 6." 4 -RFC 2119 -.RS 4 -\%http://tools.ietf.org/html/rfc2119 -.RE -.IP " 7." 4 -RFC 8174 -.RS 4 -\%http://tools.ietf.org/html/rfc8174 -.RE -.IP " 8." 4 -RFC 7952 -.RS 4 -\%http://tools.ietf.org/html/rfc7952 -.RE -.IP " 9." 4 -RFC 7951 -.RS 4 -\%http://tools.ietf.org/html/rfc7951 -.RE +The XPath arguments for the \f[I]must\f[R] and \f[I]when\f[R] statements +are checked only for basic syntax errors. +.SH AUTHORS +.PP +See the file CONTRIBUTORS at https://github.com/mbj4668/pyang. diff --git a/man/man1/yang2dsdl.1 b/man/man1/yang2dsdl.1 index edcc0182..ee2c65a7 100644 --- a/man/man1/yang2dsdl.1 +++ b/man/man1/yang2dsdl.1 @@ -1,445 +1,273 @@ -'\" t -.\" Title: yang2dsdl -.\" Author: Ladislav Lhotka -.\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 2022-03-30 -.\" Manual: pyang manual -.\" Source: yang2dsdl-2.5.3 -.\" Language: English +.\" Automatically generated by Pandoc 2.9.2.1 .\" -.TH "YANG2DSDL" "1" "2022\-03\-30" "yang2dsdl\-2\&.5\&.3" "pyang manual" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -yang2dsdl \- translates YANG data models to DSDL schemas and validates instance documents\&. -.SH "SYNOPSIS" -.HP \w'\fByang2dsdl\fR\ 'u -\fByang2dsdl\fR [\-t\ \fItarget\fR] [\-d\ \fIdir\fR] [\-b\ \fIbasename\fR] [\-j] [\-x] [\-c] [\-v\ \fIinstance\fR] \fIfile\fR... -.HP \w'\fByang2dsdl\fR\ 'u -\fByang2dsdl\fR \-L [\-t\ \fItarget\fR] [\-d\ \fIdir\fR] [\-b\ \fIbasename\fR] [\-j] [\-x] [\-c] [\-v\ \fIinstance\fR] \fIfile\fR -.HP \w'\fByang2dsdl\fR\ 'u -\fByang2dsdl\fR \-s [\-t\ \fItarget\fR] [\-d\ \fIdir\fR] \-b\ \fIbasename\fR [\-j] [\-x] [\-c] \-v\ \fIinstance\fR -.HP \w'\fByang2dsdl\fR\ 'u -\fByang2dsdl\fR \-h -.SH "DESCRIPTION" -.PP -This shell script facilitates the translation of a data model described by one or more input YANG modules to DSDL schemas (RELAX NG, Schematron and DSRL) for a selected instance XML document type, as described in -\m[blue]\fBRFC\ \&6110\fR\m[]\&\s-2\u[1]\d\s+2\&. Optionally, the script can validate an instance document of the given type against the schemas\&. -.PP -The input YANG module(s) may be given either directly as -\fIfile\fR -parameter(s) on the command line, or indirectly through a server message which also declares capabilities and features supported by the server\&. The latter alternative is indicated by the -\fB\-L\fR -switch, and only one -\fIfile\fR -parameter may be given in this case\&. -.PP -Input YANG module(s) may be expressed in YANG or YIN syntax\&. The output DSDL schemas are written to the directory -\fIdir\fR -(current directory by default)\&. Unless the option -\fB\-s\fR -is used, this directory must be writable\&. -.PP -Metadata annotations are also supported, if they are defined and used as described in -\m[blue]\fBRFC\ \&7952\fR\m[]\&\s-2\u[2]\d\s+2\&. -.PP -The script can be executed by any shell interpreter compatible with POSIX\&.2, such as -\fBbash\fR(1) -or -\fBdash\fR(1)\&. -.PP -The -\fItarget\fR -argument specifies the type of the target instance document\&. Supported values are: -.PP +.TH "YANG2DSDL" "1" "2023-11-03" "yang2dsdl-2.6.0" "User Manual" +.hy +.SH NAME +.PP +yang2dsdl - translates YANG data models to DSDL schemas and validates +instance documents. +.SH SYNOPSIS +.PP +\f[B]yang2dsdl\f[R] [-t \f[I]target\f[R]] [-d \f[I]dir\f[R]] [-b +\f[I]basename\f[R]] [-j] [-x] [-c] [-v \f[I]instance\f[R]] +\f[I]file\f[R]\&... +.PP +\f[B]yang2dsdl\f[R] -L [-t \f[I]target\f[R]] [-d \f[I]dir\f[R]] [-b +\f[I]basename\f[R]] [-j] [-x] [-c] [-v \f[I]instance\f[R]] +\f[I]file\f[R]\&... +.PP +\f[B]yang2dsdl\f[R] -s [-t \f[I]target\f[R]] [-d \f[I]dir\f[R]] [-b +\f[I]basename\f[R]] [-j] [-x] [-c] [-v \f[I]instance\f[R]] +.PP +\f[B]yang2dsdl\f[R] -h +.SH DESCRIPTION +.PP +This shell script facilitates the translation of a data model described +by one or more input YANG modules to DSDL schemas (RELAX NG, Schematron +and DSRL) for a selected instance XML document type, as described in +\f[B]RFC\ 6110\f[R]. +Optionally, the script can validate an instance document of the given +type against the schemas. +.PP +The input YANG module(s) may be given either directly as \f[I]file\f[R] +parameter(s) on the command line, or indirectly through a server +message which also declares capabilities and features supported by the +server. +The latter alternative is indicated by the \f[B]-L\f[R] switch, and only +one \f[I]file\f[R] parameter may be given in this case. +.PP +Input YANG module(s) may be expressed in YANG or YIN syntax. +The output DSDL schemas are written to the directory \f[I]dir\f[R] +(current directory by default). +Unless the option \f[B]-s\f[R] is used, this directory must be writable. +.PP +Metadata annotations are also supported, if they are defined and used as +described in \f[B]RFC\ 7952\f[R]. +.PP +The script can be executed by any shell interpreter compatible with +POSIX.2, such as \f[B]bash\f[R](1) or \f[B]dash\f[R](1). +.PP +The \f[I]target\f[R] argument specifies the type of the target instance +document. +Supported values are: +.TP data -.RS 4 -Datastore contents (configuration and state data) encapsulated in document element\&. -.RE -.PP +Datastore contents (configuration and state data) encapsulated in + document element. +.TP config -.RS 4 -A configuration datastore contents encapsulated in document element\&. -.RE -.PP -get\-reply -.RS 4 -A complete NETCONF message containing a reply to the operation\&. -.RE -.PP -get\-data\-reply -.RS 4 -A complete NETCONF message containing a reply to the operation\&. -.RE -.PP -get\-config\-reply -.RS 4 -A complete NETCONF message containing a reply to the operation\&. -.RE -.PP -edit\-config -.RS 4 -A complete NETCONF message containing an request\&. Only the RELAX NG schema is generated for this target\&. -.RE -.PP +A configuration datastore contents encapsulated in document +element. +.TP +get-reply +A complete NETCONF message containing a reply to the operation. +.TP +get-data-reply +A complete NETCONF message containing a reply to the +operation. +.TP +get-config-reply +A complete NETCONF message containing a reply to the +operation. +.TP +edit-config +A complete NETCONF message containing an request. +Only the RELAX NG schema is generated for this target. +.TP rpc -.RS 4 -An RPC request defined in an input YANG module\&. -.RE -.PP -rpc\-reply -.RS 4 -An RPC reply defined in an input YANG module\&. -.RE -.PP +An RPC request defined in an input YANG module. +.TP +rpc-reply +An RPC reply defined in an input YANG module. +.TP notification -.RS 4 -An event notification defined in an input YANG module\&. -.RE -.PP -The output schemas are contained in the following four files whose names depend on the arguments -\fIbasename\fR -and -\fItarget\fR: -.PP -\fIbasename\fR\-\fItarget\fR\&.rng -.RS 4 -RELAX NG schema for the target document type\&. -.RE -.PP -\fIbasename\fR\-gdefs\-config\&.rng, \fIbasename\fR\-gdefs\-edit\&.rng, \fIbasename\fR\-gdefs\&.rng -.RS 4 -Auxiliary RELAX NG schema containing global named pattern definitions\&. The first is generated for "config" and "get\-config\-reply" targets, the second for "edit\-config" and the third for the remaining targets\&. -.RE -.PP -\fIbasename\fR\-\fItarget\fR\&.sch -.RS 4 -Schematron schema for the target document type\&. Not generated for the "edit\-config" target\&. -.RE -.PP -\fIbasename\fR\-\fItarget\fR\&.dsrl -.RS 4 -DSRL schema for the target document type\&. Not generated for the "edit\-config" target\&. -.RE +An event notification defined in an input YANG module. +.PP +The output schemas are contained in the following four files whose names +depend on the arguments \f[I]basename\f[R] and \f[I]target\f[R]: +.TP +\f[I]basename\f[R]-\f[I]target\f[R].rng +RELAX NG schema for the target document type. +.TP +\f[I]basename\f[R]-gdefs-config.rng, \f[I]basename\f[R]-gdefs-edit.rng, \f[I]basename\f[R]-gdefs.rng +Auxiliary RELAX NG schema containing global named pattern definitions. +The first is generated for \[lq]config\[rq] and +\[lq]get-config-reply\[rq] targets, the second for \[lq]edit-config\[rq] +and the third for the remaining targets. +.TP +\f[I]basename\f[R]-\f[I]target\f[R].sch +Schematron schema for the target document type. +Not generated for the \[lq]edit-config\[rq] target. +.TP +\f[I]basename\f[R]-\f[I]target\f[R].dsrl +DSRL schema for the target document type. +Not generated for the \[lq]edit-config\[rq] target. .PP Optional validation of an XML document stored in the file -\fIinstance\fR -proceeds as follows: -.sp -.RS 4 -.ie n \{\ -\h'-04' 1.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 1." 4.2 -.\} -Grammatical and datatype constraints are checked using the RELAX NG schema\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04' 2.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 2." 4.2 -.\} -The DSRL schema is used for adding default values together with ancestor containers to the instance document where necessary\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04' 3.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 3." 4.2 -.\} -Semantic constraints are checked using the Schematron schema\&. The skeleton implementation of -\m[blue]\fBISO Schematron\fR\m[]\&\s-2\u[3]\d\s+2 -by Rick Jelliffe is included in the distribution and used for this purpose\&. -.RE -.PP -Steps -2 -and -3 -are not performed for the "edit\-config" target, or if step -1 -reports any errors\&. -.PP -Option -\fB\-s\fR -may be used together with -\fB\-v\fR -for validating an instance document without generating the schemas\&. This assumes that the schemas are already present in the directory selected by the -\fB\-d\fR -option (current directory by default)\&. In this case, the basename of the schemas must be specified using -\fB\-b\fR\fIbasename\fR -and the input YANG modules need not be given\&. Also, if the DSRL or Schematron schema is missing, the corresponding step is skipped\&. -.PP -The script uses programs from the libxml2 suite \- -\fBxmllint\fR(1) for RELAX NG validation and -\fBxsltproc\fR(1) for performing XSLT transformations\&. Alternatively, -\fBjing\fR(1) can be used for RELAX NG validation (option -\fB\-j\fR)\&. If necessary, the script could be easily modified for use with other RELAX NG validators and/or XSLT1 processors supporting EXSLT\&. -.SH "OPTIONS" -.PP -\fB\-b\fR \fIbasename\fR -.RS 4 -Specifies the basename of files in which the output schemas are stored\&. The default is the concatenation of the names of all input YANG modules connected with the underscore character "_"\&. This option is mandatory if -\fB\-s\fR -is used\&. -.RE -.PP -\fB\-d\fR \fIdir\fR -.RS 4 -Specifies the directory for output files\&. By default they are stored in the current directory\&. -.RE -.PP -\fB\-h\fR -.RS 4 -Displays help screen and exits\&. -.RE -.PP -\fB\-j\fR -.RS 4 -Uses -\fBjing\fR(1) for RELAX NG validation instead of the default -\fBxmllint\fR(1)\&. -.RE -.PP -\fB\-L\fR -.RS 4 -Interpret the -\fIfile\fR -parameter as the name of a file containing a server message\&. In this case, exactly one -\fIfile\fR -parameter must be given\&. -.RE -.PP -\fB\-s\fR -.RS 4 -Performs just validation, without (re)generating the schemas\&. This option is only allowed together with -\fB\-v\fR -and -\fB\-b\fR\fIbasename\fR -must also be specified\&. -.RE -.PP -\fB\-t\fR \fItarget\fR -.RS 4 -Specifies the target XML document type using one of the following strings as explained above: -\fBdata\fR -(default), -\fBconfig\fR, -\fBget\-reply\fR, -\fBget\-data\-reply\fR, -\fBget\-config\-reply\fR, -\fBedit\-config\fR, -\fBrpc\fR, -\fBrpc\-reply\fR -or -\fBnotification\fR\&. -.RE -.PP -\fB\-v\fR \fIinstance\fR -.RS 4 -Validates an instance XML document contained in file -\fIinstance\fR\&. -.RE -.PP -\fB\-x\fR -.RS 4 -Try to translate modules written in unsupported YANG versions\&. If the module doesn\*(Aqt use any constructs introduced after YANG version 1, this may work\&. This option may produce unexpected results\&. Use at own risk\&. -.RE -.PP -\fB\-c\fR -.RS 4 -Use only definitions with status "current" in the YANG module\&. -.RE -.SH "FILES" -.PP -/usr/local/share/yang/xslt/gen\-relaxng\&.xsl -.RS 4 -XSLT stylesheet generating RELAX NG schemas\&. -.RE -.PP -/usr/local/share/yang/xslt/gen\-schematron\&.xsl -.RS 4 -XSLT stylesheet generating Schematron schemas\&. -.RE -.PP -/usr/local/share/yang/xslt/gen\-dsrl\&.xsl -.RS 4 -XSLT stylesheet generating DSRL schemas\&. -.RE -.PP -/usr/local/share/yang/xslt/gen\-common\&.xsl -.RS 4 -Common templates for all three XSLT generators\&. -.RE -.PP -/usr/local/share/yang/xslt/dsrl2xslt\&.xsl -.RS 4 -Translates a subset of DSRL containing only specification of default contents to an XSLT stylesheet\&. -.RE -.PP -/usr/local/share/yang/xslt/svrl2text\&.xsl -.RS 4 -Translates an SVRL report to plain text\&. -.RE -.PP -/usr/local/share/yang/schema/relaxng\-lib\&.rng -.RS 4 -RELAX NG library of common NETCONF elements\&. -.RE -.PP -/usr/local/share/yang/schema/edit\-config\-attributes\&.rng -.RS 4 -RELAX NG definitions of attributes\&. -.RE -.SH "ENVIRONMENT VARIABLES" -.PP -\fBPYANG_XSLT_DIR\fR -.RS 4 -Alternative directory for XSLT stylesheets\&. The default is installation dependent\&. -.RE -.PP -\fBPYANG_RNG_LIBDIR\fR -.RS 4 -Alternative directory for the RELAX NG library\&. The default is installation dependent\&. -.RE -.PP -\fBXSLT_OPTS\fR -.RS 4 -Options to pass to the XSLT processor when generating the DSDL schemas\&. This is mainly useful for debugging\&. -.RE -.SH "EXAMPLES" -.sp -.if n \{\ -.RS 4 -.\} +\f[I]instance\f[R] proceeds as follows: +.IP "1." 3 +Grammatical and datatype constraints are checked using the RELAX NG +schema. +.IP "2." 3 +The DSRL schema is used for adding default values together with ancestor +containers to the instance document where necessary. +.IP "3." 3 +Semantic constraints are checked using the Schematron schema. +The skeleton implementation of \f[B]ISO Schematron\f[R] by Rick Jelliffe +is included in the distribution and used for this purpose. +.PP +Steps 3 and 3 are not performed for the \[lq]edit-config\[rq] target, or +if step 1 reports any errors. +.PP +Option \f[B]-s\f[R] may be used together with \f[B]-v\f[R] for +validating an instance document without generating the schemas. +This assumes that the schemas are already present in the directory +selected by the \f[B]-d\f[R] option (current directory by default). +In this case, the basename of the schemas must be specified using +\f[B]-b\f[R] \f[I]basename\f[R] and the input YANG modules need not be +given. +Also, if the DSRL or Schematron schema is missing, the corresponding +step is skipped. +.PP +The script uses programs from the libxml2 suite - \f[B]xmllint\f[R](1) +for RELAX NG validation and \f[B]xsltproc\f[R](1) for performing XSLT +transformations. +Alternatively, \f[B]jing\f[R](1) can be used for RELAX NG validation +(option \f[B]-j\f[R]). +If necessary, the script could be easily modified for use with other +RELAX NG validators and/or XSLT1 processors supporting EXSLT. +.SH OPTIONS +.TP +\f[B]-b\f[R] \f[I]basename\f[R] +Specifies the basename of files in which the output schemas are stored. +The default is the concatenation of the names of all input YANG modules +connected with the underscore character \[dq]_\[dq]. +This option is mandatory if \f[B]-s\f[R] is used. +.TP +\f[B]-d\f[R] \f[I]dir\f[R] +Specifies the directory for output files. +By default they are stored in the current directory. +.TP +\f[B]-h\f[R] +Displays help screen and exits. +.TP +\f[B]-j\f[R] +Uses \f[B]jing\f[R](1) for RELAX NG validation instead of the default +\f[B]xmllint\f[R](1). +.TP +\f[B]-L\f[R] +Interpret the \f[I]file\f[R] parameter as the name of a file containing +a server message. +In this case, exactly one \f[I]file\f[R] parameter must be given. +.TP +\f[B]-s\f[R] +Performs just validation, without (re)generating the schemas. +This option is only allowed together with \f[B]-v\f[R] and \f[B]-b\f[R] +\f[I]basename\f[R] must also be specified. +.TP +\f[B]-t\f[R] \f[I]target\f[R] +Specifies the target XML document type using one of the following +strings as explained above: \f[B]data\f[R] (default), \f[B]config\f[R], +\f[B]get-reply\f[R], \f[B]get-data-reply\f[R], +\f[B]get-config-reply\f[R], \f[B]edit-config\f[R], \f[B]rpc\f[R], +\f[B]rpc-reply\f[R] or \f[B]notification\f[R]. +.TP +\f[B]-v\f[R] \f[I]instance\f[R] +Validates an instance XML document contained in file \f[I]instance\f[R]. +.TP +\f[B]-x\f[R] +Try to translate modules written in unsupported YANG versions. +If the module doesn\[cq]t use any constructs introduced after YANG +version 1, this may work. +This option may produce unexpected results. +Use at own risk. +.TP +\f[B]-c\f[R] +Use only definitions with status \[lq]current\[rq] in the YANG module. +.SH FILES +.TP +/usr/local/share/yang/xslt/gen-relaxng.xsl +XSLT stylesheet generating RELAX NG schemas. +.TP +/usr/local/share/yang/xslt/gen-schematron.xsl +XSLT stylesheet generating DSRL schemas. +.TP +/usr/local/share/yang/xslt/gen-common.xsl +Common templates for all three XSLT generators. +.TP +/usr/local/share/yang/xslt/dsrl2xslt.xsl +Translates a subset of DSRL containing only specification of default +contents to an XSLT stylesheet. +.TP +/usr/local/share/yang/xslt/svrl2text.xsl +Translates an SVRL report to plain text. +.TP +/usr/local/share/yang/schema/relaxng-lib.rng +RELAX NG library of common NETCONF elements. +.TP +/usr/local/share/yang/schema/edit-config-attributes.rng +RELAX NG definitions of attributes. +.SH ENVIRONMENT VARIABLES +.TP +\f[B]PYANG_XSLT_DIR\f[R] +Alternative directory for XSLT stylesheets. +The default is installation dependent. +.TP +\f[B]PYANG_RNG_LIBDIR\f[R] +Alternative directory for the RELAX NG library. +The default is installation dependent. +.TP +\f[B]XSLT_OPTS\f[R] +Options to pass to the XSLT processor when generating the DSDL schemas. +This is mainly useful for debugging. +.SH EXAMPLES +.IP .nf -$ yang2dsdl \-v dhcp\-data\&.xml dhcp\&.yang +\f[C] +$ yang2dsdl -v dhcp-data.xml dhcp.yang +\f[R] .fi -.if n \{\ -.RE -.\} .PP -This command generates the DSDL schemas for the datastore contents (default -\fIdata\fR -target) as defined by the -dhcp\&.yang -module and validates an instance document stored in the -dhcp\-data\&.xml -file\&. -.sp -.if n \{\ -.RS 4 -.\} +This command generates the DSDL schemas for the datastore contents +(default \f[I]data\f[R] target) as defined by dhcp.yang module and +validates an instance document stored in the dhcp-data.xml file. +.IP .nf -$ yang2dsdl \-t rpc rpc\-rock\&.yang +\f[C] +$ yang2dsdl -t rpc rpc-rock.yang +\f[R] .fi -.if n \{\ -.RE -.\} .PP -This command generates DSDL schemas for the choice of input parts (requests) of all RPC operations defined in the module -rpc\-rock\&.yang\&. -.SH "DIAGNOSTICS" -.PP -\fByang2dsdl\fR -return codes have the following meaning: +This command generates DSDL schemas for the choice of input parts +(requests) of all RPC operations defined in the module rpc-rock.yang. +.SH DIAGNOSTICS .PP +\f[B]yang2dsdl\f[R] return codes have the following meaning: +.TP 0 -.RS 4 No error (normal termination) -.RE -.PP +.TP 1 -.RS 4 Error in input parameters -.RE -.PP +.TP 2 -.RS 4 Error in DSDL schema generation -.RE -.PP +.TP 3 -.RS 4 Instance validation failed -.RE -.SH "BUGS" -.sp -.RS 4 -.ie n \{\ -\h'-04' 1.\h'+01'\c -.\} -.el \{\ -.sp -1 -.IP " 1." 4.2 -.\} -The logic of command\-line arguments may not be able to distinguish replies to different RPC requests, for example if the replies have the same top\-level element\&. -.RE -.SH "SEE ALSO" -.PP -\fBpyang\fR(1), -\fBxsltproc\fR(1), -\fBxmllint\fR(1), -\m[blue]\fBRFC\ \&6110\fR\m[]\&\s-2\u[1]\d\s+2, -\m[blue]\fBDSDL\fR\m[]\&\s-2\u[4]\d\s+2, -\m[blue]\fBRELAX NG\fR\m[]\&\s-2\u[5]\d\s+2, -\m[blue]\fBISO Schematron\fR\m[]\&\s-2\u[3]\d\s+2\&. -.SH "AUTHOR" -.PP -\fBLadislav Lhotka\fR <\&lhotka@nic\&.cz\&> -.br -CZ\&.NIC -.RS 4 -.RE -.SH "NOTES" -.IP " 1." 4 -RFC\ \&6110 -.RS 4 -\%http://tools.ietf.org/html/rfc6110 -.RE -.IP " 2." 4 -RFC\ \&7952 -.RS 4 -\%http://tools.ietf.org/html/rfc7952 -.RE -.IP " 3." 4 -ISO Schematron -.RS 4 -\%http://www.schematron.com -.RE -.IP " 4." 4 -DSDL -.RS 4 -\%http://www.dsdl.org/ -.RE -.IP " 5." 4 -RELAX NG -.RS 4 -\%http://www.relaxng.org/ -.RE +.SH BUGS +.IP "1." 3 +The logic of command-line arguments may not be able to distinguish +replies to different RPC requests, for example if the replies have the +same top-level element. +.SH SEE ALSO +.PP +\f[B]pyang\f[R](1), \f[B]xsltproc\f[R](1), \f[B]xmllint\f[R](1), +\f[B]RFC 61110\f[R]. +.SH AUTHOR +.PP +\f[B]Ladislav Lhotka\f[R] +.PD 0 +.P +.PD +CZ.NIC diff --git a/pyang/__init__.py b/pyang/__init__.py index cfee11cf..74254465 100644 --- a/pyang/__init__.py +++ b/pyang/__init__.py @@ -1,4 +1,4 @@ """The pyang library for parsing, validating, and converting YANG modules""" -__version__ = '2.5.3' -__date__ = '2022-03-30' +__version__ = '2.6.0' +__date__ = '2023-11-03' From 495dda02c9fb1fa89e44ec44c0a5f605939bf349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Wed, 15 Nov 2023 09:37:55 +0100 Subject: [PATCH 28/41] set i_main_module properly when a submodule is validated standalone --- pyang/statements.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyang/statements.py b/pyang/statements.py index 4852e1d2..7291792a 100644 --- a/pyang/statements.py +++ b/pyang/statements.py @@ -445,7 +445,8 @@ def v_init_module(ctx, stmt): prefix = belongs_to.search_one('prefix') stmt.i_modulename = belongs_to.arg mod = ctx.get_module(stmt.i_modulename) - if mod is None: + if mod is None or not mod.i_is_validated: + # this happens if a submodule is validated standalone mod = stmt else: stmt.i_modulename = "" From e3ff8ab9f31a3b72329b6f09514292c7eeb3dea1 Mon Sep 17 00:00:00 2001 From: Joe Clarke Date: Wed, 24 Jan 2024 10:32:40 -0500 Subject: [PATCH 29/41] Replace sys.exit with return. (#887) * Replace sys.exit with return, and create an error object for the IOError prior to returning. If other modules import this code, an exit in a library may have unintended consequences. Like in other places, use return instead of exit. --------- Co-authored-by: Joe Clarke --- pyang/plugins/check_update.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pyang/plugins/check_update.py b/pyang/plugins/check_update.py index 721fd700..3aadc363 100644 --- a/pyang/plugins/check_update.py +++ b/pyang/plugins/check_update.py @@ -161,6 +161,9 @@ def add_opts(self, optparser): error.add_error_code( 'CHK_UNION_TYPES', 3, "the member types in the union have changed") + error.add_error_code( + 'CHK_IO_ERROR', 1, + "error %s: %s") def post_validate_ctx(self, ctx, modules): if not ctx.opts.check_update_from: @@ -194,8 +197,9 @@ def check_update(ctx, newmod): fd = io.open(oldfilename, "r", encoding="utf-8") text = fd.read() except IOError as ex: - sys.stderr.write("error %s: %s\n" % (oldfilename, ex)) - sys.exit(1) + pos = error.Position(oldfilename) + err_add(ctx.errors, pos, "CHK_IO_ERROR", (oldfilename, ex)) + return if oldfilename in ctx.opts.old_deviation: oldctx.add_module(oldfilename, text) else: From 87d23b087d4becd313c06303869acd69875fa48e Mon Sep 17 00:00:00 2001 From: Nick Hancock Date: Tue, 30 Jan 2024 18:00:10 +0100 Subject: [PATCH 30/41] UML Plugin correct direction of the generalization and realization relations --- pyang/plugins/uml.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyang/plugins/uml.py b/pyang/plugins/uml.py index 5b57ac7e..f7f3beaa 100644 --- a/pyang/plugins/uml.py +++ b/pyang/plugins/uml.py @@ -286,7 +286,7 @@ def __init__(self, ctx): if ctx.opts.uml_uses != "": if ctx.opts.uml_uses in uses_strings: if ctx.opts.uml_uses == 'generalization': - self.uses_relation_symbol = "<|--" + self.uses_relation_symbol = "--|>" elif ctx.opts.uml_uses == 'aggregation': self.uses_relation_symbol = "o--" elif ctx.opts.uml_uses == 'association': @@ -297,7 +297,7 @@ def __init__(self, ctx): self.uses_relation_symbol = "..>" self.uses_relation_label = "<>" elif ctx.opts.uml_uses == 'realization': - self.uses_relation_symbol = "<|.." + self.uses_relation_symbol = "..|>" else: sys.stderr.write("\"%s\" no valid argument to --uml-uses=..., valid arguments (one only): %s \n" %(ctx.opts.uml_uses, uses_strings)) From 3e2ca00dccf89a0ef442b6565ad3092281116d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Tue, 12 Mar 2024 10:37:45 +0100 Subject: [PATCH 31/41] Fixed #884 - tree module header not printed --- pyang/plugins/tree.py | 10 ++++++---- test/test_issues/test_i884/Makefile | 2 ++ test/test_issues/test_i884/a.yang | 8 ++++++++ test/test_issues/test_i884/b.yang | 9 +++++++++ test/test_issues/test_i884/res.expect | 5 +++++ 5 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 test/test_issues/test_i884/Makefile create mode 100644 test/test_issues/test_i884/a.yang create mode 100644 test/test_issues/test_i884/b.yang create mode 100644 test/test_issues/test_i884/res.expect diff --git a/pyang/plugins/tree.py b/pyang/plugins/tree.py index 27c70fff..e089d6b9 100644 --- a/pyang/plugins/tree.py +++ b/pyang/plugins/tree.py @@ -136,21 +136,23 @@ def print_help(): """) def emit_tree(ctx, modules, fd, depth, llen, path): - printed_header = False - def print_header(module): - nonlocal printed_header if not printed_header: bstr = "" b = module.search_one('belongs-to') if b is not None: bstr = " (belongs-to %s)" % b.arg fd.write("%s: %s%s\n" % (module.keyword, module.arg, bstr)) - printed_header = True + printed_header.append(None) + + printed_header = [] for module in modules: if printed_header: fd.write("\n") + del printed_header[:] + + chs = [ch for ch in module.i_children if ch.keyword in statements.data_definition_keywords] if path is not None and len(path) > 0: diff --git a/test/test_issues/test_i884/Makefile b/test/test_issues/test_i884/Makefile new file mode 100644 index 00000000..1d8083fb --- /dev/null +++ b/test/test_issues/test_i884/Makefile @@ -0,0 +1,2 @@ +test: + $(PYANG) -f tree a.yang b.yang | diff res.expect - diff --git a/test/test_issues/test_i884/a.yang b/test/test_issues/test_i884/a.yang new file mode 100644 index 00000000..e7e39649 --- /dev/null +++ b/test/test_issues/test_i884/a.yang @@ -0,0 +1,8 @@ +module a { + namespace urn:a; + prefix a; + + leaf a { + type string; + } +} diff --git a/test/test_issues/test_i884/b.yang b/test/test_issues/test_i884/b.yang new file mode 100644 index 00000000..6ed89ee3 --- /dev/null +++ b/test/test_issues/test_i884/b.yang @@ -0,0 +1,9 @@ +module b { + namespace urn:b; + prefix b; + + leaf b { + type string; + } + +} diff --git a/test/test_issues/test_i884/res.expect b/test/test_issues/test_i884/res.expect new file mode 100644 index 00000000..c2f0b328 --- /dev/null +++ b/test/test_issues/test_i884/res.expect @@ -0,0 +1,5 @@ +module: a + +--rw a? string + +module: b + +--rw b? string From 25f69e85cf418886a66eaa0d9702496569df3180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Tue, 12 Mar 2024 11:18:24 +0100 Subject: [PATCH 32/41] Fixes #886 - crash on deviation of config --- pyang/statements.py | 8 ++- test/test_issues/test_i886/Makefile | 4 ++ .../test_i886/deviation-problem-dev.yang | 35 +++++++++++++ .../test_i886/deviation-problem.yang | 51 +++++++++++++++++++ 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 test/test_issues/test_i886/Makefile create mode 100644 test/test_issues/test_i886/deviation-problem-dev.yang create mode 100644 test/test_issues/test_i886/deviation-problem.yang diff --git a/pyang/statements.py b/pyang/statements.py index 7291792a..70c56238 100644 --- a/pyang/statements.py +++ b/pyang/statements.py @@ -2055,8 +2055,12 @@ def v_key(): 'KEY_HAS_MANDATORY_FALSE', ()) if ptr.i_config != stmt.i_config: - err_add(ctx.errors, ptr.search_one('config').pos, - 'KEY_BAD_CONFIG', name) + cfg = ptr.search_one('config') + if cfg is not None: + pos = cfg.pos + else: + pos = ptr.pos + err_add(ctx.errors, pos, 'KEY_BAD_CONFIG', name) stmt.i_key.append(ptr) ptr.i_is_key = True diff --git a/test/test_issues/test_i886/Makefile b/test/test_issues/test_i886/Makefile new file mode 100644 index 00000000..90b59554 --- /dev/null +++ b/test/test_issues/test_i886/Makefile @@ -0,0 +1,4 @@ +test: + $(PYANG) --print-error-code \ + --deviation-module deviation-problem-dev.yang \ + deviation-problem.yang 2>&1 | grep KEY_BAD_CONFIG > /dev/null diff --git a/test/test_issues/test_i886/deviation-problem-dev.yang b/test/test_issues/test_i886/deviation-problem-dev.yang new file mode 100644 index 00000000..d82ca871 --- /dev/null +++ b/test/test_issues/test_i886/deviation-problem-dev.yang @@ -0,0 +1,35 @@ +module deviation-problem-dev { + + yang-version 1.1; + namespace "urn:deviation-problem-dev:1.0"; + prefix "dp-dev"; + + import deviation-problem { + prefix "dp"; + } + + organization "x"; + contact "x"; + description "x"; + revision "2023-12-12" { + description + "version 1.0.0 + 1) initial version"; + reference + "x"; + } + + /* Deviations to permit configuration of RO parameters */ + deviation "/dp:top/dp:cnode" { + deviate replace { + config true; + } + } + + /* Deviations to permit configuration of RO parameters */ + deviation "/dp:top/dp:lnode" { + deviate replace { + config true; + } + } +} \ No newline at end of file diff --git a/test/test_issues/test_i886/deviation-problem.yang b/test/test_issues/test_i886/deviation-problem.yang new file mode 100644 index 00000000..a8463258 --- /dev/null +++ b/test/test_issues/test_i886/deviation-problem.yang @@ -0,0 +1,51 @@ +module deviation-problem { + + yang-version 1.1; + namespace "urn:deviation-problem:1.0"; + prefix "deviation-problem"; + + organization "x"; + contact "x"; + description "x"; + revision "2023-12-12" { + description + "version 1.0.0 + 1) initial version"; + reference + "x"; + } + + container top { + description "top container"; + + leaf tleaf { + type uint32; + units nanoseconds; + description "eleaf"; + } + + container cnode { + config false; + description "container node"; + leaf cleaf { + type uint32; + units nanoseconds; + description "eleaf"; + } + } + + list lnode { + key "id"; + config false; + description + "List node"; + + leaf id { + type uint16; + description + "list key"; + } + } + } + +} \ No newline at end of file From 4f271fffd1d83ebe54fbc74bde608ee0d949bc30 Mon Sep 17 00:00:00 2001 From: Siddharth Sharma Date: Sat, 11 May 2024 23:25:09 +0200 Subject: [PATCH 33/41] Fix IEEE module name prefix expectation This addresses mbj4668/pyang#893 Signed-off-by: Siddharth Sharma --- pyang/plugins/ieee.py | 17 +++++++++-- test/plugins/test_ieee/Makefile | 15 ++++++++++ .../ieee-802-dot1q-incorrect-name.expect | 1 + .../ieee-802-dot1q-incorrect-name.yang | 29 +++++++++++++++++++ .../test_ieee/ieee802-dot1q-correct.yang | 29 +++++++++++++++++++ .../ieee802-dot1q-incorrect-namespace.expect | 1 + .../ieee802-dot1q-incorrect-namespace.yang | 29 +++++++++++++++++++ 7 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 test/plugins/test_ieee/Makefile create mode 100644 test/plugins/test_ieee/ieee-802-dot1q-incorrect-name.expect create mode 100644 test/plugins/test_ieee/ieee-802-dot1q-incorrect-name.yang create mode 100644 test/plugins/test_ieee/ieee802-dot1q-correct.yang create mode 100644 test/plugins/test_ieee/ieee802-dot1q-incorrect-namespace.expect create mode 100644 test/plugins/test_ieee/ieee802-dot1q-incorrect-namespace.yang diff --git a/pyang/plugins/ieee.py b/pyang/plugins/ieee.py index ce96f1aa..14dd6347 100644 --- a/pyang/plugins/ieee.py +++ b/pyang/plugins/ieee.py @@ -17,7 +17,6 @@ def pyang_plugin_init(): class IEEEPlugin(lint.LintPlugin): def __init__(self): lint.LintPlugin.__init__(self) - self.modulename_prefixes = ['ieee'] def add_opts(self, optparser): optlist = [ @@ -34,15 +33,29 @@ def setup_ctx(self, ctx): return self._setup_ctx(ctx) + error.add_error_code( + 'IEEE_BAD_MODULENAME_PREFIX', 4, + 'the module name prefix should be of the form ' + '{IEEE committee}- e.g., ieee802-') + error.add_error_code( 'IEEE_BAD_NAMESPACE_VALUE', 4, - 'the namespace should be on the form ' + 'the namespace should be of the form ' 'urn:ieee:std:{IEEE standard designation}:yang:%s') + statements.add_validation_fun( + 'grammar', ['module', 'submodule'], + lambda ctx, s: self.v_chk_module_name(ctx, s)) + statements.add_validation_fun( 'grammar', ['namespace'], lambda ctx, s: self.v_chk_namespace(ctx, s)) + def v_chk_module_name(self, ctx, stmt): + r = '^ieee[0-9]+-.*' + if re.match(r, stmt.arg) is None: + err_add(ctx.errors, stmt.pos, 'IEEE_BAD_MODULENAME_PREFIX', ()) + def v_chk_namespace(self, ctx, stmt): r = 'urn:ieee:std:.*:yang:' + stmt.i_module.arg if re.match(r, stmt.arg) is None: diff --git a/test/plugins/test_ieee/Makefile b/test/plugins/test_ieee/Makefile new file mode 100644 index 00000000..5f8ec59d --- /dev/null +++ b/test/plugins/test_ieee/Makefile @@ -0,0 +1,15 @@ +test: test1 test2 test3 test4 + +# Baseline test that a module following 3gpp guidelines is OK +test1: + $(PYANG) --ieee ieee802-dot1q-correct.yang + +test2: + $(PYANG) --ieee ieee-802-dot1q-incorrect-name.yang 2>&1 | diff ieee-802-dot1q-incorrect-name.expect - + +test3: + $(PYANG) --ieee ieee802-dot1q-incorrect-namespace.yang 2>&1 | diff ieee802-dot1q-incorrect-namespace.expect - + +# Check help text +test4: + $(PYANG) -h | grep " --ieee Validate the module(s) according to IEEE rules." diff --git a/test/plugins/test_ieee/ieee-802-dot1q-incorrect-name.expect b/test/plugins/test_ieee/ieee-802-dot1q-incorrect-name.expect new file mode 100644 index 00000000..cd0c7652 --- /dev/null +++ b/test/plugins/test_ieee/ieee-802-dot1q-incorrect-name.expect @@ -0,0 +1 @@ +ieee-802-dot1q-incorrect-name.yang:1: warning: the module name prefix should be of the form {IEEE committee}- e.g., ieee802- diff --git a/test/plugins/test_ieee/ieee-802-dot1q-incorrect-name.yang b/test/plugins/test_ieee/ieee-802-dot1q-incorrect-name.yang new file mode 100644 index 00000000..d7ddfc83 --- /dev/null +++ b/test/plugins/test_ieee/ieee-802-dot1q-incorrect-name.yang @@ -0,0 +1,29 @@ +module ieee-802-dot1q-incorrect-name { + yang-version 1.1; + namespace "urn:ieee:std:802.1Q:yang:ieee-802-dot1q-incorrect-name"; + prefix dot1q-incorrect-name; + + organization + "Institute of Electrical and Electronics Engineers"; + + contact + "WG-URL: http://www.ieee802.org/1 + WG-EMail: stds-802-1-L@ieee.org + + Contact: IEEE 802.1 Working Group Chair + Postal: C/O IEEE 802.1 Working Group + IEEE Standards Association + 445 Hoes Lane + Piscataway + NJ 08854 + USA + + E-mail: STDS-802-1-L@LISTSERV.IEEE.ORG"; + + description + "ieee-802-dot1q-incorrect-name"; + + revision 2024-05-10 { + reference "ieee-802-dot1q-incorrect-name"; + } +} \ No newline at end of file diff --git a/test/plugins/test_ieee/ieee802-dot1q-correct.yang b/test/plugins/test_ieee/ieee802-dot1q-correct.yang new file mode 100644 index 00000000..332700a2 --- /dev/null +++ b/test/plugins/test_ieee/ieee802-dot1q-correct.yang @@ -0,0 +1,29 @@ +module ieee802-dot1q-correct { + yang-version 1.1; + namespace "urn:ieee:std:802.1Q:yang:ieee802-dot1q-correct"; + prefix dot1q-correct; + + organization + "Institute of Electrical and Electronics Engineers"; + + contact + "WG-URL: http://www.ieee802.org/1 + WG-EMail: stds-802-1-L@ieee.org + + Contact: IEEE 802.1 Working Group Chair + Postal: C/O IEEE 802.1 Working Group + IEEE Standards Association + 445 Hoes Lane + Piscataway + NJ 08854 + USA + + E-mail: STDS-802-1-L@LISTSERV.IEEE.ORG"; + + description + "ieee802-dot1q-correct"; + + revision 2024-05-10 { + reference "ieee802-dot1q-correct"; + } +} \ No newline at end of file diff --git a/test/plugins/test_ieee/ieee802-dot1q-incorrect-namespace.expect b/test/plugins/test_ieee/ieee802-dot1q-incorrect-namespace.expect new file mode 100644 index 00000000..b78fc5b3 --- /dev/null +++ b/test/plugins/test_ieee/ieee802-dot1q-incorrect-namespace.expect @@ -0,0 +1 @@ +ieee802-dot1q-incorrect-namespace.yang:3: warning: the namespace should be of the form urn:ieee:std:{IEEE standard designation}:yang:ieee802-dot1q-incorrect-namespace diff --git a/test/plugins/test_ieee/ieee802-dot1q-incorrect-namespace.yang b/test/plugins/test_ieee/ieee802-dot1q-incorrect-namespace.yang new file mode 100644 index 00000000..d8fb32c3 --- /dev/null +++ b/test/plugins/test_ieee/ieee802-dot1q-incorrect-namespace.yang @@ -0,0 +1,29 @@ +module ieee802-dot1q-incorrect-namespace { + yang-version 1.1; + namespace "urn:ieee:std:802.1Q:yang:ieee802-dot1q-correct-namespace"; + prefix dot1q-incorrect-namespace; + + organization + "Institute of Electrical and Electronics Engineers"; + + contact + "WG-URL: http://www.ieee802.org/1 + WG-EMail: stds-802-1-L@ieee.org + + Contact: IEEE 802.1 Working Group Chair + Postal: C/O IEEE 802.1 Working Group + IEEE Standards Association + 445 Hoes Lane + Piscataway + NJ 08854 + USA + + E-mail: STDS-802-1-L@LISTSERV.IEEE.ORG"; + + description + "ieee802-dot1q-incorrect-namespace"; + + revision 2024-05-10 { + reference "ieee802-dot1q-incorrect-namespace"; + } +} \ No newline at end of file From 283cfbf78d74033795bbcc6de10b015e142ffecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Sun, 12 May 2024 11:15:55 +0200 Subject: [PATCH 34/41] fixed email address --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9def65fc..52b26c62 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ def run_commands(self): setup(name='pyang', version=pyang.__version__, author='Martin Bjorklund', - author_email='mbj@tail-f.com', + author_email='mbj4668@gmail.com', description="A YANG (RFC 6020/7950) validator and converter", long_description="An extensible YANG (RFC 6020/7950) validator." + \ " Provides a framework for plugins that can convert YANG modules" + \ From d4159de94a8e1b7035acd43376a673121bcf0bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Thu, 23 May 2024 13:27:04 +0200 Subject: [PATCH 35/41] fixes #907 - check ordered-by updates --- env.sh | 1 + pyang/plugins/check_update.py | 18 ++++++++++++++++++ test/test_update/a.yang | 24 ++++++++++++++++++++++-- test/test_update/a@2014-04-01.yang | 21 +++++++++++++++++++++ test/test_update/expect/a.out | 3 +++ 5 files changed, 65 insertions(+), 2 deletions(-) diff --git a/env.sh b/env.sh index a75602d4..caa0ba93 100644 --- a/env.sh +++ b/env.sh @@ -9,4 +9,5 @@ export PYTHONPATH="$PWD:$PYTHONPATH" export YANG_MODPATH="$PWD/modules:$YANG_MODPATH" export PYANG_XSLT_DIR="$PWD/xslt" export PYANG_RNG_LIBDIR="$PWD/schema" +export PYANG="$PWD/bin/pyang" export W="$PWD" diff --git a/pyang/plugins/check_update.py b/pyang/plugins/check_update.py index 3aadc363..081a7efa 100644 --- a/pyang/plugins/check_update.py +++ b/pyang/plugins/check_update.py @@ -649,6 +649,22 @@ def chk_unique(old, new, ctx): else: err_def_added(u, ctx) +def chk_ordered_by(old, new, ctx): + oldorderedby = old.search_one('ordered-by') + neworderedby = new.search_one('ordered-by') + if oldorderedby is None and neworderedby is None: + pass + elif oldorderedby is None and neworderedby is not None and \ + neworderedby.arg == 'user': + err_def_added(neworderedby, ctx) + elif oldorderedby is not None and neworderedby is None and \ + oldorderedby.arg == 'user': + err_def_removed(oldorderedby, new, ctx) + elif oldorderedby is not None and neworderedby is not None and \ + oldorderedby.arg != neworderedby.arg: + err_add(ctx.errors, neworderedby.pos, 'CHK_DEF_CHANGED', + ('ordered-by', neworderedby.arg, oldorderedby.arg)) + def chk_leaf(old, new, ctx): chk_type(old.search_one('type'), new.search_one('type'), ctx) chk_units(old, new, ctx) @@ -659,6 +675,7 @@ def chk_leaf_list(old, new, ctx): chk_type(old.search_one('type'), new.search_one('type'), ctx) chk_units(old, new, ctx) chk_min_max(old, new, ctx) + chk_ordered_by(old, new, ctx) def chk_container(old, new, ctx): chk_presence(old, new, ctx) @@ -669,6 +686,7 @@ def chk_list(old, new, ctx): chk_key(old, new, ctx) chk_unique(old, new, ctx) chk_i_children(old, new, ctx) + chk_ordered_by(old, new, ctx) def chk_choice(old, new, ctx): chk_mandatory(old, new, ctx) diff --git a/test/test_update/a.yang b/test/test_update/a.yang index 2ac4eb52..5a55d781 100644 --- a/test/test_update/a.yang +++ b/test/test_update/a.yang @@ -113,7 +113,7 @@ module a { } leaf a_union { type my-union1; - } + } leaf b_union { type my-union3; } @@ -127,7 +127,7 @@ module a { leaf bbb { type uint16; - } + } leaf-list baz2 { type string; @@ -135,7 +135,27 @@ module a { leaf-list baz3 { type string; + ordered-by user; min-elements 1; max-elements 5; } + + leaf-list baz4 { + type int32; + ordered-by system; + } + + leaf-list baz5 { + type int32; + } + + leaf-list baz6 { + type int32; + ordered-by system; + } + + leaf-list baz7 { + type int32; + } + } diff --git a/test/test_update/a@2014-04-01.yang b/test/test_update/a@2014-04-01.yang index 7dea85ce..e2ecbb61 100644 --- a/test/test_update/a@2014-04-01.yang +++ b/test/test_update/a@2014-04-01.yang @@ -169,7 +169,28 @@ module a { leaf-list baz3 { type string; + ordered-by system; min-elements 2; max-elements 4; } + + leaf-list baz4 { + type int32; + } + + leaf-list baz5 { + type int32; + ordered-by system; + } + + leaf-list baz6 { + type int32; + ordered-by user; + } + + leaf-list baz7 { + type int32; + ordered-by user; + } + } diff --git a/test/test_update/expect/a.out b/test/test_update/expect/a.out index 4a6ef012..827045b1 100644 --- a/test/test_update/expect/a.out +++ b/test/test_update/expect/a.out @@ -11,3 +11,6 @@ a@2014-04-01.yang:166: error: CHK_DEF_ADDED a@2014-04-01.yang:167: error: CHK_DEF_ADDED a@2014-04-01.yang:172: error: CHK_DEF_CHANGED a@2014-04-01.yang:173: error: CHK_DEF_CHANGED +a@2014-04-01.yang:174: error: CHK_DEF_CHANGED +a@2014-04-01.yang:188: error: CHK_DEF_CHANGED +a@2014-04-01.yang:193: error: CHK_DEF_ADDED From fc9a965c3ae80688cc2889aefa183cf1aa6d55c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Thu, 23 May 2024 13:56:47 +0200 Subject: [PATCH 36/41] Updates for 2.6.1 release --- CHANGELOG.md | 11 +++++++++++ CONTRIBUTORS | 1 + man/man1/json2xml.1 | 18 ++++++++++++++++-- man/man1/pyang.1 | 23 +++++++++++++++++++---- man/man1/yang2dsdl.1 | 20 +++++++++++++++++--- pyang/__init__.py | 4 ++-- 6 files changed, 66 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88dfa155..219d7289 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +* 2.6.1 - 2024-05-23 +``` + fix IEEE module name prefix expectation + thanks to Siddharth Sharma + + #884 - tree module header not printed + #886 - crash on deviation of config + #887 - replace call to sys.exit with return + #907 - --check-update now checks for changes in ordered-by +``` + * 2.6.0 - 2023-11-03 ``` lots of improvements to the UML plugin diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1871c0dc..0d2b9e2f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -36,6 +36,7 @@ Erik Rask Michael Richardson Ralph Schmieder Juergen Schoenwaelder +Siddharth Sharma Romanos Skiadas Stefan Vallin Norbert Varkonyi diff --git a/man/man1/json2xml.1 b/man/man1/json2xml.1 index 463c7c1f..7ef49539 100644 --- a/man/man1/json2xml.1 +++ b/man/man1/json2xml.1 @@ -1,6 +1,20 @@ -.\" Automatically generated by Pandoc 2.9.2.1 +.\" Automatically generated by Pandoc 3.1.3 .\" -.TH "JSON2XML" "1" "2023-11-03" "json2xml-2.6.0" "User Manual" +.\" Define V font for inline verbatim, using C font in formats +.\" that render this, and otherwise B font. +.ie "\f[CB]x\f[]"x" \{\ +. ftr V B +. ftr VI BI +. ftr VB B +. ftr VBI BI +.\} +.el \{\ +. ftr V CR +. ftr VI CI +. ftr VB CB +. ftr VBI CBI +.\} +.TH "JSON2XML" "1" "2024-05-23" "json2xml-2.6.1" "User Manual" .hy .SH NAME .PP diff --git a/man/man1/pyang.1 b/man/man1/pyang.1 index 606b96f3..cb2313f6 100644 --- a/man/man1/pyang.1 +++ b/man/man1/pyang.1 @@ -1,6 +1,20 @@ -.\" Automatically generated by Pandoc 2.9.2.1 +.\" Automatically generated by Pandoc 3.1.3 .\" -.TH "PYANG" "1" "2023-11-03" "pyang-2.6.0" "User Manual" +.\" Define V font for inline verbatim, using C font in formats +.\" that render this, and otherwise B font. +.ie "\f[CB]x\f[]"x" \{\ +. ftr V B +. ftr VI BI +. ftr VB B +. ftr VBI BI +.\} +.el \{\ +. ftr V CR +. ftr VI CI +. ftr VB CB +. ftr VBI CBI +.\} +.TH "PYANG" "1" "2024-05-23" "pyang-2.6.1" "User Manual" .hy .SH NAME .PP @@ -348,7 +362,7 @@ current directory .IP "3." 3 \f[B]$HOME\f[R]/yang/modules .IP "4." 3 -\f[B]\f[BI]Y\f[B]\f[BI]A\f[B]\f[BI]N\f[B]\f[BI]G\f[B]_\f[BI]I\f[B]\f[BI]N\f[B]\f[BI]S\f[B]\f[BI]T\f[B]\f[BI]A\f[B]\f[BI]L\f[B]\f[BI]L\f[B]\[u2005]*\[u2005]\[u2005]*\[u2005]/\f[BI]y\f[B]\f[BI]a\f[B]\f[BI]n\f[B]\f[BI]g\f[B]/\f[BI]m\f[B]\f[BI]o\f[B]\f[BI]d\f[B]\f[BI]u\f[B]\f[BI]l\f[B]\f[BI]e\f[B]\f[BI]s\f[B]\f[BI]O\f[B]\f[BI]R\f[B]\f[BI]i\f[B]\f[BI]f\f[B]\[u2005]*\[u2005]*YANG_INSTALL\f[R] +\f[B]\f[BI]Y\f[B]\f[BI]A\f[B]\f[BI]N\f[B]\f[BI]G\f[B]_\f[BI]I\f[B]\f[BI]N\f[B]\f[BI]S\f[B]\f[BI]T\f[B]\f[BI]A\f[B]\f[BI]L\f[B]\f[BI]L\f[B] *  * /\f[BI]y\f[B]\f[BI]a\f[B]\f[BI]n\f[B]\f[BI]g\f[B]/\f[BI]m\f[B]\f[BI]o\f[B]\f[BI]d\f[B]\f[BI]u\f[B]\f[BI]l\f[B]\f[BI]e\f[B]\f[BI]s\f[B]\f[BI]O\f[B]\f[BI]R\f[B]\f[BI]i\f[B]\f[BI]f\f[B] * *YANG_INSTALL\f[R] is unset /yang/modules (on Unix systems: /usr/share/yang/modules) .RE @@ -1074,7 +1088,8 @@ Output the qualified XPath i.e., .TP \f[B]--flatten-qualified-module-and-prefix-path\f[R] Output an XPath with both module and prefix i.e., -/module1:prefix1:root/\&... This is NOT a colloquial syntax of XPath. +/module1:prefix1:root/\&... +This is NOT a colloquial syntax of XPath. Emitted separately. .TP \f[B]--flatten-deviated\f[R] diff --git a/man/man1/yang2dsdl.1 b/man/man1/yang2dsdl.1 index ee2c65a7..d0d77fbd 100644 --- a/man/man1/yang2dsdl.1 +++ b/man/man1/yang2dsdl.1 @@ -1,6 +1,20 @@ -.\" Automatically generated by Pandoc 2.9.2.1 +.\" Automatically generated by Pandoc 3.1.3 .\" -.TH "YANG2DSDL" "1" "2023-11-03" "yang2dsdl-2.6.0" "User Manual" +.\" Define V font for inline verbatim, using C font in formats +.\" that render this, and otherwise B font. +.ie "\f[CB]x\f[]"x" \{\ +. ftr V B +. ftr VI BI +. ftr VB B +. ftr VBI BI +.\} +.el \{\ +. ftr V CR +. ftr VI CI +. ftr VB CB +. ftr VBI CBI +.\} +.TH "YANG2DSDL" "1" "2024-05-23" "yang2dsdl-2.6.1" "User Manual" .hy .SH NAME .PP @@ -141,7 +155,7 @@ RELAX NG validators and/or XSLT1 processors supporting EXSLT. \f[B]-b\f[R] \f[I]basename\f[R] Specifies the basename of files in which the output schemas are stored. The default is the concatenation of the names of all input YANG modules -connected with the underscore character \[dq]_\[dq]. +connected with the underscore character \[lq]_\[lq]. This option is mandatory if \f[B]-s\f[R] is used. .TP \f[B]-d\f[R] \f[I]dir\f[R] diff --git a/pyang/__init__.py b/pyang/__init__.py index 74254465..0a9ebe0c 100644 --- a/pyang/__init__.py +++ b/pyang/__init__.py @@ -1,4 +1,4 @@ """The pyang library for parsing, validating, and converting YANG modules""" -__version__ = '2.6.0' -__date__ = '2023-11-03' +__version__ = '2.6.1' +__date__ = '2024-05-23' From 76b7840b4a0456154c1870e686a343122dcc4e94 Mon Sep 17 00:00:00 2001 From: Urs Baumann Date: Fri, 24 Jan 2025 21:22:53 +0100 Subject: [PATCH 37/41] Add fd to Decimal64Value --- pyang/types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyang/types.py b/pyang/types.py index 51f07ac5..e2f0e8d3 100644 --- a/pyang/types.py +++ b/pyang/types.py @@ -68,6 +68,7 @@ def __init__(self, value, s=None, fd=None): # must set s (string repr) OR fd (fraction-digits) self.value = value self.s = s + self.fd = fd if s is None: if fd is None: raise ValueError( From f8ff894081e3bb99e93f2cf619ed1da8eaa054a7 Mon Sep 17 00:00:00 2001 From: "Pawel W." Date: Fri, 10 Jan 2025 11:56:24 +0100 Subject: [PATCH 38/41] Replace deprecated pkg_resources with importlib for Python >=3.12 Depending on Python version use pkg_resources (old behavior) or use importlib to check for plugins. --- pyang/plugin.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pyang/plugin.py b/pyang/plugin.py index f8716a5a..3aa814fa 100644 --- a/pyang/plugin.py +++ b/pyang/plugin.py @@ -2,7 +2,10 @@ import os import sys -import pkg_resources +if sys.version_info >= (3, 12): + import importlib.resources as resources +else: + import pkg_resources plugins = [] """List of registered PyangPlugin instances""" @@ -19,7 +22,11 @@ def init(plugindirs=None): dsdl.pyang_plugin_init() # initialize installed plugins - for ep in pkg_resources.iter_entry_points(group='pyang.plugin'): + if sys.version_info >= (3, 12): + eps = list(resources.entry_points(group='pyang.plugin')) + else: + eps = pkg_resources.iter_entry_points(group='pyang.plugin') + for ep in eps: plugin_init = ep.load() plugin_init() From 259c2f24f05f77b304520084295678568abcc3d4 Mon Sep 17 00:00:00 2001 From: "Pawel W." Date: Fri, 10 Jan 2025 12:10:49 +0100 Subject: [PATCH 39/41] Update plugin.py --- pyang/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyang/plugin.py b/pyang/plugin.py index 3aa814fa..ea139543 100644 --- a/pyang/plugin.py +++ b/pyang/plugin.py @@ -3,7 +3,7 @@ import os import sys if sys.version_info >= (3, 12): - import importlib.resources as resources + import importlib.metadata as metadata else: import pkg_resources @@ -23,7 +23,7 @@ def init(plugindirs=None): # initialize installed plugins if sys.version_info >= (3, 12): - eps = list(resources.entry_points(group='pyang.plugin')) + eps = list(metadata.entry_points(group='pyang.plugin')) else: eps = pkg_resources.iter_entry_points(group='pyang.plugin') for ep in eps: From 07cdc5502bf50ab6951d375c90fb970dc90759d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Sun, 2 Feb 2025 11:19:14 +0100 Subject: [PATCH 40/41] Updated python versions for tests --- .github/workflows/tests.yml | 8 ++++++-- dev-requirements.txt | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cb3ce2fa..795c3263 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,11 +1,15 @@ name: tests -on: [push] +on: + push: + pull_request: + branches: + - main jobs: run-tests: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8.18", "3.9.21", "3.10.16", "3.11.11", "3.12.8", "3.13.1"] steps: - uses: actions/checkout@v3 diff --git a/dev-requirements.txt b/dev-requirements.txt index dae372d6..4834c14f 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,6 +1,7 @@ +setuptools coveralls pycodestyle pyflakes flake8 pylint -virtualenv \ No newline at end of file +virtualenv From 167bcda44556fc5285c782b0a4e3452f6d5b0bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rklund?= Date: Wed, 5 Feb 2025 17:37:04 +0100 Subject: [PATCH 41/41] use importlib.metadata in python >= 3.10 --- pyang/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyang/plugin.py b/pyang/plugin.py index ea139543..4ee52a33 100644 --- a/pyang/plugin.py +++ b/pyang/plugin.py @@ -2,7 +2,7 @@ import os import sys -if sys.version_info >= (3, 12): +if sys.version_info >= (3, 10): import importlib.metadata as metadata else: import pkg_resources @@ -22,7 +22,7 @@ def init(plugindirs=None): dsdl.pyang_plugin_init() # initialize installed plugins - if sys.version_info >= (3, 12): + if sys.version_info >= (3, 10): eps = list(metadata.entry_points(group='pyang.plugin')) else: eps = pkg_resources.iter_entry_points(group='pyang.plugin')