def apply_augments(self, auglist, p_elem, pset): """Handle substatements of augments from `auglist`. The augments are applied in the context of `p_elem`. `pset` is a patch set containing patches that may be applicable to descendants. """ for a in auglist: par = a.parent if p_elem.name == "choice" or a.search_one("when") is None: wel = p_elem else: if p_elem.interleave: kw = "interleave" else: kw = "group" wel = SchemaNode(kw, p_elem, interleave=p_elem.interleave) wel.occur = p_elem.occur if par.keyword == "uses": self.handle_substmts(a, wel, pset) continue if par.keyword == "submodule": mnam = par.i_including_modulename else: mnam = par.arg if self.prefix_stack[-1] == self.module_prefixes[mnam]: self.handle_substmts(a, wel, pset) else: self.prefix_stack.append(self.module_prefixes[mnam]) self.handle_substmts(a, wel, pset) self.prefix_stack.pop()
def notification_stmt(self, stmt, p_elem, pset): notel = SchemaNode.element("nmt:notification", self.notifications, occur=2) elem = SchemaNode.element(self.prefix_id(stmt.arg), notel, occur=2) plist, new_pset = self.select_patch(pset, stmt.arg) for s in plist: self.handle_stmt(s, elem, new_pset) self.handle_substmts(stmt, elem, new_pset)
def range_params(self, ran, kw): """Return list of <param>s corresponding to range `ran`. `kw` is the statement keyword determining the type of the range, i.e. 'range' or 'length'. `ran` is the internal representation of a range as constructed by the `get_ranges` method. """ if kw == "length": if ran[0][0] != "m" and (len(ran) == 1 or ran[0] == ran[1]): elem = SchemaNode("param").set_attr("name","length") elem.text = ran[0] return [elem] min_ = SchemaNode("param").set_attr("name","minLength") max_ = SchemaNode("param").set_attr("name","maxLength") else: if len(ran) == 1: ran *= 2 # duplicating the value min_ = SchemaNode("param").set_attr("name","minInclusive") max_ = SchemaNode("param").set_attr("name","maxInclusive") res = [] if ran[0][0] != "m": elem = min_ elem.text = ran[0] res.append(elem) if ran[1][0] != "m": elem = max_ elem.text = ran[1] res.append(elem) return res
def bits_type(self, tchain, p_elem): elem = SchemaNode("list", p_elem) zom = SchemaNode("zeroOrMore", elem) choi = SchemaNode.choice(zom, occur=2) for bit in tchain[0].search("bit"): optel = SchemaNode("optional", choi) SchemaNode("value", optel, bit.arg)
def notification_stmt(self, stmt, p_elem, pset): notel = SchemaNode("nma:notification", self.notifications) notel.occur = 2 elem = SchemaNode.element(self.qname(stmt), notel, interleave=True, occur=2) augs, new_pset = self.process_patches(pset, stmt, elem)[1:] self.handle_substmts(stmt, elem, new_pset) self.apply_augments(augs, elem, new_pset)
def gen_data(): elem = SchemaNode("data").set_attr("type", self.datatype_map[typ]) if typ == "decimal64": fd = tchain[0].search_one("fraction-digits").arg SchemaNode("param", elem, "19").set_attr("name", "totalDigits") SchemaNode("param", elem, fd).set_attr("name", "fractionDigits") return elem
def must_stmt(self, stmt, p_elem, pset): mel = SchemaNode("nma:must", p_elem) mel.attr["assert"] = self.yang_to_xpath(stmt.arg) em = stmt.search_one("error-message") if em: SchemaNode("nma:error-message", mel, em.arg) eat = stmt.search_one("error-app-tag") if eat: SchemaNode("nma:error-app-tag", mel, eat.arg)
def create_roots(self): """Create root elements for conf. data, RPCs and notifications.""" self.root = SchemaNode.element("nmt:netmod-tree", interleave=False, occur=2) self.confdata = SchemaNode.element("nmt:top", self.root, interleave=True, occur=2) self.rpcs = SchemaNode.element("nmt:rpc-methods", self.root, interleave=False, occur=2) self.notifications = SchemaNode.element("nmt:notifications", self.root, interleave=True, occur=2)
def range_params(self, ran, kw): """Return list of <param>s corresponding to range `ran`. `kw` is the statement keyword determining the type of the range, i.e. 'range' or 'length'. `ran` is the internal representation of a range as constructed by the `get_ranges` method. """ if kw == "length": if ran[0][0] != "m" and (len(ran) == 1 or ran[0] == ran[1]): elem = SchemaNode("param").set_attr("name", "length") elem.text = ran[0] return [elem] min_ = SchemaNode("param").set_attr("name", "minLength") max_ = SchemaNode("param").set_attr("name", "maxLength") else: if len(ran) == 1: ran *= 2 # duplicating the value min_ = SchemaNode("param").set_attr("name", "minInclusive") max_ = SchemaNode("param").set_attr("name", "maxInclusive") res = [] if ran[0][0] != "m": elem = min_ elem.text = ran[0] res.append(elem) if ran[1][0] != "m": elem = max_ elem.text = ran[1] res.append(elem) return res
def anyxml_stmt(self, stmt, p_elem, pset): self.has_anyxml = True elem = SchemaNode.element(self.qname(stmt), p_elem) SchemaNode("ref", elem).set_attr("name", "__anyxml__") refd = self.process_patches(pset, stmt, elem)[0] if p_elem.name == "choice": elem.occur = 3 elif refd["mandatory"] or stmt.search_one("mandatory", "true"): elem.occur = 2 self.propagate_occur(p_elem, 2) self.handle_substmts(stmt, elem)
def container_stmt(self, stmt, p_elem, pset): celem = SchemaNode.element(self.qname(stmt), p_elem) refd, augs, new_pset = self.process_patches(pset, stmt, celem) left = self.lookup_expand(stmt, new_pset.keys()) for a in augs: left = self.lookup_expand(a, left) if (p_elem.name == "choice" and p_elem.default_case != stmt.arg or refd["presence"] or stmt.search_one("presence")): celem.occur = 3 self.handle_substmts(stmt, celem, new_pset) self.apply_augments(augs, celem, new_pset) if not celem.children: SchemaNode("empty", celem)
def rpc_stmt(self, stmt, p_elem, pset): rpcel = SchemaNode.element("nmt:rpc-method", self.rpcs, occur=2) rlist, r_pset = self.select_patch(pset, stmt.arg) inpel = SchemaNode.element("nmt:input", rpcel, occur=2) elem = SchemaNode.element(self.prefix_id(stmt.arg), inpel, occur=2) inst = stmt.search_one("input") if inst: ilist, i_pset = self.select_patch(r_pset, "input") for s in ilist: self.handle_stmt(s, elem, i_pset) self.handle_substmts(inst, elem, i_pset) for s in rlist: self.handle_stmt(s, elem, r_pset) self.handle_substmts(stmt, rpcel, r_pset)
def case_stmt(self, stmt, p_elem, pset): celem = SchemaNode.case(p_elem) if p_elem.default_case != stmt.arg: celem.occur = 3 refd, augs, new_pset = self.process_patches(pset, stmt, celem) left = self.lookup_expand(stmt, new_pset.keys()) for a in augs: left = self.lookup_expand(a, left) self.handle_substmts(stmt, celem, new_pset) self.apply_augments(augs, celem, new_pset) if not celem.children: celem.subnode(SchemaNode("empty"))
def handle_extension(self, stmt, p_elem): """Append YIN representation of `stmt`.""" ext = stmt.i_extension prf, extkw = stmt.raw_keyword prefix = self.add_namespace(self.prefix_to_ns(prf), prf) eel = SchemaNode(prefix + ":" + extkw, p_elem) argst = ext.search_one("argument") if argst: if argst.search_one("yin-element", "true"): SchemaNode(prefix + ":" + argst.arg, eel, stmt.arg) else: eel.attr[argst.arg] = stmt.arg self.handle_substmts(stmt, eel)
def anyxml_stmt(self, stmt, p_elem, pset): self.has_anyxml = True elem = SchemaNode.element(self.prefix_id(stmt.arg), p_elem) SchemaNode("ref", elem).set_attr("name", "__anyxml__") plist = self.select_patch(pset, stmt.arg)[0] if p_elem.name == "choice": elem.occur = 3 elif self.is_mandatory(stmt, plist): elem.occur = 2 self.propagate_occur(p_elem, 2) for s in plist: self.handle_stmt(s, elem) self.handle_substmts(stmt, elem)
def list_stmt(self, stmt, p_elem, pset): lelem = SchemaNode.list(self.qname(stmt), p_elem) keyst = stmt.search_one("key") if keyst: lelem.keys = [self.add_prefix(k, stmt) for k in keyst.arg.split()] refd, augs, new_pset = self.process_patches(pset, stmt, lelem) left = self.lookup_expand(stmt, new_pset.keys() + lelem.keys) for a in augs: left = self.lookup_expand(a, left) lelem.minEl, lelem.maxEl = self.get_minmax(stmt, refd) if int(lelem.minEl) > 0: self.propagate_occur(p_elem, 2) self.handle_substmts(stmt, lelem, new_pset) self.apply_augments(augs, lelem, new_pset) if not lelem.children: SchemaNode("empty", lelem)
def handle_extension(self, stmt, p_elem): """Append YIN representation of extension statement `stmt`.""" ext = stmt.i_extension prf, extkw = stmt.raw_keyword (modname, rev) = stmt.i_module.i_prefixes[prf] prefix = self.add_namespace( statements.modulename_to_module(self.module, modname, rev)) eel = SchemaNode(prefix + ":" + extkw, p_elem) argst = ext.search_one("argument") if argst: if argst.search_one("yin-element", "true"): SchemaNode(prefix + ":" + argst.arg, eel, stmt.arg) else: eel.attr[argst.arg] = stmt.arg self.handle_substmts(stmt, eel)
def add_identity(self, ident): """Add `id_stmt` and all derivates to `self.identities`. `ident` must be a fully qualified identity name. """ def trname(iname): return "__" + iname.replace(":","_") if ident in self.identities: return parent = SchemaNode.define(trname(ident)) self.identities[ident] = parent if self.identity_deps[ident]: parent = SchemaNode.choice(parent, occur=2) SchemaNode("value", parent, ident).attr["type"]="QName" for i in self.identity_deps[ident]: SchemaNode("ref", parent).attr["name"]=trname(i) self.add_identity(i)
def leaf_list_stmt(self, stmt, p_elem, pset): lelem = SchemaNode.leaf_list(self.qname(stmt), p_elem) lelem.attr["nma:leaf-list"] = "true" refd = self.process_patches(pset, stmt, lelem)[0] lelem.minEl, lelem.maxEl = self.get_minmax(stmt, refd) if int(lelem.minEl) > 0: self.propagate_occur(p_elem, 2) self.handle_substmts(stmt, lelem)
def identityref_type(self, tchain, p_elem): bid = tchain[0].search_one("base").i_identity module = self.main_module(bid) qid = self.module_prefixes[module.arg] + ":" + bid.arg self.add_identity(qid) SchemaNode("ref", p_elem).set_attr("name", "__" + qid.replace(":", "_"))
def case_stmt(self, stmt, p_elem, pset): celem = SchemaNode.case(p_elem) if p_elem.default_case != stmt.arg: celem.occur = 3 plist, new_pset = self.select_patch(pset, stmt.arg) for s in plist: self.handle_stmt(s, celem, new_pset) self.handle_substmts(stmt, celem, new_pset)
def type_stmt(self, stmt, p_elem, pset): """Handle ``type`` statement. Built-in types are handled by a specific type callback method defined below. """ typedef = stmt.i_typedef if typedef and not stmt.i_is_derived: # just ref uname = self.unique_def_name(typedef) if uname not in self.defs: self.install_def(uname, typedef) SchemaNode("ref", p_elem).set_attr("name", uname) defst = typedef.search_one("default") if defst: self.defs[uname].default = defst.arg occur = 1 else: occur = self.defs[uname].occur if occur > 0: self.propagate_occur(p_elem, occur) return chain = [stmt] tdefault = None while typedef: type_ = typedef.search_one("type") chain.insert(0, type_) if tdefault is None: tdef = typedef.search_one("default") if tdef: tdefault = tdef.arg typedef = type_.i_typedef if tdefault and p_elem.occur == 0: p_elem.default = tdefault p_elem.occur = 1 self.propagate_occur(p_elem.parent, 1) self.type_handler[chain[0].arg](chain, p_elem)
def leaf_list_stmt(self, stmt, p_elem, pset): lelem = SchemaNode.leaf_list(self.prefix_id(stmt.arg), p_elem) plist = self.select_patch(pset, stmt.arg)[0] lelem.minEl, lelem.maxEl = self.get_minmax(stmt, plist) for s in plist: self.handle_stmt(s, lelem) self.handle_substmts(stmt, lelem)
def insert_doc(self, p_elem, docstring): """Add <a:documentation> with `docstring` to `p_elem`.""" dtag = self.namespaces[self.a_uri] + ":documentation" elem = SchemaNode(dtag, text=docstring) pos = 0 for ch in p_elem.children: if ch.name == dtag: pos += 1 p_elem.children.insert(pos, elem)
def add_identity(self, ident): """Add `id_stmt` and all derivates to `self.identities`. `ident` must be a fully qualified identity name. """ def trname(iname): return "__" + iname.replace(":", "_") if ident in self.identities: return parent = SchemaNode.define(trname(ident)) self.identities[ident] = parent if self.identity_deps[ident]: parent = SchemaNode.choice(parent, occur=2) SchemaNode("value", parent, ident).attr["type"] = "QName" for i in self.identity_deps[ident]: SchemaNode("ref", parent).attr["name"] = trname(i) self.add_identity(i)
def create_roots(self, yam): """Create the top-level structure for module `yam`.""" self.local_grammar = SchemaNode("grammar") self.local_grammar.attr["ns"] = yam.search_one("namespace").arg self.local_grammar.attr["nma:module"] = self.module.arg src_text = "YANG module '%s'" % yam.arg revs = yam.search("revision") if len(revs) > 0: src_text += " revision %s" % self.current_revision(revs) self.dc_element(self.local_grammar, "source", src_text) start = SchemaNode("start", self.local_grammar) self.data = SchemaNode("nma:data", start, interleave=True) self.data.occur = 2 self.rpcs = SchemaNode("nma:rpcs", start, interleave=False) self.notifications = SchemaNode("nma:notifications", start, interleave=False)
def handle_empty(self): """Handle empty subtree(s) of conceptual tree. If any of the subtrees of the conceptual tree is empty, put <empty/> as its content. """ if self.no_data: return for subtree in (self.confdata, self.rpcs, self.notifications): if len(subtree.children) == 0: SchemaNode("empty", subtree)
def list_stmt(self, stmt, p_elem, pset): lelem = SchemaNode.list(self.prefix_id(stmt.arg), p_elem) plist, new_pset = self.select_patch(pset, stmt.arg) lelem.minEl, lelem.maxEl = self.get_minmax(stmt, plist) keyst = stmt.search_one("key") if keyst: self.lists.append(lelem) lelem.keys = [self.prefix_id(k) for k in keyst.arg.split()] for s in plist: self.handle_stmt(s, lelem, new_pset) self.handle_substmts(stmt, lelem, new_pset)
def if_feature_stmt(self, stmt, p_elem, pset): feat = stmt.i_feature module = self.main_module(feat) try: if feat.arg not in module.i_active_features: p_elem.subnode(SchemaNode("notAllowed")) except TypeError: # slot i_active_features missing self.add_namespace(module) p_elem.attr["nma:if-feature"] = \ self.module_prefixes[module.arg] + ":" + feat.arg
def container_stmt(self, stmt, p_elem, pset): celem = SchemaNode.element(self.prefix_id(stmt.arg),p_elem) plist, new_pset = self.select_patch(pset, stmt.arg) if p_elem.name == "choice": if p_elem.default_case != stmt.arg: celem.occur = 3 elif ([ s for s in plist if s.keyword == "presence"] or stmt.search_one("presence")): celem.occur = 3 for s in plist: self.handle_stmt(s, celem, new_pset) self.handle_substmts(stmt, celem, new_pset)
def rpc_stmt(self, stmt, p_elem, pset): rpcel = SchemaNode("nma:rpc", self.rpcs) r_pset = self.process_patches(pset, stmt, rpcel)[2] inpel = SchemaNode("nma:input", rpcel) elem = SchemaNode.element(self.qname(stmt), inpel, occur=2) augs, pset = self.process_patches(r_pset,stmt,elem,"input")[1:] inst = stmt.search_one("input") if inst: self.handle_substmts(inst, elem, pset) else: SchemaNode("empty", elem) self.apply_augments(augs, elem, pset) augs, pset = self.process_patches(r_pset,stmt,None,"output")[1:] oust = stmt.search_one("output") if oust or augs: outel = SchemaNode("nma:output", rpcel) outel.occur = 2 if oust: self.handle_substmts(oust, outel, pset) self.apply_augments(augs, outel, pset) self.handle_substmts(stmt, rpcel, r_pset)
def choice_stmt(self, stmt, p_elem, pset): chelem = SchemaNode.choice(p_elem) chelem.attr["nma:name"] = stmt.arg refd, augs, new_pset = self.process_patches(pset, stmt, chelem) left = self.lookup_expand(stmt, new_pset.keys()) for a in augs: left = self.lookup_expand(a, left) if refd["mandatory"] or stmt.search_one("mandatory", "true"): chelem.attr["nma:mandatory"] = "true" self.propagate_occur(chelem, 2) else: defv = self.get_default(stmt, refd) if defv is not None: chelem.default_case = defv else: chelem.occur = 3 self.handle_substmts(stmt, chelem, new_pset) self.apply_augments(augs, chelem, new_pset) if not chelem.children: chelem.subnode(SchemaNode("empty"))
def type_with_ranges(self, tchain, p_elem, rangekw, gen_data): """Handle types with 'range' or 'length' restrictions.""" ranges = self.get_ranges(tchain, rangekw) if not ranges: return p_elem.subnode(gen_data()) if len(ranges) > 1: p_elem = SchemaNode.choice(p_elem) p_elem.occur = 2 for r in ranges: d_elem = gen_data() for p in self.range_params(r, rangekw): d_elem.subnode(p) p_elem.subnode(d_elem)
def container_stmt(self, stmt, p_elem, pset): celem = SchemaNode.element(self.prefix_id(stmt.arg), p_elem) plist, new_pset = self.select_patch(pset, stmt.arg) if p_elem.name == "choice": if p_elem.default_case != stmt.arg: celem.occur = 3 elif ([s for s in plist if s.keyword == "presence"] or stmt.search_one("presence")): celem.occur = 3 for s in plist: self.handle_stmt(s, celem, new_pset) self.handle_substmts(stmt, celem, new_pset)
def choice_stmt(self, stmt, p_elem, pset): chelem = SchemaNode.choice(p_elem) plist, new_pset = self.select_patch(pset, stmt.arg) if self.is_mandatory(stmt, plist): chelem.occur = 2 self.propagate_occur(chelem.parent, 2) else: defv = self.get_default(stmt, plist) if defv: chelem.default_case = defv else: chelem.occur = 3 for s in plist: self.handle_stmt(s, chelem, new_pset) self.handle_substmts(stmt, chelem, new_pset)
def install_def(self, name, dstmt, def_map, interleave=False): """Install definition `name` into the appropriate dictionary. `dstmt` is the definition statement ('typedef' or 'grouping') that is to be mapped to a RELAX NG named pattern '<define name="`name`">'. `def_map` must be either `self.local_defs` or `self.global_defs`. `interleave` determines the interleave status inside the definition. """ delem = SchemaNode.define(name, interleave=interleave) delem.attr["name"] = name def_map[name] = delem if def_map is self.global_defs: self.gg_level += 1 self.handle_substmts(dstmt, delem) if def_map is self.global_defs: self.gg_level -= 1
def type_with_ranges(self, tchain, p_elem, rangekw, gen_data): """Handle types with 'range' or 'length' restrictions. `tchain` is the chain of type definitions from which the ranges may need to be extracted. `rangekw` is the statement keyword determining the range type (either 'range' or 'length'). `gen_data` is a function that generates the output schema node (a RELAX NG <data> pattern). """ ranges = self.get_ranges(tchain, rangekw) if not ranges: return p_elem.subnode(gen_data()) if len(ranges) > 1: p_elem = SchemaNode.choice(p_elem) p_elem.occur = 2 for r in ranges: d_elem = gen_data() for p in self.range_params(r, rangekw): d_elem.subnode(p) p_elem.subnode(d_elem)
def leaf_stmt(self, stmt, p_elem, pset): qname = self.qname(stmt) elem = SchemaNode.element(qname) if p_elem.name == "_list_" and qname in p_elem.keys: p_elem.keymap[qname] = elem elem.occur = 2 else: p_elem.subnode(elem) refd = self.process_patches(pset, stmt, elem)[0] if p_elem.name == "choice": if p_elem.default_case != stmt.arg: elem.occur = 3 elif refd["mandatory"] or stmt.search_one("mandatory", "true"): self.propagate_occur(elem, 2) if elem.occur == 0: defv = self.get_default(stmt, refd) if defv is not None: elem.default = defv self.propagate_occur(elem, 1) self.handle_substmts(stmt, elem)
def leaf_stmt(self, stmt, p_elem, pset): def handle_default(): defv = self.get_default(stmt, plist) if defv and elem.occur == 0: elem.occur = 1 elem.default = defv self.propagate_occur(elem.parent, 1) qname = self.prefix_id(stmt.arg) elem = SchemaNode.element(qname) plist = self.select_patch(pset, stmt.arg)[0] p_elem.subnode(elem) if p_elem.name == "choice": if p_elem.default_case == stmt.arg: handle_default() else: elem.occur = 3 elif self.is_mandatory(stmt, plist): self.propagate_occur(elem, 2) else: handle_default() for s in plist: self.handle_stmt(s, elem) self.handle_substmts(stmt, elem)
def choice_type(self, tchain, p_elem): """Handle ``enumeration`` and ``union`` types.""" elem = SchemaNode.choice(p_elem, occur=2) self.handle_substmts(tchain[0], elem)
def boolean_type(self, tchain, p_elem): elem = SchemaNode.choice(p_elem, occur=2) SchemaNode("value", elem, "true") SchemaNode("value", elem, "false")
def get_data(): elem = SchemaNode("data").set_attr("type", "string") for p in pels: elem.subnode(p) return elem
def instance_identifier_type(self, tchain, p_elem): SchemaNode("data", p_elem).set_attr("type", "string") ii = SchemaNode("nma:instance-identifier", p_elem) rinst = tchain[0].search_one("require-instance") if rinst: ii.attr["require-instance"] = rinst.arg