<commit_before>"""Tree output plugin

Idea copied from libsmi.
"""

import optparse
import sys
import re
import string

from pyang import plugin
from pyang import statements

def pyang_plugin_init():
    plugin.register_plugin(TreePlugin())

class TreePlugin(plugin.PyangPlugin):
    def add_output_format(self, fmts):
        self.multiple_modules = True
        fmts['tree'] = self

    def add_opts(self, optparser):
        optlist = [
            optparse.make_option("--tree-help",
                                 dest="tree_help",
                                 action="store_true",
                                 help="Print help on tree symbols and exit"),
            optparse.make_option("--tree-depth",
                                 type="int",
                                 dest="tree_depth",
                                 help="Number of levels to print"),
            optparse.make_option("--tree-path",
                                 dest="tree_path",
                                 help="Subtree to print"),
            ]
        g = optparser.add_option_group("Tree output specific options")
        g.add_options(optlist)

    def setup_ctx(self, ctx):
        if ctx.opts.tree_help:
            print_help()
            sys.exit(0)

    def setup_fmt(self, ctx):
        ctx.implicit_errors = False

    def emit(self, ctx, modules, fd):
        if ctx.opts.tree_path is not None:
            path = string.split(ctx.opts.tree_path, '/')
            if path[0] == '':
                path = path[1:]
        else:
            path = None
        emit_tree(modules, fd, ctx.opts.tree_depth, path)

def print_help():
    print """
Each node is printed as:

<status> <flags> <name> <opts>   <type>

  <status> is one of:
    +  for current
    x  for deprecated
    o  for obsolete

  <flags> is one of:
    rw  for configuration data
    ro  for non-configuration data
    -x  for rpcs
    -n  for notifications

  <name> is the name of the node
    (<name>) means that the node is a choice node
   :(<name>) means that the node is a case node

   If the node is augmented into the tree from another module, its
   name is printed as <prefix>:<name>.

  <opts> is one of:
    ?  for an optional leaf or presence container
    *  for a leaf-list
    [<keys>] for a list's keys

  <type> is the name of the type for leafs and leaf-lists
"""    

def emit_tree(modules, fd, depth, path):
    for module in modules:
        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))
        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:
            chs = [ch for ch in chs
                   if ch.arg == path[0]]
            path = path[1:]

        print_children(chs, module, fd, ' ', path, depth)

        rpcs = module.search('rpc')
        if path is not None and len(path) > 0:
            rpcs = [rpc for rpc in rpcs
                    if rpc.arg == path[0]]
            path = path[1:]
        if len(rpcs) > 0:
            fd.write("rpcs:\n")
            print_children(rpcs, module, fd, path, depth, ' ')

        notifs = module.search('notification')
        if path is not None and len(path) > 0:
            notifs = [n for n in notifs
                      if n.arg == path[0]]
            path = path[1:]
        if len(notifs) > 0:
            fd.write("notifications:\n")
            print_children(notifs, module, fd, path, depth, ' ')

def print_children(i_children, module, fd, prefix, path, depth, width=0):
    if depth == 0:
        return
    def get_width(w, chs):
        for ch in chs:
            if ch.keyword in ['choice', 'case']:
                w = get_width(w, ch.i_children)
            else:
                if ch.i_module.i_modulename == module.i_modulename:
                    nlen = len(ch.arg)
                else:
                    nlen = len(ch.i_module.i_prefix) + 1 + len(ch.arg)
                if nlen > w:
                    w = nlen
        return w<commit_msg>fix tree plugin crash when module has rpcs and/or notifs<commit_after>"""Tree output plugin

Idea copied from libsmi.
"""

import optparse
import sys
import re
import string

from pyang import plugin
from pyang import statements

def pyang_plugin_init():
    plugin.register_plugin(TreePlugin())

class TreePlugin(plugin.PyangPlugin):
    def add_output_format(self, fmts):
        self.multiple_modules = True
        fmts['tree'] = self

    def add_opts(self, optparser):
        optlist = [
            optparse.make_option("--tree-help",
                                 dest="tree_help",
                                 action="store_true",
                                 help="Print help on tree symbols and exit"),
            optparse.make_option("--tree-depth",
                                 type="int",
                                 dest="tree_depth",
                                 help="Number of levels to print"),
            optparse.make_option("--tree-path",
                                 dest="tree_path",
                                 help="Subtree to print"),
            ]
        g = optparser.add_option_group("Tree output specific options")
        g.add_options(optlist)

    def setup_ctx(self, ctx):
        if ctx.opts.tree_help:
            print_help()
            sys.exit(0)

    def setup_fmt(self, ctx):
        ctx.implicit_errors = False

    def emit(self, ctx, modules, fd):
        if ctx.opts.tree_path is not None:
            path = string.split(ctx.opts.tree_path, '/')
            if path[0] == '':
                path = path[1:]
        else:
            path = None
        emit_tree(modules, fd, ctx.opts.tree_depth, path)

def print_help():
    print """
Each node is printed as:

<status> <flags> <name> <opts>   <type>

  <status> is one of:
    +  for current
    x  for deprecated
    o  for obsolete

  <flags> is one of:
    rw  for configuration data
    ro  for non-configuration data
    -x  for rpcs
    -n  for notifications

  <name> is the name of the node
    (<name>) means that the node is a choice node
   :(<name>) means that the node is a case node

   If the node is augmented into the tree from another module, its
   name is printed as <prefix>:<name>.

  <opts> is one of:
    ?  for an optional leaf or presence container
    *  for a leaf-list
    [<keys>] for a list's keys

  <type> is the name of the type for leafs and leaf-lists
"""    

def emit_tree(modules, fd, depth, path):
    for module in modules:
        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))
        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:
            chs = [ch for ch in chs
                   if ch.arg == path[0]]
            path = path[1:]

        print_children(chs, module, fd, ' ', path, depth)

        rpcs = module.search('rpc')
        if path is not None and len(path) > 0:
            rpcs = [rpc for rpc in rpcs
                    if rpc.arg == path[0]]
            path = path[1:]
        if len(rpcs) > 0:
            fd.write("rpcs:\n")
            print_children(rpcs, module, fd, ' ', path, depth)

        notifs = module.search('notification')
        if path is not None and len(path) > 0:
            notifs = [n for n in notifs
                      if n.arg == path[0]]
            path = path[1:]
        if len(notifs) > 0:
            fd.write("notifications:\n")
            print_children(notifs, module, fd, ' ', path, depth)

def print_children(i_children, module, fd, prefix, path, depth, width=0):
    if depth == 0:
        return
    def get_width(w, chs):
        for ch in chs:
            if ch.keyword in ['choice', 'case']:
                w = get_width(w, ch.i_children)
            else:
                if ch.i_module.i_modulename == module.i_modulename:
                    nlen = len(ch.arg)
                else:
                    nlen = len(ch.i_module.i_prefix) + 1 + len(ch.arg)
                if nlen > w:
                    w = nlen
        return w
{'fraction_non_alphanumeric': 0.10525691230568411, 'fraction_numerical': 0.004034650528064555, 'mean_word_length': 1.629641185647426, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5286172', 'n_tokens_mistral': 2565, 'n_tokens_neox': 2460, 'n_words': 774}