def get(self, *args): """ Get an item from the list Example: node.get(value) - fetch item where there is a single key. node.get(value1, value2) - fetch item where there is a composite key. Returns a ListElement Node. Alternatively access data by node[value] or node[value1, value2] """ context = self._context node = self._node (keys, values) = Common.Utils.get_key_val_tuples(context, node, list(args)) predicates = Common.Utils.encode_xpath_predicates('', keys, values) if not context.dal.has_item(node.real_data_path + predicates): raise Errors.ListDoesNotContainElement(node.real_data_path + predicates) # Return Object new_node = Common.YangNode(node.libyang_node, node.real_schema_path, node.real_data_path + predicates) return ListElement(context, new_node, self)
def get_yangnode(node, context, attr='', keys=[], values=[], predicates=""): """ Given a node, with a child attribute name, and list of key/values return a libyang schema object and the value path. Each time we return a node we will store the following on the yang node to help with underscore translations. The input to this method will have hyphens converted to underscores. - real_schema_path - real_data_path Libyang itself has schema_path and data_path but these do not know about the underscore translations. Remember: - schemapaths must have the yang module at every component - values paths only require the yang module prefix at the first component. The cache entries are built deliberately not to be a valid path (designated by the %). This is done so that we can lookup the cache without having to carry out processing. """ if len(keys) and len(values): predicates = Utils.encode_xpath_predicates('', keys, values) cache_entry = "!" + node.real_data_path + attr + "!" + predicates + "!" + node.real_schema_path if context.schemacache.is_path_cached(cache_entry): return context.schemacache.get_item_from_cache(cache_entry) real_schema_path = node.real_schema_path if not attr == '': real_attribute_name = Utils.get_original_name( real_schema_path, context, attr) real_schema_path = real_schema_path + '/' + context.module + ":" + real_attribute_name try: node_schema = next(context.schemactx.find_path(real_schema_path)) except libyang.util.LibyangError: raise Errors.NonExistingNode(node.real_schema_path + '/' + context.module + ":" + attr) if not attr == '': real_data_path = node.real_data_path if node_schema.nodetype() not in (Types.LIBYANG_NODETYPE['CHOICE'], Types.LIBYANG_NODETYPE['CASE']): if node.real_data_path == '': real_data_path = '/' + context.module + ':' + real_attribute_name + predicates else: real_data_path = real_data_path + '/' + real_attribute_name + predicates if not attr: real_data_path = node.real_data_path + predicates real_schema_path = node.real_schema_path node_schema = node item = YangNode(node_schema, real_schema_path, real_data_path) context.schemacache.add_entry(cache_entry, item) return item
def get_yang_type(node_schema, value=None, xpath=None, default_to_string=False): """ Map a given yang-type (e.g. string, decimal64) to a type code for the backend. Sysrepo has a few cases- centered around the sr.Val() class 1) For most types we can provide just the value 2) For enumerations we must provide sr.SR_ENUM_T 3) For uint32 (and other uints) we need to provide the type still (we can form the Val object without, but sysrepo will not accept the data) 4) For decimal64 we must not provide any type 5) As long as a uint8/16/32/64 int8/16/32/64 fits the range constraints sysrepo doesn't strictly enforce it (when considering a union of all 8 types). For simple leaves sysrepo is strict. Libyang gives us the following type from node = next(yangctx.find_path(`'/integrationtest:morecomplex/integrationtest:inner/integrationtest:leaf666'`)) node.type().base() Unless we find a Union (11) or leafref (9) then we can just map directly. """ base_type = node_schema.base() if base_type in Types.LIBYANG_MAPPING: return Types.LIBYANG_MAPPING[base_type] if base_type == 9: # LEAF REF base_type = node_schema.leafref_type().base() node_schema = node_schema.leafref_type() if base_type in Types.LIBYANG_MAPPING: return Types.LIBYANG_MAPPING[base_type] if base_type == 11: # Uninon """ Note: for sysrepo if we are a union of enumerations and other types then we must set the data as sr.SR_ENUM_T if it matches the enumeration. e.g. leaf666/type6 """ u_types = [] for union_type in node_schema.union_types(): if union_type.base() == 11: raise NotImplementedError( 'Union containing unions not supported (see README.md)' ) elif union_type.base() == 9: raise NotImplementedError( 'Union containing leafrefs not supported (see README.md)' ) elif union_type.base() == 6: # TODO: we need to lookup enumerations for (val, validx) in union_type.enums(): if str(val) == str(value): return Types.DATA_ABSTRACTION_MAPPING['ENUM'] u_types.append(union_type.base()) if 10 in u_types and isinstance(value, str): return Types.DATA_ABSTRACTION_MAPPING['STRING'] elif Utils.LOOKS_LIKE_A_FLOAT.match(str(value)): return Types.DATA_ABSTRACTION_MAPPING['DECIMAL64'] elif Utils.LOOKS_LIKE_A_NUMBER.match(str(value)): return Utils._find_best_number_type(u_types, int(value)) if value: raise Errors.ValueNotMappedToTypeUnion(xpath, value) if default_to_string: return Types.DATA_ABSTRACTION_MAPPING['STRING'] if value: raise Errors.ValueNotMappedToType(xpath, value) msg = 'Unable to handle the yang type at path ' + str(xpath) msg += ' (this may be listed as a corner-case on the README already' raise NotImplementedError(msg)
def __setattr__(self, attr, value): node = self._node raise Errors.ListItemsMustBeAccesssedByAnElementError( node.real_data_path, attr)
def _raise_ValueDoesMatchEnumeration(node_schema, val): raise Errors.ValueDoesMatchEnumeration(node_schema.real_data_path, val)