def i_to_o_list_keys(stmt, new_list): """Return a new list statement in OC format.""" assert stmt.keyword == "list", "Expected list statement" # For each child of the list: # - create a new top-level leafref for any keys mapping to the # respective item in the new config container. for child in stmt.i_children: if (child.i_config and hasattr(child, "i_is_key") and child.i_is_key): # Add a leaf-ref under the list. new_child = statements.Statement(stmt.top, new_list, stmt.pos, "leaf", child.arg) new_child.i_config = True new_child.i_module = stmt.i_module new_list.substmts.append(new_child) new_list.i_children.append(new_child) new_list.i_key.append(new_child) new_child_type = statements.Statement(stmt.top, new_child, stmt.pos, "type", "leafref") new_child_type.i_config = True new_child_type.i_module = stmt.i_module new_child_type.i_children = [] new_child.substmts.append(new_child_type) new_child_type_path = statements.Statement( stmt.top, new_child_type, stmt.pos, "path", "../config/{}".format(new_child.arg)) new_child_type_path.i_config = True new_child_type_path.i_module = stmt.i_module new_child_type.substmts.append(new_child_type_path)
def create_config_and_state_containers(parent): config = statements.Statement(parent.top, parent, parent.pos, "container", "config") config.i_config = True # config.i_module = parent.i_module # config.i_children = [] config_desc = statements.Statement(parent.top, config, parent.pos, "description", "Contains intended configuration") config.substmts.append(config_desc) config.inserted = False state = statements.Statement(parent.top, parent, parent.pos, "container", "state") state.i_config = False # state.i_module = parent.i_module # state.i_children = [] state_config = statements.Statement(parent.top, state, parent.pos, "config", "false") state.substmts.append(state_config) state_desc = statements.Statement( parent.top, state, parent.pos, "description", "Contains applied configuration and derived state") state.substmts.append(state_desc) state.inserted = False return (config, state)
def add_leaf_name_parameters(leaf_name, module): leaf_name.i_config = True leaf_name.i_default = None leaf_name.i_default_str = "" leaf_name.i_groupings = dict() leaf_name.i_is_key = True leaf_name.i_leafref = None leaf_name.i_leafref_expanded = False leaf_name.i_leafref_ptr = None leaf_name.i_module = module leaf_name.i_origin_module = module leaf_name.i_typedefs = dict() leaf_name.i_uniques = list() leaf_name.is_grammatically_valid = True leaf_name_type = statements.Statement( module, leaf_name, error.Position("Automatically inserted statement"), "type", "string") leaf_name_type.i_groupings = dict() leaf_name_type.i_is_derived = False leaf_name_type.i_is_validated = True leaf_name_type.i_lengths = list() leaf_name_type.i_module = module leaf_name_type.i_origin_module = module leaf_name_type.i_ranges = list() leaf_name_type.i_type_spec = types.StringTypeSpec() leaf_name_type.i_type_spec.base = None leaf_name_type.i_type_spec.definition = "" leaf_name_type.i_type_spec.name = "string" leaf_name_type.i_typedef = None leaf_name_type.i_typedefs = dict() leaf_name_type.i_uniques = list() leaf_name_type.is_grammatically_valid = True leaf_name_mandatory = statements.Statement( module, leaf_name, error.Position("Automatically inserted statement"), "mandatory", "true") leaf_name_mandatory.i_groupings = dict() leaf_name_mandatory.i_module = module leaf_name_mandatory.i_origin_module = module leaf_name_mandatory.i_typedefs = dict() leaf_name_mandatory.i_uniques = list() leaf_name_mandatory.is_grammatically_valid = True leaf_name_description = statements.Statement( module, leaf_name, error.Position("Automatically inserted statement"), "description", "Name of the {0} service".format(module.arg)) leaf_name_description.i_groupings = dict() leaf_name_description.i_module = module leaf_name_description.i_origin_module = module leaf_name_description.i_typedefs = dict() leaf_name_description.i_uniques = list() leaf_name_description.is_grammatically_valid = True leaf_name.substmts.append(leaf_name_type) leaf_name.substmts.append(leaf_name_mandatory) leaf_name.substmts.append(leaf_name_description)
def i_to_o_list_keys(stmt): """Return a new list statement in OC format.""" assert stmt.keyword == "list", "Expected list statement" new_substmts = [] def attrsearch(tag, attr, lst): for x in lst: if x.__dict__[attr] == tag: return x return None key_stmt = stmt.search_one('key') for x in key_stmt.arg.split(): if x == '': continue if x.find(":") == -1: name = x else: [prefix, name] = x.split(':', 1) #ptr = attrsearch(name, 'arg', stmt.i_children) if True: # For each child of the list: # - create a new top-level leafref for any keys mapping to the # respective item in the new config container. #for child in stmt.i_children: #if (hasattr(child, "i_is_key") and child.i_is_key): # Prepend a leaf-ref under the list. key_leafref = statements.Statement(stmt.top, stmt, stmt.pos, "leaf", name) key_leafref.i_config = True new_substmts.append(key_leafref) #stmt.i_key.insert(index, key_leafref) new_child_type = statements.Statement(stmt.top, key_leafref, stmt.pos, "type", "leafref") new_child_type.i_config = True key_leafref.substmts.append(new_child_type) new_child_desc = statements.Statement( stmt.top, key_leafref, stmt.pos, "description", "Structural leafref to equivalent leaf in ./config container") key_leafref.substmts.append(new_child_desc) new_child_type_path = statements.Statement( stmt.top, new_child_type, stmt.pos, "path", "../config/{}".format(key_leafref.arg)) new_child_type_path.i_config = True #new_child_type_path.i_module = stmt.i_module new_child_type.substmts.append(new_child_type_path) return (new_substmts)
def gen_new_import(module, modname, revision): i = 0 pre = "p" + str(i) while pre in module.i_prefixes: i = i + 1 pre = "p" + str(i) module.i_prefixes[pre] = (modname, revision) imp = statements.Statement(module, module, None, 'import', modname) if revision is not None: rev = statements.Statement(module, imp, None, 'revision-date', revision) imp.substmts.append(rev) module.i_gen_import.append(imp)
def create_enabled_leaf(config_parent): enabled = statements.Statement(config_parent.top, config_parent, config_parent.pos, "leaf", "presence") enabled.i_children = [] enabled.i_config = True enabled.i_module = config_parent.i_module enabled_type = statements.Statement(config_parent.top, enabled, config_parent.pos, "type", "boolean") enabled.substmts.append(enabled_type) enabled_desc = statements.Statement( config_parent.top, enabled, config_parent.pos, "description", config_parent.search_one("presence").arg) enabled.substmts.append(enabled_desc) return (enabled)
def ietf_to_oc(module): """Return a new module tree in OpenConfig format.""" module.arg += "-oc" module.i_modulename = module.arg if augfile == 0: sys.exit("--augfile option missing") if any(c.keyword == "augment" for c in module.substmts): # Find the IETF interfaces import and replace it with # Openconfig interfaces import. for i, s in enumerate(module.substmts): if (s.keyword == "import" and s.arg not in ["ietf-yang-types","ietf-inet-types"]): map_key = aug_config(s.arg, augfile) try: if map_key is None: raise Exception("No match found in import file") except: break imp = statements.Statement(module.top, module, module.pos, "import", map_key[0]) imp.i_module = module pref = statements.Statement(module.top, module, module.pos, "prefix", map_key[1]) pref.i_module = module imp.substmts = [pref] module.substmts[i] = imp # Iterate through the tree. # Looks for any list with config. for child in module.substmts: if child.keyword in ("container", "list", "augment"): new_node = i_to_o_container(child) if child.keyword == "augment": new_node.arg = aug_config(child.arg, augfile) if new_node.arg is None: new_node.arg = child.arg try: index = module.i_children.index(child) module.i_children[index] = new_node except ValueError: pass index = module.substmts.index(child) module.substmts[index] = new_node return module
def ext_module_yang_to_xml(ctx, root, module, yangsearchlist): yangextmods = search(root, yangsearchlist) extrootlist = [] for yangextmod in yangextmods: extmodule = statements.Statement(module, module, None, 'import', yangextmod.attrib['module']) mod = ctx.get_module(extmodule.arg, None) extrootlist.append(yang_to_xml(ctx, mod)) return extrootlist
def add_fake_list_at_beginning(module): top_list = statements.Statement( module, module, error.Position("Automatically inserted statement"), "list", module.arg) leaf_name = statements.Statement( module, top_list, error.Position("Automatically inserted statement"), "leaf", "name") add_leaf_name_parameters(leaf_name, module) top_list.i_config = True top_list.i_is_validated = True top_list.i_key = [leaf_name] top_list.i_module = module top_list.i_origin_module = module top_list.i_typedefs = dict() top_list.i_unique = list() top_list.i_uniques = list() top_list.is_grammatically_valid = True leaf_name_keyword = statements.Statement( module, top_list, error.Position("Automatically inserted statement"), "key", "name") leaf_name_keyword.i_groupings = dict() leaf_name_keyword.i_module = module leaf_name_keyword.i_origin_module = module leaf_name_keyword.i_typedefs = dict() leaf_name_keyword.i_uniques = list() leaf_name_keyword.is_grammatically_valid = True old_list = list(module.i_children) del module.i_children[:] top_list.i_children = [leaf_name] top_list.i_children.extend(old_list) top_list.substmts.append(leaf_name_keyword) top_list.substmts.append(leaf_name) top_list.substmts.extend(old_list) module.i_children.append(top_list) del module.substmts[-len(old_list):] module.substmts.append(top_list)
def i_to_o_list_keys_new(stmt): """Return a new list statement in OC format.""" assert stmt.keyword == "list", "Expected list statement" index = 0 # For each child of the list: # - create a new top-level leafref for any keys mapping to the # respective item in the new config container. for child in stmt.i_children: if (child.i_config and hasattr(child, "i_is_key") and child.i_is_key): # Prepend a leaf-ref under the list. key_leafref = statements.Statement(stmt.top, stmt, stmt.pos, "leaf", child.arg) key_leafref.i_config = True key_leafref.i_module = stmt.i_module stmt.substmts.insert(index, key_leafref) stmt.i_children.insert(index, key_leafref) stmt.i_key.insert(index, key_leafref) new_child_type = statements.Statement(stmt.top, key_leafref, stmt.pos, "type", "leafref") new_child_type.i_config = True new_child_type.i_module = stmt.i_module new_child_type.i_children = [] key_leafref.substmts.append(new_child_type) new_child_desc = statements.Statement( stmt.top, key_leafref, stmt.pos, "description", "Structural leafref to equivalent leaf in ./config container") key_leafref.substmts.append(new_child_desc) new_child_type_path = statements.Statement( stmt.top, new_child_type, stmt.pos, "path", "../config/{}".format(key_leafref.arg)) new_child_type_path.i_config = True new_child_type_path.i_module = stmt.i_module new_child_type.substmts.append(new_child_type_path) index += 1
def gen_new_typedef(module, new_type): i = 0 name = "t" + str(i) all_typedefs = module.search('typedef') + module.i_local_typedefs + \ module.i_gen_typedef while util.attrsearch(name, 'arg', all_typedefs): i = i + 1 name = "t" + str(i) typedef = statements.Statement(module, module, new_type.pos, 'typedef', name) typedef.substmts.append(new_type) module.i_gen_typedef.append(typedef) return name
def ietf_to_oc(module): """Return a new module tree in OpenConfig format.""" module.arg += "-oc" module.i_modulename = module.arg if any(c.keyword == "augment" for c in module.substmts): # Find the IETF interfaces import and replace it with # Openconfig interfaces import. imp = statements.Statement(module.top, module, module.pos, "import", "openconfig-interfaces") imp.i_module = module pref = statements.Statement(module.top, module, module.pos, "prefix", "oc-if") pref.i_module = module imp.substmts = [pref] for i, s in enumerate(module.substmts): if s.keyword == "import" and "ietf-interfaces" in s.arg: module.substmts[i] = imp break # Iterate through the tree. # Looks for any list with config. for child in module.substmts: if child.keyword in ("container", "list", "augment"): new_node = i_to_o_container(child) if child.keyword == "augment": new_node.arg = "/oc-if:interfaces/oc-if:interface" try: index = module.i_children.index(child) module.i_children[index] = new_node except ValueError: pass index = module.substmts.index(child) module.substmts[index] = new_node return module
def get_union(self): stmt = self.stmt nodes = [] typenode = self.get_subnode("type") if typenode is not None: for s in typenode.stmt.substmts: if s.keyword == "type": # Create a fake parent parent = statements.Statement(stmt.top, stmt.parent, stmt.pos, stmt.keyword, stmt.arg) parent.substmts.append(s) nodes.append( drned_node(self.schema, parent, register=False)) return nodes
def mod_desc(stmt, text): desc = stmt.search_one('description') if desc: desc.arg += ' ' + text # XXX for some reason validate_module() crashes with undefined i_module if # add description to module or submodule elif stmt.keyword not in ['module', 'submodule']: desc = statements.Statement(stmt.top, stmt, stmt.pos, 'description', text) stmt.substmts.append(desc) # XXX there may be a better idiom for this if hasattr(stmt, 'i_children'): for child in stmt.i_children: mod_desc(child, text)
def update_or_add_stmt(stmt, keyword, arg, index=None): child = stmt.search_one(keyword) currarg = child.arg if child else None (argval, replace) = get_arg_value(arg, currarg) if argval is None: child = None elif child: if not replace and child.arg and child.arg != argval and child.arg \ != 'TBD': sys.stderr.write('%s: not replacing existing %s %r with %r\n' % (child.pos, keyword, child.arg, argval)) else: child.arg = argval else: child = statements.Statement(stmt.top, stmt, None, keyword, argval) if index is None: index = len(stmt.substmts) # XXX this hack ensures that 'reference' is always last if index > 0 and stmt.substmts[index - 1].keyword == 'reference': index -= 1 stmt.substmts.insert(index, child) return child
def __init__(self, name='builder-generated', top=None, keyword='module'): """Initialize builder. Arguments: name (str): optional name for a hypothetical output module. Note that this argument may be used for debugging purposes, usually the syntax errors will threat this string as a filename. If no name is provided, the string ``builder-generated`` is used. top (pyang.statements.Statement): optional outer-most statement where the subtree will be placed. There is no need to pass this argument: the Builder itself will generate a top statement. Just use it if you plan to append the generated subtree to a pre-existing statement. """ self._pos = (top and top.pos) or Position(name) # Creates a dummy outermost module statement to simplify # traversing tree logic self._top = top or st.Statement(None, None, self._pos, keyword, name) if not self._pos.top: self._pos.top = self._top
def emit_child_stmt(self, parent, node, fd, cont=True): keysign = '' keyprefix = '' uniquesign = '' # manage shorthand omitting case in choice if (parent.keyword == 'choice') and ((node.keyword == 'container') or (node.keyword == 'leaf') or (node.keyword == 'leaf-list') or (node.keyword == 'list')): # 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 <<case>> \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)) parent = newparent if node.keyword == 'container': self.emit_container(parent, node, fd) if cont: for children in node.substmts: self.emit_child_stmt(node, children, fd) elif node.keyword == 'grouping' and not self._ctx.opts.uml_inline: self.emit_grouping(parent, node, fd) elif node.keyword == 'list': self.emit_list(parent, node, fd) if cont: for children in node.substmts: self.emit_child_stmt(node, children, fd) elif node.keyword == 'choice': if (not self.ctx_filterfile): fd.write('class \"%s\" as %s <<choice>> \n' % (self.full_display_path(node), self.full_path(node))) fd.write('%s .. %s : choice \n' % (self.full_path(parent), self.full_path(node))) if cont: for children in node.substmts: # try pointing to parent self.emit_child_stmt(node, children, fd) # self.emit_child_stmt(parent, children, fd) elif node.keyword == 'case': # sys.stderr.write('in case \n') if (not self.ctx_filterfile): fd.write('class \"%s\" as %s <<case>>\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)) if cont: for children in node.substmts: self.emit_child_stmt(node, children, fd) elif node.keyword == 'uses': if (not self.ctx_filterfile) and not (self._ctx.opts.uml_inline): fd.write('%s : %s {uses} \n' % (self.full_path(parent), node.arg)) if not (self._ctx.opts.uml_inline): self.emit_uses(parent, node) if hasattr(node, 'i_grouping') and (self._ctx.opts.uml_inline) and cont: grouping_node = node.i_grouping if grouping_node is not None: # inline grouping here # sys.stderr.write('Found target grouping to inline %s %s \n' %(grouping_node.keyword, grouping_node.arg)) for children in grouping_node.substmts: # make the inlined parent to parent rather then the grouping to make full path unique children.parent = parent self.emit_child_stmt(parent, children, fd) # moved stuff below here in order to include annotations for classes-only elif (node.keyword == 'description') and (self.ctx_description): # make plain ASCII descrstr = ''.join([x for x in node.arg if ord(x) < 128]) self.annotate_node(parent, descrstr, fd) elif node.keyword == 'config': self.annotate_node(parent, "<b>Config = </b>" + node.arg, fd) elif node.keyword == 'must': self.emit_must(parent, node, fd) elif node.keyword == ('tailf-common', 'hidden'): self.annotate_node(parent, "<b>Hidden </b>" + node.arg, fd) elif node.keyword[1] == 'servicepoint': self.annotate_node(parent, "<b>FastMap SERVICE: </b>" + node.arg, fd) # self.lollipop_node(parent, node.arg, fd) elif node.keyword == 'presence': self.annotate_node(parent, "<b>Presence: </b>" + node.arg, fd) elif node.keyword == 'when': self.annotate_node(parent, "<b>When: </b>" + node.arg, fd) elif node.keyword == 'status': self.annotate_node(parent, "<b>Status: </b>" + node.arg, fd) elif node.keyword == 'if-feature': self.annotate_node(parent, "<b>if-feature: </b>" + node.arg, fd) if (not self.ctx_classesonly) and (not self.ctx_filterfile): if node.keyword == 'leaf': if node.arg in self.key: # matches previously found key statement keysign = ' {key}' keyprefix = '+' if node.arg in self.unique: # matches previously found unique statement keysign = ' {unique}' # fd.write('%s : %s%s %s %s\n' %(full_path(parent), keysign, make_plantuml_keyword(node.arg), typestring(node), attribs(node) )) fd.write('%s : %s%s%s %s %s\n' % (self.full_path(parent), keyprefix, node.arg + ' : ', self.typestring(node), keysign, self.attribs(node))) self.emit_must_leaf(parent, node, fd) 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 in ['action', ('tailf-common', 'action')]: self.emit_action(parent, node, fd) elif node.keyword == ('tailf-common', 'callpoint'): fd.write('%s : callpoint:%s()\n' % (self.full_path(parent), node.arg)) elif node.keyword == ('tailf-common', 'cdb-oper'): fd.write('%s : cdboper()\n' % self.full_path(parent)) elif node.keyword == ('anyxml'): fd.write('%s : %s anyxml \n' % (self.full_path(parent), node.arg)) elif node.keyword == 'key': self.key = node.arg.split( " ") # multiple keys, make list of every key elif node.keyword == 'unique': self.unique = node.arg.split( " ") # multiple keys, make list of every key
def i_to_o_container(stmt): """Return a new container/list/etc. in OC format.""" # Make a new statement. new_node = stmt.copy() new_node.i_config = True new_node.i_children = [c for c in stmt.i_children if c.keyword not in statements.data_definition_keywords] new_node.i_key = [] new_node.substmts = [c for c in stmt.substmts if c.keyword not in statements.data_definition_keywords] # Create a new config container under the container. # Create a new state container under the container with config false. # For each child of the container: # - put each config child into both new containers # - put each non-config child into the state container config = statements.Statement(stmt.top, new_node, stmt.pos, "container", "config") config.i_config = True config.i_module = stmt.i_module config.i_children = [] state = statements.Statement(stmt.top, new_node, stmt.pos, "container", "state") state.i_config = False state.i_module = stmt.i_module state.i_children = [] state_config = statements.Statement(stmt.top, state, stmt.pos, "config", "false") state.substmts.append(state_config) if stmt.keyword == "list": # Add new leaf-ref keys i_to_o_list_keys(stmt, new_node) if (stmt.keyword == "container" and stmt.search_one("presence") is not None): # Add an "enabled" leaf of type bool to each new container. enabled = statements.Statement(stmt.top, config, stmt.pos, "leaf", "presence") enabled.i_children = [] enabled.i_config = True enabled.i_module = stmt.i_module enabled_type = statements.Statement(stmt.top, enabled, stmt.pos, "type", "boolean") enabled.substmts.append(enabled_type) enabled_desc = statements.Statement(stmt.top, enabled, stmt.pos, "description", stmt.search_one("presence").arg) enabled.substmts.append(enabled_desc) config.substmts.append(enabled) config.i_children.append(enabled) enabled_s = enabled.copy(parent=state) enabled_s.i_config = False state.substmts.append(enabled) state.i_children.append(enabled) for child in stmt.i_children: # N.B. This will result in containers as substatements of the # "state" container (e.g. statistics in the interface model). if child.i_config: if child.keyword in ("list", "container", "augment"): new_child = i_to_o_container(child) new_node.substmts.append(new_child) new_node.i_children.append(new_child) else: child_copy = child.copy() child_copy.i_config = False config.substmts.append(child) config.i_children.append(child) state.substmts.append(child_copy) state.i_children.append(child_copy) else: # Remove the config false statement. config_stmt = child.search_one("config") if config_stmt is not None: child.substmts.remove(config_stmt) # Append the child to the new state container. state.substmts.append(child) state.i_children.append(child) if len(config.i_children) > 0: new_node.substmts.append(config) new_node.i_children.append(config) if len(state.i_children) > 0: new_node.substmts.append(state) new_node.i_children.append(state) return new_node
def set_revision_details(ctx, stmt, lastrev): revision_done = False # relevant options opts = { 'olddate': ctx.opts.edit_delete_revisions_after, 'newdate': ctx.opts.edit_revision_date, 'description': ctx.opts.edit_revision_description, 'reference': ctx.opts.edit_revision_reference } # the logic is quite tricky; here's what we want to achieve: # * 'olddate' is the date of the oldest revision to be retained; if not # supplied, any existing revisions are deleted # * if 'newdate' is supplied, it's the date of the next published # revision and is to be inserted at the start of any remaining # revisions # * reuse rather than delete the oldest revision statement, purely in # order to retain any blank lines after it # default action is to do nothing action = '' #sys.stderr.write('revision %s (lastrev %s)\n' % (stmt.arg, lastrev)) # only adjust revisions if either olddate or newdate is supplied olddate = opts.get('olddate', None) newdate = opts.get('newdate', None) if olddate is not None or newdate is not None: # determine whether to delete this old revision if olddate is None or stmt.arg > olddate: action = 'delete' #sys.stderr.write('-> delete (olddate %s)\n' % olddate) # determine whether to insert the new revision if newdate is not None and (action != 'delete' or lastrev): action = 'replace' if action == 'delete' else 'insert' #sys.stderr.write('-> %s (newdate %s)\n' % (action, newdate)) # if deleting, return an empty list replstmts = None if action == 'delete': replstmts = [] # replace and insert logic is quite similar: # * if replacing, modify this statement and return a list containing # only it # * if inserting, create a new statement and return a list containing # the new and the original statement elif action == 'replace' or action == 'insert': if action == 'replace': revstmt = stmt revstmt.arg = newdate else: revstmt = statements.Statement(stmt.top, stmt.parent, None, 'revision', newdate) other_keywords = set(opts.keys()) - {'olddate', 'newdate'} for keyword in other_keywords: update_or_add_stmt(revstmt, keyword, opts[keyword]) if action == 'replace': replstmts = [revstmt] else: replstmts = [revstmt, stmt] revision_done = True #sys.stderr.write( # '= %s\n' % ([s.arg for s in replstmts] if replstmts else None)) return replstmts, revision_done
def add_type(leaf, type_name): type_ = statements.Statement(leaf.top, leaf, leaf.pos, 'type', type_name) leaf.substmts.append(type_) return type_
def add_leaf(parent, name, type_name): leaf = statements.Statement(parent.top, parent, parent.pos, 'leaf', name) parent.substmts.append(leaf) add_type(leaf, type_name) return leaf
def __call__(self, keyword, arg=None, children=None, parent=None): """Magic method to generate YANG statements. Arguments: keyword (str): string to be used as keyword for the statement arg (str): argument of the statement Keyword Arguments: children: optional statement or list to be inserted as sub-statement parent (pyang.statements.Statement): optional parent statement Returns: StatementWrapper: wrapper around ``pyang.statements.Statement``. call ``unwrap`` if direct access is necessary. """ children = children or [] if is_statement(keyword): return StatementWrapper(keyword, self) if is_wrapper(keyword): return keyword if isinstance(arg, (list, tuple, st.Statement, StatementWrapper)): children = arg arg = None if not isinstance(children, list): children = [children] if isinstance(arg, bool): arg = str(arg).lower() # ensure arg will be string if arg is not None: arg = str(arg) if keyword in ('module', 'submodule'): node = self._top node.keyword = keyword node.arg = arg node.i_module = node else: parent_node = parent.unwrap() if is_wrapper(parent) else parent node = st.Statement( self._top, parent_node, self._top.pos, keyword, arg) node.i_module = self._top unwraped_children = [] for child in children: if is_wrapper(child): unwraped = child.unwrap() elif isinstance(child, tuple): unwraped = self.from_tuple(child).unwrap() else: unwraped = child unwraped.parent = node unwraped_children.append(unwraped) node.substmts = unwraped_children return StatementWrapper(node, self)