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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 range_params(self, ran, kw): """Return list of <param>s corresponding to `kw` range `ran`. """ specs = { "range": (SchemaNode("value"), SchemaNode("param").set_attr("name", "minInclusive"), SchemaNode("param").set_attr("name", "maxInclusive")), "length": (SchemaNode("param").set_attr("name", "length"), SchemaNode("param").set_attr("name", "minLength"), SchemaNode("param").set_attr("name", "maxLength")) } (exact, min_, max_) = specs[kw] if (len(ran) == 1 or ran[0] == ran[1]) and ran[0][0] != "m": elem = exact elem.text = ran[0] return [elem] 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.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 string_type(self, tchain, p_elem): pels = [] for t in tchain: for pst in t.search("pattern"): pels.append( SchemaNode("param", text=pst.arg).set_attr("name", "pattern")) def get_data(): elem = SchemaNode("data").set_attr("type", "string") for p in pels: elem.subnode(p) return elem self.type_with_ranges(tchain, p_elem, "length", get_data)
def from_modules(self, modules, no_dc=False, no_a=False, record_defs=False, debug=0): self.namespaces = { "urn:ietf:params:xml:ns:netmod:conceptual-tree:1": "nmt", "urn:ietf:params:xml:ns:netmod:dsdl-annotations:1": "nma", } if not no_dc: self.namespaces[self.dc_uri] = "dc" if not no_a: self.namespaces[self.a_uri] = "a" self.defs = {} self.has_anyxml = False self.in_rpc = False self.no_data = True self.debug = debug self.lists = [] self.module_prefixes = {} for module in modules: ns = module.search_one("namespace").arg pref = module.search_one("prefix").arg self.add_namespace(ns, pref) self.module_prefixes[module.arg] = pref self.grammar_elem = SchemaNode("grammar") for module in modules: self.module = module src_text = "YANG module '%s'" % module.arg revs = module.search("revision") if len(revs) > 0: src_text += " revision %s" % self.current_revision(revs) self.dc_element("source", src_text) if record_defs: self.preload_defs() if self.has_data_node(module): if self.no_data: self.no_data = False self.create_roots() ns = self.module.search_one("namespace").arg self.prefix = self.module_prefixes[module.arg] self.handle_substmts(module, self.confdata) for l in self.lists: self.collect_keys(l) self.handle_empty() self.dc_element("creator", "Pyang %s, CTS plugin" % pyang.__version__) return self
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 uses_stmt(self, stmt, p_elem, pset): noexpand = True for sub in stmt.substmts: if sub.keyword in ("refine", "augment"): noexpand = False self.add_patch(pset, Patch(sub, prefix=self.prefix)) if noexpand and pset: # any patch applies to the grouping? noexpand = not self.contains_any(stmt.i_grouping, pset.keys()) if noexpand: uname = self.unique_def_name(stmt.i_grouping, pref="_") if p_elem.interleave == False: uname += "_rpc" if uname not in self.defs: self.install_def(uname, stmt.i_grouping, p_elem.interleave) elem = SchemaNode("ref", p_elem).set_attr("name", uname) occur = self.defs[uname].occur if occur > 0: self.propagate_occur(p_elem, occur) self.handle_substmts(stmt, elem) else: self.handle_substmts(stmt.i_grouping, p_elem, pset)
def uses_stmt(self, stmt, p_elem, pset): expand = False grp = stmt.i_grouping for sub in stmt.substmts: if sub.keyword in ("refine", "augment"): expand = True self.add_patch(pset, sub) if expand: self.lookup_expand(grp, pset.keys()) elif len(self.prefix_stack) <= 1 and not (hasattr(stmt, "d_expand")): uname, dic = self.unique_def_name(stmt.i_grouping, not (p_elem.interleave)) gname = "_" + uname if uname not in dic: self.install_def(gname, stmt.i_grouping, dic, p_elem.interleave) elem = SchemaNode("ref", p_elem).set_attr("name", gname) occur = dic[gname].occur if occur > 0: self.propagate_occur(p_elem, occur) self.handle_substmts(stmt, elem) return self.handle_substmts(grp, p_elem, pset)
def mapped_type(self, tchain, p_elem): """Handle types that are simply mapped to RELAX NG.""" SchemaNode("data", p_elem).set_attr("type", self.datatype_map[tchain[0].arg])
def identityref_type(self, tchain, p_elem): SchemaNode("data", p_elem).set_attr("type", "QName")
def empty_type(self, tchain, p_elem): SchemaNode("empty", p_elem)