def get_ptypes(prop, property_type, type_stmt, one_class_per_module, identity_subclasses): if prop.stmt.keyword == 'anyxml': return ["'str'"] ptypes = [] type_spec = type_stmt.i_type_spec types_extractor = TypesExtractor() if isinstance(type_spec, UnionTypeSpec): for contained_type_stmt in type_spec.types: contained_property_type = types_extractor.get_property_type(contained_type_stmt) ptypes.extend(get_ptypes(prop, contained_property_type, contained_type_stmt, one_class_per_module, identity_subclasses)) else: ptypes.append(get_ptype(prop, property_type, type_stmt, one_class_per_module, identity_subclasses)) return ptypes
def get_ptypes(prop, property_type, type_stmt, one_class_per_module, identity_subclasses): if prop.stmt.keyword == 'anyxml': return ["'str'"] ptypes = [] type_spec = type_stmt.i_type_spec types_extractor = TypesExtractor() if isinstance(type_spec, UnionTypeSpec): for contained_type_stmt in type_spec.types: contained_property_type = types_extractor.get_property_type( contained_type_stmt) ptypes.extend( get_ptypes(prop, contained_property_type, contained_type_stmt, one_class_per_module, identity_subclasses)) else: ptypes.append( get_ptype(prop, property_type, type_stmt, one_class_per_module, identity_subclasses)) return ptypes
def _get_union_types(self, union_leaf): union_type = union_leaf.property_type contained_types = set() for contained_type_stmt in union_type.types: contained_property_type = TypesExtractor().get_property_type(contained_type_stmt) if isinstance(contained_property_type, UnionTypeSpec): contained_types.update(self._get_union_types(contained_property_type)) elif isinstance(contained_property_type, PathTypeSpec): contained_types.add('%s' % self._get_leafref_comment(union_leaf)) else: contained_types.add(contained_type_stmt.i_type_spec.name) return contained_types
def get_meta_info_data(prop, property_type, type_stmt): """ Gets an instance of MetaInfoData that has the useful information about the property. Args: prop: The property property_type : The type under consideration type_stmt : The type stmt currently under consideration """ clazz = prop.owner meta_info_data = MetaInfoData(prop) types_extractor = TypesExtractor() target_type_stmt = type_stmt if isinstance(property_type, Class): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = ':py:class:`%s <%s.%s>`' % ( property_type.name, property_type.get_py_mod_name(), property_type.qn()) if prop.is_many: meta_info_data.mtype = 'REFERENCE_LIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link elif property_type.is_identity(): meta_info_data.mtype = 'REFERENCE_IDENTITY_CLASS' else: meta_info_data.mtype = 'REFERENCE_CLASS' # if the class is local use just the local name if property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() elif isinstance(property_type, Enum): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = ':py:class:`%s <%s.%s>`' % ( property_type.name, property_type.get_py_mod_name(), property_type.qn()) meta_info_data.mtype = 'REFERENCE_ENUM_CLASS' if prop.is_many: meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() elif isinstance(property_type, Bits): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = ':py:class:`%s <%s.%s>`' % ( property_type.name, property_type.get_py_mod_name(), property_type.qn()) meta_info_data.mtype = 'REFERENCE_BITS' if prop.is_many: meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() else: if prop.stmt.keyword == 'leaf-list': meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of ' elif prop.stmt.keyword == 'anyxml': meta_info_data.mtype = 'ANYXML_CLASS' meta_info_data.doc_link = 'anyxml' meta_info_data.ptype = 'object' return meta_info_data else: meta_info_data.mtype = 'ATTRIBUTE' meta_info_data.doc_link = '' type_spec = type_stmt.i_type_spec while isinstance(type_spec, PathTypeSpec): if not hasattr(type_spec, 'i_target_node'): return None target_type_stmt = type_spec.i_target_node.search_one('type') type_spec = target_type_stmt.i_type_spec if isinstance(type_spec, BinaryTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, BitsTypeSpec): # This can happen in a Union raise EmitError('Illegal Code path') elif isinstance(type_spec, BooleanTypeSpec): meta_info_data.ptype = 'bool' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, Decimal64TypeSpec): meta_info_data.ptype = 'Decimal64' meta_info_data.prange.append( ('%s' % type_spec.min.s, '%s' % type_spec.max.s)) # ' :ref:`Decimal64 <ydk_models_types_Decimal64>`' meta_info_data.doc_link += ':py:class:`Decimal64 <ydk.types.Decimal64>`' elif isinstance(type_spec, EmptyTypeSpec): meta_info_data.ptype = 'Empty' # ' :ref:`Empty <ydk_models_types_Empty>`' meta_info_data.doc_link += ':py:class:`Empty <ydk.types.Empty>`' elif isinstance(prop.property_type, Enum): raise EmitError('Illegal Code path') elif isinstance(type_spec, IdentityrefTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, IntTypeSpec): meta_info_data.ptype = 'int' meta_info_data.doc_link += meta_info_data.ptype meta_info_data.prange.append((type_spec.min, type_spec.max)) elif isinstance(type_spec, LengthTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype meta_info_data.prange = get_length_limits(type_spec) elif isinstance(type_spec, PathTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, PatternTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype while hasattr( target_type_stmt, 'i_typedef') and target_type_stmt.i_typedef is not None: target_type_stmt = target_type_stmt.i_typedef.search_one( 'type') pattern = target_type_stmt.search_one('pattern') if pattern is not None: meta_info_data.pattern.append(pattern.arg.encode('ascii')) elif isinstance(type_spec, RangeTypeSpec): meta_info_data.ptype = get_range_base_type_name(type_spec) meta_info_data.prange = get_range_limits(type_spec) meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, StringTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, UnionTypeSpec): # validate against all the data types meta_info_data.mtype = 'REFERENCE_UNION' meta_info_data.ptype = 'str' meta_info_data.property_type = type_spec if len(type_spec.types) > 0: # meta_info_data.doc_link += 'one of { ' for contained_type_stmt in type_spec.types: enum_type_stmt = types_extractor.get_enum_type_stmt( contained_type_stmt) bits_type_stmt = types_extractor.get_bits_type_stmt( contained_type_stmt) union_type_stmt = types_extractor.get_union_type_stmt( contained_type_stmt) contained_property_type = contained_type_stmt.i_type_spec if isinstance(contained_property_type, IdentityrefTypeSpec): contained_property_type = contained_property_type.base.i_identity.i_class elif enum_type_stmt is not None: # this is an enumeration if not hasattr(enum_type_stmt, 'i_enum'): raise EmitError('Failure to get i_enum') contained_property_type = enum_type_stmt.i_enum elif bits_type_stmt is not None: # bits contained_property_type = bits_type_stmt.i_bits elif union_type_stmt is not None: contained_property_type = union_type_stmt child_meta_info_data = get_meta_info_data( prop, contained_property_type, contained_type_stmt) meta_info_data.children.append(child_meta_info_data) # if meta_info_data.doc_link[-1:] != ' ': # meta_info_data.doc_link += ' | ' # meta_info_data.doc_link += child_meta_info_data.doc_link # meta_info_data.doc_link += ' }' elif isinstance(type_spec, TypeSpec) and type_spec.name == 'instance-identifier': # Treat as string meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype else: raise EmitError('Illegal path') return meta_info_data
def __init__(self, ctx): self.ctx = ctx self.types_extractor = TypesExtractor()
class TestCasePrinter(object): def __init__(self, ctx): self.ctx = ctx self.types_extractor = TypesExtractor() def print_testcases(self, package, identity_subclasses): assert isinstance(package, Package) self.identity_subclasses = identity_subclasses self._print_header(package) self._print_body([p for p in package.owned_elements if isinstance(p, Class) and not p.is_identity()]) self._print_trailer() def _print_header(self, package): self._print_imports(package) self._print_class_header(package) def _print_body(self, clazzes): for clazz in clazzes: self._print_test_case(clazz) def _print_trailer(self): self.ctx.lvl_dec() self.ctx.bline() self.ctx.writeln("if __name__ == '__main__':") self.ctx.lvl_inc() self.ctx.writeln("unittest.main()") self.ctx.lvl_dec() def _print_imports(self, package): self._print_common_imports() imports_to_print = self._get_imports(package) for import_to_print in imports_to_print: self.ctx.writeln('%s' % import_to_print) self.ctx.bline() for top_element in [t for t in package.owned_elements if isinstance(t, Class) or isinstance(t, Enum)]: self.ctx.writeln('from %s import %s' % (package.get_py_mod_name(), top_element.name)) def _get_imports(self, package): imports_to_print = [] for imported_type in package.imported_types(): import_stmt = 'from %s import %s' % ( imported_type.get_py_mod_name(), imported_type.qn().split('.')[0]) if import_stmt in imports_to_print: continue else: imports_to_print.append(import_stmt) imports_to_print.extend(x for x in self._get_properties_imports(package) if x not in imports_to_print) imports_to_print = sorted(imports_to_print) return imports_to_print def _get_properties_imports(self, element): leafref_imports = [] if isinstance(element, Class): for prop in element.properties(): if isinstance(prop.property_type, Class) and prop.property_type.is_identity(): ref_class = self.identity_subclasses[prop.property_type][0] child_class = ref_class if ref_class in self.identity_subclasses: child_class = self.identity_subclasses[ref_class][0] leafref_imports.append('from %s import %s' % (child_class.get_py_mod_name(), child_class.qn().split('.')[0])) elif isinstance(prop.property_type, PathTypeSpec): if prop.stmt.i_leafref_ptr is not None: ref_class = prop.stmt.i_leafref_ptr[0].parent.i_class leafref_imports.append('from %s import %s' % (ref_class.get_py_mod_name(), ref_class.qn().split('.')[0])) for clazz in [t for t in element.owned_elements if isinstance(t, Class) and t.is_config() and not t.is_identity()]: leafref_imports.extend(self._get_properties_imports(clazz)) return leafref_imports def _print_common_imports(self): self.ctx.bline() self.ctx.writeln('import unittest') self.ctx.writeln('from tests.compare import is_equal') self.ctx.writeln('from ydk.providers import NativeNetconfServiceProvider') self.ctx.writeln('from ydk.services import CRUDService') self.ctx.writeln('from ydk.types import Decimal64, Empty') self.ctx.bline() def _print_class_header(self, package): self.ctx.bline() self.ctx.bline() self.ctx.writeln('class %sTest(unittest.TestCase):' % package.name) self.ctx.lvl_inc() self._print_setup_class() self._print_teardown_class() self._print_setup(package) self._print_teardown(package) def _print_setup_class(self): self.ctx.bline() self.ctx.writeln('@classmethod') self.ctx.writeln('def setUpClass(self):') self.ctx.lvl_inc() self.ctx.writeln('''self.ncc = NativeNetconfServiceProvider(address='127.0.0.1' , username='******', password='******', port=12022)''') self.ctx.writeln('self.crud = CRUDService()') self.ctx.lvl_dec() def _print_setup(self, package): self.ctx.bline() self.ctx.writeln('def setUp(self):') self.ctx.lvl_inc() self.ctx.writeln("print '\\nIn method '+ self._testMethodName + ':'") for p in package.owned_elements: if isinstance(p, Class) and not p.is_identity() and p.is_config(): self._print_mandatory_leafs(p) self.ctx.lvl_dec() def _print_teardown(self, package): self.ctx.bline() self.ctx.writeln('def tearDown(self):') self.ctx.lvl_inc() top_elements = [p for p in package.owned_elements if isinstance(p, Class) and not p.is_identity() and p.is_config()] if len(top_elements) > 0: self.ctx.writeln('#TEARDOWN TOP ELEMENTS') else: self.ctx.writeln('pass') self.ctx.bline() for clazz in top_elements: self._print_class_instance(clazz, clazz.get_key_props(), suffix='_teardown') self.ctx.writeln('print "Teardown %s"' % get_obj_name(clazz)) self.ctx.writeln('try:') self.ctx.lvl_inc() self.ctx.writeln('self.crud.delete(self.ncc, %s_teardown)' % get_obj_name(clazz)) self.ctx.lvl_dec() self.ctx.writeln('except Exception as e:') self.ctx.lvl_inc() self.ctx.writeln('pass') self.ctx.lvl_dec() self.ctx.bline() self.ctx.lvl_dec() def _print_teardown_class(self): self.ctx.bline() self.ctx.writeln('@classmethod') self.ctx.writeln('def tearDownClass(self):') self.ctx.lvl_inc() self.ctx.writeln('''self.ncc.close()''') self.ctx.lvl_dec() def _print_test_case(self, clazz): for prop in clazz.properties(): if isinstance(prop.property_type, Class) and not prop.property_type.is_identity(): self._print_test_case(prop.property_type) self._print_test_case_header(clazz) self._print_test_case_body(clazz) self._print_test_case_trailer() def _print_test_case_header(self, clazz): self.ctx.writeln('def test_%s(self):' % ('_'.join([snake_case(f) for f in clazz.qn().split('.')]))) self.ctx.lvl_inc() def _print_test_case_trailer(self): self.ctx.lvl_dec() self.ctx.bline() def _print_test_case_body(self, clazz): if not clazz.is_config(): self.ctx.writeln("'''This is an oper field'''") self.ctx.writeln('pass') else: # start building the object tree self._print_leafref_references(clazz) self._print_parents_mandatory_leafs(clazz.owner) self.ctx.writeln('# CREATE') self._print_class_instance(clazz, clazz.properties(), suffix='') self._print_crud_operations(get_obj_name(clazz), clazz) def _print_class_instance(self, clazz, props, suffix): if clazz is None: return owner_obj_name = '' obj_name = get_obj_name_with_suffix(clazz, suffix) if clazz.owner is not None and isinstance(clazz.owner, Class): owner_obj_name = get_obj_name_with_suffix(clazz.owner, suffix) if isinstance(clazz, Class): self.ctx.writeln('%s = %s()' % (obj_name, clazz.qn())) self._print_properties(obj_name, props) if len(clazz.get_key_props()) > 0: self._print_list_obj_append(clazz, clazz.owner, suffix) if isinstance(clazz.owner, Class): self._print_class_instance(clazz.owner, clazz.owner.get_key_props(), suffix) if clazz.owner is not None and isinstance(clazz.owner, Class): self.ctx.writeln('%s.parent = %s' % (obj_name, owner_obj_name)) def _print_properties(self, obj_name, properties): for prop in properties: self._print_property(obj_name, prop) def _print_mandatory_leafs(self, element): mandatory_leafs = self._get_mandatory_leafs(element) if len(mandatory_leafs) > 0: self.ctx.writeln('#MANDATORY LEAFS CREATE') for mandatory_leaf in mandatory_leafs: leafs_to_set = mandatory_leaf.clazz.get_key_props() leafs_to_set.extend(x for x in mandatory_leaf.props if x not in leafs_to_set) self._print_class_instance(mandatory_leaf.clazz, leafs_to_set, suffix='') self.ctx.writeln('print "Creating mandatory %s"' % snake_case(mandatory_leaf.clazz.qn() + '.' + mandatory_leaf.props[0].name)) self.ctx.writeln('self.crud.create(self.ncc, %s)' % get_obj_name(mandatory_leaf.clazz)) self.ctx.bline() def _get_mandatory_leafs(self, element): mandatory_leafs = [] if hasattr(element, 'properties'): mandatory_info = None for prop in element.properties(): mandatory = prop.stmt.search_one('mandatory') if mandatory is not None and mandatory.arg == 'true': if mandatory_info is None: mandatory_info = LeafInfo(element) mandatory_info.props.append(prop) if mandatory_info is not None: mandatory_leafs.append(mandatory_info) for p in element.owned_elements: if isinstance(p, Class) and (not p.is_identity()) and p.is_config() and (p.stmt.search_one('presence') is None) and len(p.get_key_props()) == 0: mandatory_leafs.extend(self._get_mandatory_leafs(p)) return mandatory_leafs def _print_parents_mandatory_leafs(self,clazz): if isinstance(clazz, Class) and not clazz.is_identity() and clazz.is_config(): if clazz.owner is not None: self._print_parents_mandatory_leafs(clazz.owner) self._print_mandatory_leafs(clazz) def _print_leafref_references(self, clazz): leaf_ref_infos = list(reversed(self._get_leafref_references(clazz))) if len(leaf_ref_infos) > 0: self.ctx.writeln('#LEAFREF REFERENCES CREATE') for leaf_info in leaf_ref_infos: reference_clazz = leaf_info.clazz leafs_to_set = leaf_info.props leafs_to_set.extend(x for x in reference_clazz.get_key_props() if x not in leafs_to_set) leafs_to_set.extend(x for x in reference_clazz.properties() if x.stmt.search_one('mandatory') is not None) self._print_class_instance(reference_clazz, leafs_to_set, '_reference') self.ctx.writeln('print "Creating reference %s"' % get_obj_name(reference_clazz)) self.ctx.writeln('self.crud.create(self.ncc, %s_reference)' % get_obj_name(reference_clazz)) self.ctx.bline() def _get_leafref_references(self, clazz): leaf_ref_infos = [] info = None for prop in clazz.properties(): if isinstance(prop.property_type, PathTypeSpec): if prop.stmt.i_leafref_ptr is not None: if info is None: info = LeafInfo(prop.stmt.i_leafref_ptr[0].parent.i_class) info.props.append(prop.stmt.i_leafref_ptr[0].i_property) if info is not None and info not in leaf_ref_infos: leaf_ref_infos.append(info) if clazz.owner is not None and isinstance(clazz.owner, Class): leaf_ref_infos.extend([x for x in self._get_leafref_references(clazz.owner) if x not in leaf_ref_infos]) return leaf_ref_infos def _print_property(self, obj_name, prop): format_string = '%s.%s = %s' if prop.stmt.keyword == 'leaf-list': format_string = '%s.%s.append(%s)' type_spec = prop.property_type type_stmt = prop.stmt.search_one('type') if isinstance(type_spec, UnionTypeSpec): if len(type_spec.types) > 0: type_spec, type_stmt = self._get_union_type_spec(type_spec.types[0]) if type_stmt is not None: if 'prefix' in type_stmt.arg and 'ip' in type_stmt.arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'1.2.3.4/32'")) return elif 'address' in type_stmt.arg and 'ipv6' in type_stmt.arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'123::123'")) return elif 'address' in type_stmt.arg and 'ip' in type_stmt.arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'1.2.3.4'")) return elif 'host' in type_stmt.arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'1.2.3.4'")) return elif 'mac-address' in type_stmt.arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'00:0a:95:9d:68:16'")) return if isinstance(type_spec, Class): if type_spec.is_identity(): ref_class = self.identity_subclasses[type_spec][0] child_class = ref_class if ref_class in self.identity_subclasses: child_class = self.identity_subclasses[ref_class][0] self.ctx.writeln(format_string % (obj_name, prop.name, child_class.qn() + '()')) elif isinstance(type_spec, Enum): self.ctx.writeln(format_string % (obj_name, prop.name, type_spec.qn() + '.' + type_spec.literals[0].name)) elif isinstance(type_spec, Bits): self.ctx.writeln("%s.%s['%s'] = True" % (obj_name, prop.name, list(type_spec._dictionary.keys())[0])) else: target_type_stmt = None while isinstance(type_spec, PathTypeSpec): if not hasattr(type_spec, 'i_target_node'): return target_type_stmt = type_spec.i_target_node.search_one('type') type_spec = target_type_stmt.i_type_spec if target_type_stmt is not None: if 'prefix' in target_type_stmt.arg and 'ip' in target_type_stmt.arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'1.2.3.4/32'")) return elif 'address' in target_type_stmt.arg and 'ip' in target_type_stmt.arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'1.2.3.4'")) return elif 'host' in target_type_stmt.arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'1.2.3.4'")) return if isinstance(type_spec, StringTypeSpec): self.ctx.writeln(format_string % (obj_name, prop.name, "'Hello'")) elif isinstance(type_spec, LengthTypeSpec): ranges = meta_data_util.get_length_limits(type_spec) for min_limit, max_limit in ranges: if isinstance(min_limit, int) and isinstance(max_limit, int): size = (min_limit + max_limit) / 2 else: size = min_limit + 1 test_string = generate_string_of_size(size) self.ctx.writeln(format_string % (obj_name, prop.name, "'" + test_string + "'")) break elif isinstance(type_spec, IntTypeSpec): self.ctx.writeln(format_string % (obj_name, prop.name, '100')) elif isinstance(type_spec, RangeTypeSpec): ranges = meta_data_util.get_range_limits(type_spec) for min_limit, max_limit in ranges: if isinstance(min_limit, int) and isinstance(max_limit, int): size = (min_limit + max_limit) / 2 elif isinstance(min_limit, int): size = min_limit + 1 else: size = int(min_limit) + 1 self.ctx.writeln(format_string % (obj_name, prop.name, str(size))) break elif isinstance(type_spec, Decimal64TypeSpec): self.ctx.writeln(format_string % (obj_name, prop.name, 'Decimal64("1.0")')) elif isinstance(type_spec, BooleanTypeSpec): self.ctx.writeln(format_string % (obj_name, prop.name, 'False')) elif isinstance(type_spec, BinaryTypeSpec): self.ctx.writeln(format_string % (obj_name, prop.name, "'0x00'")) elif isinstance(type_spec, EmptyTypeSpec): self.ctx.writeln(format_string % (obj_name, prop.name, 'Empty()')) elif isinstance(type_spec, PatternTypeSpec): target_type_stmt = prop.stmt.search_one('type') while hasattr(target_type_stmt, 'i_typedef') and target_type_stmt.i_typedef is not None: target_type_stmt = target_type_stmt.i_typedef.search_one('type') pattern = target_type_stmt.search_one('pattern') if pattern is not None: if pattern.arg == '[\w\-\.:,_@#%$\+=\|;]+': self.ctx.writeln(format_string % (obj_name, prop.name, "'abc'")) return elif pattern.arg == '(([a-zA-Z0-9_]*\d+/){3}\d+)|(([a-zA-Z0-9_]*\d+/){4}\d+)|(([a-zA-Z0-9_]*\d+/){3}\d+\.\d+)|(([a-zA-Z0-9_]*\d+/){2}([a-zA-Z0-9_]*\d+))|(([a-zA-Z0-9_]*\d+/){2}([a-zA-Z0-9_]+))|([a-zA-Z0-9_-]*\d+)|([a-zA-Z0-9_-]*\d+\.\d+)|(mpls)|(dwdm)': self.ctx.writeln(format_string % (obj_name, prop.name, "'test1'")) return elif pattern.arg == '(!.+)|([^!].+)': self.ctx.writeln(format_string % (obj_name, prop.name, "'!Hello'")) return elif pattern.arg == '[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\.[a-fA-F0-9]{2}': self.ctx.writeln(format_string % (obj_name, prop.name, "'aa.aaaa.aaaa.aaaa.aa'")) return elif pattern.arg == '(act)|(pre)': self.ctx.writeln(format_string % (obj_name, prop.name, "'act'")) return elif pattern.arg == '((([a-zA-Z0-9_]*\d+)|(\*))/){2}(([a-zA-Z0-9_]*\d+)|(\*))': self.ctx.writeln(format_string % (obj_name, prop.name, "'test1/test1/test1'")) return elif pattern.arg == '[0-9a-fA-F]{1,8}': self.ctx.writeln(format_string % (obj_name, prop.name, "'aaa'")) return elif pattern.arg == '[a-zA-Z0-9][a-zA-Z0-9\._@$%+#:=<>\-]{0,62}': self.ctx.writeln(format_string % (obj_name, prop.name, "'Hello'")) return elif pattern.arg == '([0-9]|[1-5][0-9]|6[0-3])|(([0-9]|[1-5][0-9]|6[0-3])-([0-9]|[1-5][0-9]|6[0-3]))|(af11)|(af12)|(af13)|(af21)|(af22)|(af23)|(af31)|(af32)|(af33)|(af41)|(af42)|(af43)|(ef)|(default)|(cs1)|(cs2)|(cs3)|(cs4)|(cs5)|(cs6)|(cs7)': self.ctx.writeln(format_string % (obj_name, prop.name, "'cs123'")) return elif pattern.arg == '(\d+)|(\d+\-\d+)': self.ctx.writeln(format_string % (obj_name, prop.name, "'123'")) return elif pattern.arg == '([a-zA-Z0-9_]*\d+/){1,2}([a-zA-Z0-9_]*\d+)': self.ctx.writeln(format_string % (obj_name, prop.name, "'a1/a2'")) return if prop.name == 'masklength_range': self.ctx.writeln(format_string % (obj_name, prop.name, "'1..2'")) elif 'address' in prop.stmt.search_one('type').arg and 'ip' in prop.stmt.search_one('type').arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'1.2.3.4'")) elif 'domain' in prop.stmt.search_one('type').arg and 'domain' in prop.stmt.search_one('type').arg: self.ctx.writeln(format_string % (obj_name, prop.name, "'example.com'")) else: #print prop.stmt.search_one('type').arg # if pattern is not None: # print pattern.arg, prop.name self.ctx.writeln("#%s.%s = %s" % (obj_name, prop.name, "'Hello'")) else: # print prop.name, type_spec.arg self.ctx.writeln('#%s.%s = None' % (obj_name, prop.name)) def _get_union_type_spec(self, type_stmt): contained_property_type = self.types_extractor.get_property_type(type_stmt) if isinstance(contained_property_type, UnionTypeSpec): return self._get_union_type_spec(contained_property_type.types[0]) else: return contained_property_type, type_stmt def _print_list_obj_append(self, clazz, owner, suffix): parent_obj_name = get_obj_name_with_suffix(owner, suffix) prop_name = '' if isinstance(owner, Class): for prop in owner.properties(): if isinstance(prop.property_type, Class) and prop.property_type.name == clazz.name: prop_name = prop.name break else: return self.ctx.writeln('%s = %s()' % (parent_obj_name, owner.qn())) self.ctx.writeln('%s.%s.append(%s)' % (parent_obj_name, prop_name, get_obj_name_with_suffix(clazz, suffix))) def _print_crud_operations(self, obj_name, clazz): self.ctx.writeln('print "Creating test %s"' % obj_name) self.ctx.writeln('self.crud.create(self.ncc, %s)' % obj_name) self._print_crud_read_test_operation(obj_name, clazz) self._print_crud_delete_operation(obj_name, clazz) def _print_crud_read_test_operation(self, obj_name, clazz): self.ctx.bline() self.ctx.writeln('# READ') self._print_class_instance(clazz, clazz.get_key_props(), suffix='_read') self.ctx.writeln('print "Reading test %s_read"' % obj_name) self.ctx.writeln('%s_read_output = self.crud.read(self.ncc, %s_read)' % (obj_name, obj_name)) self.ctx.writeln('#self.assertEqual(is_equal(%s, %s_read_output), True)' % (obj_name, obj_name)) def _print_crud_delete_operation(self, obj_name, clazz): self.ctx.bline() self.ctx.writeln('# DELETE') self._print_class_instance(clazz, clazz.get_key_props(), suffix='_delete') self.ctx.writeln('print "Deleting test %s_delete"' % obj_name) self.ctx.writeln('self.crud.delete(self.ncc, %s_delete)' % (obj_name))
def __init__(self, lang, identity_subclasses): self.lang = lang self.identity_subclasses = identity_subclasses self.types_extractor = TypesExtractor() self.type_spec = None self.type_stmt = None
class ValueBuilder(object): """ Return value for terminal nodes (leaf or leaf-list).""" def __init__(self, lang, identity_subclasses): self.lang = lang self.identity_subclasses = identity_subclasses self.types_extractor = TypesExtractor() self.type_spec = None self.type_stmt = None def get_prop_value(self, prop, default=None): """Return value based on prop. Args: prop (ydkgen.api_model.Property): Terminal nodes' property. default (str): default value. Returns: prop_value: Value get based on YANG constraints. It could be string, integer, BitsValue, or IdentityValue. """ self._set_prop_type(prop) prop_value = None if isinstance(self.type_spec, atypes.Bits): prop_value = self._handle_bits() elif is_identity_element(self.type_spec): prop_value = self._handle_identity() elif isinstance(self.type_spec, atypes.Enum): prop_value = self._handle_enum() elif isinstance(self.type_spec, ptypes.BinaryTypeSpec): prop_value = self._handle_binary() elif isinstance(self.type_spec, ptypes.BooleanTypeSpec): prop_value = self._handle_boolean(prop) elif isinstance(self.type_spec, ptypes.Decimal64TypeSpec): prop_value = self._handle_decimal64() elif isinstance(self.type_spec, ptypes.EmptyTypeSpec): prop_value = self._handle_empty() elif isinstance(self.type_spec, ptypes.LengthTypeSpec): prop_value = self._handle_length() elif isinstance(self.type_spec, ptypes.IntTypeSpec): prop_value = self._handle_int() elif isinstance(self.type_spec, ptypes.PatternTypeSpec): prop_value = self._handle_pattern(prop) elif isinstance(self.type_spec, ptypes.RangeTypeSpec): prop_value = self._handle_range() elif isinstance(self.type_spec, ptypes.StringTypeSpec): prop_value = self._handle_string(default=default) return prop_value def _handle_bits(self): """Chose an set a bit.""" val = choice(list(self.type_spec._dictionary.keys())) return BitsValue(val=val, type_spec=self.type_spec) def _handle_identity(self): """Chose and return identity from available derived identities. Identity could come from different bundle. """ identities = set() self._collect_identities(self.type_spec, identities) if (len(identities) == 0): return '' identity = choice(list(identities)) identity_value = '{}()'.format(get_qn(self.lang, identity)) return IdentityValue(val=identity_value, identity=identity) def _handle_enum(self): """Chose an return enum literal.""" literal = choice(self.type_spec.literals) qn = get_qn(self.lang, self.type_spec) return self.nmsp_sep.join([qn, literal.name]) def _handle_binary(self): """Return binary value.""" random_string = self._get_string(0) if sys.version_info >= (3, 0): bin_string = base64.b64encode(str.encode(random_string)).decode() else: bin_string = base64.b64encode(random_string) return self._render_string(bin_string) def _handle_boolean(self, prop): """Chose and return boolean value.""" boolean = str(bool(getrandbits(1))) # hard code to enable if prop.name == 'enabled': boolean = 'True' if self.lang == 'cpp': boolean = boolean.lower() return boolean def _handle_decimal64(self, low=None, high=None): """Generate and return decimal64 value based on YANG constraints.""" low = self.type_spec.min if low is None else low high = self.type_spec.max if high is None else high decimal64 = randint(low.value, high.value) minus = '-' if decimal64 < 0 else '' decimal64 = '{:=19d}'.format(decimal64) fractions = self.type_spec.fraction_digits decimal64 = '.'.join([decimal64[:-fractions], decimal64[-fractions:]]) decimal64 = decimal64.strip('- 0') if decimal64.endswith('.'): decimal64 += '0' decimal64 = '"{}{}"'.format(minus, decimal64) if self.lang == 'cpp': decimal64 = 'std::string{{{}}}'.format(decimal64) return 'Decimal64({})'.format(decimal64) def _handle_empty(self): """Return empty value.""" return 'Empty()' def _handle_length(self): """YANG length statement restrict string or derived string type, return trimmed string.""" low, high = choice(self._get_length_limits(self.type_spec)) self.type_spec = self.type_spec.base self.type_stmt = get_typedef_stmt(self.type_stmt) return self._handle_string(low=low, high=high) def _handle_int(self, low=None, high=None): """Return integer value based on low and high limit.""" low = 0 if low is None else low high = low if high is None else high return self._handle_int_range(low, high) def _handle_int_range(self, low, high): """Return integer value if the YANG type statement has a `range` substatement. """ int_value = randint(low, high) range_stmt = self.type_stmt.search_one('range') if range_stmt is not None: if hasattr(range_stmt, 'i_type_spec'): self.type_stmt = range_stmt self.type_spec = range_stmt.i_type_spec int_value = self._handle_range() else: low, high = choice(range_stmt.arg.split('|')).split('..') low, high = self._render_range(low, high) int_value = randint(low, high) return int_value def _handle_pattern(self, prop): """Return string value based on YANG pattern statement. YANG regular expression syntax (XSD) is different from Python, need to use come hard code value. """ patterns = self._collect_patterns() pattern = None for p in patterns: # ignore ipv4/ipv6 zone id pattern if '(%[\\p{N}\\p{L}]+)?' in p.arg: pattern = p.arg.replace('(%[\\p{N}\\p{L}]+)?', '') break if pattern is None: pattern = choice(patterns).arg pattern_value = self._get_string(pattern=pattern) if 'ipv4' in self.type_stmt.arg: pattern_value = '10.0.0.1' if 'ipv6' in self.type_stmt.arg: pattern_value = '2001:db8::ff:2' if 'domain-name' in self.type_stmt.arg: pattern_value = 'domain.name' if 'phys-address' in self.type_stmt.arg: pattern_value = '08:56:27:6f:2b:9c' if 'password' in prop.name: pattern_value = '$0$password' if 'masklength_range' in prop.name: pattern_value = '21..24' if 'access_operations' in prop.name: pattern_value = '*' if prop.name in ('ip_prefix', 'address_prefix', 'fec_address'): pattern_value = '10.0.0.1/32' pattern_value = pattern_value.strip(':').lower() return self._render_string(pattern_value) def _handle_range(self): """Return integer value or decimal64 value based on range statement. """ low, high = choice(self._get_range_limits(self.type_spec)) self.type_spec = self.type_spec.base self.type_stmt = get_typedef_stmt(self.type_stmt) if isinstance(self.type_spec, ptypes.IntTypeSpec): return self._handle_int(low=low, high=high) elif isinstance(self.type_spec, ptypes.Decimal64TypeSpec): return self._handle_decimal64(low=low, high=high) def _handle_string(self, default=None, low=None, high=None, pattern=None): """Return string value.""" string_value = self._get_string(low, high) string_value = default if default is not None else string_value return self._render_string(string_value) def _render_string(self, value): """Remove null and control characters from value and trim value by language. """ value = ''.join(c for c in value if ord(c) >= 32) if self.lang == 'py': return '"""%s"""' % value elif self.lang == 'cpp': return 'R"(%s)"' % value def _set_prop_type(self, prop): """Set self.type_spec and self.type_stmt: - Trace path statement and set destination statement's pyang statement as self.type_stmt, pyang TypeSpec as self.type_spec. - If prop represents union property, chose one. """ type_spec = prop.property_type type_stmt = prop.stmt.search_one('type') if isinstance(type_spec, ptypes.PathTypeSpec): type_stmt = self._get_path_target_type_stmt(type_stmt) type_spec = type_stmt.i_type_spec if isinstance(type_spec, ptypes.UnionTypeSpec): type_spec, type_stmt = self._get_union_type_spec(type_spec) self.type_spec = type_spec self.type_stmt = type_stmt def _get_path_target_type_stmt(self, type_stmt): """Return target pyang statement.""" type_spec = type_stmt.i_type_spec while all([ isinstance(type_spec, ptypes.PathTypeSpec), hasattr(type_spec, 'i_target_node') ]): type_stmt = type_spec.i_target_node.search_one('type') type_spec = type_stmt.i_type_spec return type_stmt def _get_union_type_spec(self, orig_type_spec): """Return union type_spec and type_stmt.""" type_spec = orig_type_spec while isinstance(type_spec, ptypes.UnionTypeSpec): type_stmt = choice(type_spec.types) type_spec = self.types_extractor.get_property_type(type_stmt) if hasattr(type_spec, 'i_type_spec'): type_spec = type_spec.i_type_spec return type_spec, type_stmt def _collect_patterns(self): """Collect all patterns for derived string type.""" patterns = [] type_stmt = self.type_stmt while all([ hasattr(type_stmt, 'i_typedef') and type_stmt.i_typedef is not None ]): patterns.extend(type_stmt.search('pattern')) type_stmt = type_stmt.i_typedef.search_one('type') patterns.extend(type_stmt.search('pattern')) return patterns def _collect_identities(self, identity, identities): """Collect identities and derived identities.""" identity_id = id(identity) if identity_id in self.identity_subclasses: derived_identities = set(self.identity_subclasses[identity_id]) identities |= derived_identities for identity in derived_identities: self._collect_identities(identity, identities) def _get_string(self, low=None, high=None, pattern=None): """Return string from `pattern` or a universal pattern [0-9a-zA-Z]. """ low, high = self._render_range(low, high) if pattern is None or is_match_all(pattern): pattern = r'[0-9a-zA-Z]' return rstr.xeger(pattern).rstrip("\\\"") def _get_length_limits(self, length_type): """Get length limits.""" lengths = [] for low, high in length_type.lengths: low, high = self._render_range(low, high) lengths.append((low, high)) return lengths def _get_range_limits(self, range_type): """Get range limits.""" ranges = [] for low, high in range_type.ranges: low = self._get_range_min(range_type) if low == 'min' else low high = self._get_range_max(range_type) if high == 'max' else high ranges.append((low, high)) return ranges def _get_range_min(self, range_type): """Get range min value.""" range_min = range_type.base.min if isinstance(range_type, ptypes.Decimal64TypeSpec): range_min = range_min.s return range_min def _get_range_max(self, range_type): """Get range max value.""" range_max = range_type.base.max if isinstance(range_type, ptypes.Decimal64TypeSpec): range_max = range_max.s return range_max def _render_range(self, low, high): """Change range value to integer value.""" if low in (None, 'min'): low = _LOW low = int(low) if high in (None, 'max'): high = low high = int(high) return low, high @property def nmsp_sep(self): sep = '.' if self.lang == 'cpp': sep = '::' return sep
def get_meta_info_data(prop, property_type, type_stmt, language, identity_subclasses=None): """ Gets an instance of MetaInfoData that has the useful information about the property. Args: prop: The property property_type : The type under consideration type_stmt : The type stmt currently under consideration """ clazz = prop.owner meta_info_data = MetaInfoData(prop) types_extractor = TypesExtractor() target_type_stmt = type_stmt mandatory = prop.stmt.search_one('mandatory') if mandatory is not None and mandatory.arg == 'true': meta_info_data.mandatory = True presence = prop.stmt.search_one('presence') if presence is not None: meta_info_data.is_presence = True units = prop.stmt.search_one('units') if units is not None: meta_info_data.units = units.arg status = prop.stmt.search_one('status') if status is not None: meta_info_data.status = status.arg default_value = prop.stmt.search_one('default') if default_value is not None: meta_info_data.default_value = default_value.arg if isinstance(property_type, Class): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() if identity_subclasses is None: meta_info_data.doc_link = get_class_crossref_tag( property_type.name, property_type, language) else: meta_info_data.doc_link = _get_identity_docstring( identity_subclasses, property_type, language) meta_info_data.doc_link_description = 'one of the below types:' if prop.stmt.keyword == 'leaf-list': meta_info_data.mtype = 'REFERENCE_LEAFLIST' target = '' if isinstance(meta_info_data.doc_link, list): doc_link = map(lambda l: '\n\n\t\t%s' % l, meta_info_data.doc_link) target = ''.join(doc_link) meta_info_data.doc_link = target meta_info_data.doc_link = '\n\t\t' + _get_list_doc_link_tag( meta_info_data, 'doc_link', language, meta_info_data.mtype) elif prop.stmt.keyword == 'list': meta_info_data.mtype = 'REFERENCE_LIST' meta_info_data.doc_link_description = _get_list_doc_link_tag( meta_info_data, 'doc_link_description', language, meta_info_data.mtype) elif property_type.is_identity(): meta_info_data.mtype = 'REFERENCE_IDENTITY_CLASS' else: meta_info_data.mtype = 'REFERENCE_CLASS' # if the class is local use just the local name if property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() elif isinstance(property_type, Enum): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = get_class_crossref_tag( property_type.name, property_type, language) meta_info_data.mtype = 'REFERENCE_ENUM_CLASS' if prop.is_many: meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = _get_list_doc_link_tag( meta_info_data, 'doc_link', language, meta_info_data.mtype) if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() elif isinstance(property_type, Bits): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = get_bits_doc_link(property_type, language) meta_info_data.mtype = 'REFERENCE_BITS' if prop.is_many: meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = _get_list_doc_link_tag( meta_info_data, 'doc_link', language, meta_info_data.mtype) if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() else: if prop.stmt.keyword == 'leaf-list': meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = _get_list_tag(language, meta_info_data.mtype) elif prop.stmt.keyword == 'anyxml': meta_info_data.mtype = 'ANYXML_CLASS' meta_info_data.doc_link = 'anyxml' meta_info_data.ptype = 'object' return meta_info_data else: meta_info_data.mtype = 'ATTRIBUTE' meta_info_data.doc_link = '' type_spec = type_stmt.i_type_spec if isinstance(type_spec, PathTypeSpec): if prop.stmt.i_leafref_ptr is not None: reference_class = prop.stmt.i_leafref_ptr[0].parent.i_class reference_prop = prop.stmt.i_leafref_ptr[0].i_property tag = get_class_crossref_tag(reference_prop.name, reference_class, language) meta_info_data.target_of_leafref = tag while isinstance(type_spec, PathTypeSpec): if not hasattr(type_spec, 'i_target_node'): return None target_type_stmt = type_spec.i_target_node.search_one('type') type_spec = target_type_stmt.i_type_spec if isinstance(type_spec, BinaryTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) elif isinstance(type_spec, BitsTypeSpec): # This can happen in a Union raise EmitError('Illegal Code path') elif isinstance(type_spec, BooleanTypeSpec): meta_info_data.ptype = 'bool' meta_info_data.doc_link += get_primitive_type_tag('bool', language) elif isinstance(type_spec, Decimal64TypeSpec): meta_info_data.ptype = 'Decimal64' meta_info_data.prange.append( ('%s' % str(type_spec.min.s), '%s' % str(type_spec.max.s))) meta_info_data.doc_link += get_primitive_type_tag( 'Decimal64', language) elif isinstance(type_spec, EmptyTypeSpec): meta_info_data.ptype = 'Empty' meta_info_data.doc_link += get_primitive_type_tag( 'Empty', language) elif isinstance(prop.property_type, Enum): raise EmitError('Illegal Code path') elif isinstance(type_spec, IdentityrefTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, IntTypeSpec): meta_info_data.ptype = 'int' meta_info_data.doc_link += meta_info_data.ptype lower = str(type_spec.min) upper = str(type_spec.max) meta_info_data.prange.append((lower, upper)) elif isinstance(type_spec, LengthTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) meta_info_data.prange = get_length_limits(type_spec) elif isinstance(type_spec, PathTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, PatternTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) while hasattr( target_type_stmt, 'i_typedef') and target_type_stmt.i_typedef is not None: target_type_stmt = target_type_stmt.i_typedef.search_one( 'type') pattern = target_type_stmt.search_one('pattern') if pattern is not None: meta_info_data.pattern.append(pattern.arg.encode('ascii')) elif isinstance(type_spec, RangeTypeSpec): meta_info_data.ptype = get_range_base_type_name(type_spec) meta_info_data.prange = get_range_limits(type_spec) meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, StringTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) elif isinstance(type_spec, UnionTypeSpec): # validate against all the data types meta_info_data.mtype = 'REFERENCE_UNION' meta_info_data.ptype = 'str' meta_info_data.property_type = type_spec for contained_type_stmt in type_spec.types: contained_property_type = types_extractor.get_property_type( contained_type_stmt) child_meta_info_data = get_meta_info_data( prop, contained_property_type, contained_type_stmt, language, identity_subclasses=identity_subclasses) meta_info_data.children.append(child_meta_info_data) elif isinstance(type_spec, TypeSpec) and type_spec.name == 'instance-identifier': # Treat as string meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) else: raise EmitError('Illegal path') return meta_info_data
def get_meta_info_data(prop, property_type, type_stmt, language, identity_subclasses=None): """ Gets an instance of MetaInfoData that has the useful information about the property. Args: prop: The property property_type : The type under consideration type_stmt : The type stmt currently under consideration """ clazz = prop.owner meta_info_data = MetaInfoData(prop) if type_stmt is not None: meta_info_data.ytype = type_stmt.arg types_extractor = TypesExtractor() target_type_stmt = type_stmt mandatory = prop.stmt.search_one('mandatory') if mandatory is not None and mandatory.arg == 'true': meta_info_data.mandatory = True presence = prop.stmt.search_one('presence') if presence is not None: meta_info_data.is_presence = True units = prop.stmt.search_one('units') if units is not None: meta_info_data.units = units.arg status = prop.stmt.search_one('status') if status is not None: meta_info_data.status = status.arg default_value = prop.stmt.search_one('default') if default_value is not None: meta_info_data.default_value = default_value.arg # if the class is local use just the local name if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name elif hasattr(property_type, 'qn'): meta_info_data.ptype = property_type.qn() if isinstance(property_type, Class): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() if identity_subclasses is None: meta_info_data.doc_link = get_class_crossref_tag( property_type.name, property_type, language) else: meta_info_data.doc_link = _get_identity_docstring( identity_subclasses, property_type, language) meta_info_data.doc_link_description = 'one of the below values:' if prop.stmt.keyword == 'leaf-list': meta_info_data.mtype = 'REFERENCE_LEAFLIST' if isinstance(meta_info_data.doc_link, list): doc_link = map(lambda l: '\n\n\t\t%s' % l, meta_info_data.doc_link) target = ''.join(doc_link) meta_info_data.doc_link = target meta_info_data.doc_link = _get_list_doc_link_tag( meta_info_data, 'doc_link', language, meta_info_data.mtype) elif prop.stmt.keyword == 'list': meta_info_data.mtype = 'REFERENCE_LIST' meta_info_data.doc_link_description = _get_list_doc_link_tag( meta_info_data, 'doc_link_description', language, meta_info_data.mtype) elif property_type.is_identity(): meta_info_data.mtype = 'REFERENCE_IDENTITY_CLASS' else: meta_info_data.mtype = 'REFERENCE_CLASS' elif isinstance(property_type, Enum): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = get_class_crossref_tag(property_type.name, property_type, language) _set_mtype_docstring(meta_info_data, prop, 'REFERENCE_ENUM_CLASS', language) elif isinstance(property_type, Bits): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = get_bits_doc_link(property_type, language) _set_mtype_docstring(meta_info_data, prop, 'REFERENCE_BITS', language) else: if prop.stmt.keyword == 'leaf-list': meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = _get_list_tag(language, meta_info_data.mtype) elif prop.stmt.keyword == 'anyxml': meta_info_data.mtype = 'ANYXML_CLASS' meta_info_data.doc_link = 'anyxml' meta_info_data.ptype = 'object' return meta_info_data else: meta_info_data.mtype = 'ATTRIBUTE' meta_info_data.doc_link = '' type_spec = type_stmt.i_type_spec if isinstance(type_spec, PathTypeSpec): if prop.stmt.i_leafref_ptr is not None: reference_class = prop.stmt.i_leafref_ptr[0].parent.i_class reference_prop = prop.stmt.i_leafref_ptr[0].i_property tag = get_class_crossref_tag(reference_prop.name, reference_class, language) meta_info_data.target_of_leafref = tag while isinstance(type_spec, PathTypeSpec): if not hasattr(type_spec, 'i_target_node'): return None target_type_stmt = type_spec.i_target_node.search_one('type') type_spec = target_type_stmt.i_type_spec if isinstance(type_spec, BinaryTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) elif isinstance(type_spec, BitsTypeSpec): # This can happen in a Union raise EmitError('Illegal Code path') elif isinstance(type_spec, BooleanTypeSpec): meta_info_data.ptype = 'bool' meta_info_data.doc_link += get_primitive_type_tag('bool', language) elif isinstance(type_spec, Decimal64TypeSpec): meta_info_data.ptype = 'Decimal64' meta_info_data.prange.append( ('%s' % str(type_spec.min.s), '%s' % str(type_spec.max.s))) meta_info_data.doc_link += get_primitive_type_tag('Decimal64', language) elif isinstance(type_spec, EmptyTypeSpec): meta_info_data.ptype = 'Empty' meta_info_data.doc_link += get_primitive_type_tag('Empty', language) elif isinstance(prop.property_type, Enum): raise EmitError('Illegal Code path') elif isinstance(type_spec, IdentityrefTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, IntTypeSpec): meta_info_data.ptype = 'int' meta_info_data.doc_link += meta_info_data.ptype lower = str(type_spec.min) upper = str(type_spec.max) meta_info_data.prange.append((lower, upper)) elif isinstance(type_spec, LengthTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) meta_info_data.prange = get_length_limits(type_spec) elif isinstance(type_spec, PathTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, PatternTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) add_pattern_docstring(meta_info_data, target_type_stmt) elif isinstance(type_spec, RangeTypeSpec): meta_info_data.ptype = get_range_base_type_name(type_spec) meta_info_data.prange = get_range_limits(type_spec) meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, StringTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) add_pattern_docstring(meta_info_data, target_type_stmt) elif isinstance(type_spec, UnionTypeSpec): # validate against all the data types meta_info_data.mtype = 'REFERENCE_UNION' meta_info_data.ptype = 'str' meta_info_data.property_type = type_spec for contained_type_stmt in type_spec.types: contained_property_type = types_extractor.get_property_type(contained_type_stmt) child_meta_info_data = get_meta_info_data( prop, contained_property_type, contained_type_stmt, language, identity_subclasses=identity_subclasses) meta_info_data.children.append(child_meta_info_data) elif isinstance(type_spec, TypeSpec) and type_spec.name == 'instance-identifier': # Treat as string meta_info_data.ptype = 'str' meta_info_data.doc_link += get_primitive_type_tag('str', language) else: raise EmitError('Illegal path') if default_value is not None: meta_info_data.default_value_object = get_default_value_object(meta_info_data.ptype, property_type, meta_info_data.clazz_name, default_value.arg, identity_subclasses) return meta_info_data
def get_meta_info_data(prop, property_type, type_stmt): """ Gets an instance of MetaInfoData that has the useful information about the property. Args: prop: The property property_type : The type under consideration type_stmt : The type stmt currently under consideration """ clazz = prop.owner meta_info_data = MetaInfoData(prop) types_extractor = TypesExtractor() target_type_stmt = type_stmt if isinstance(property_type, Class): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = ':py:class:`%s <%s.%s>`' % ( property_type.name, property_type.get_py_mod_name(), property_type.qn()) if prop.is_many: meta_info_data.mtype = 'REFERENCE_LIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link elif property_type.is_identity(): meta_info_data.mtype = 'REFERENCE_IDENTITY_CLASS' else: meta_info_data.mtype = 'REFERENCE_CLASS' # if the class is local use just the local name if property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() elif isinstance(property_type, Enum): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = ':py:class:`%s <%s.%s>`' % ( property_type.name, property_type.get_py_mod_name(), property_type.qn()) meta_info_data.mtype = 'REFERENCE_ENUM_CLASS' if prop.is_many: meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() elif isinstance(property_type, Bits): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = ':py:class:`%s <%s.%s>`' % ( property_type.name, property_type.get_py_mod_name(), property_type.qn()) meta_info_data.mtype = 'REFERENCE_BITS' if prop.is_many: meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() else: if prop.stmt.keyword == 'leaf-list': meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of ' elif prop.stmt.keyword == 'anyxml': meta_info_data.mtype = 'ANYXML_CLASS' meta_info_data.doc_link = 'anyxml' meta_info_data.ptype = 'object' return meta_info_data else: meta_info_data.mtype = 'ATTRIBUTE' meta_info_data.doc_link = '' type_spec = type_stmt.i_type_spec while isinstance(type_spec, PathTypeSpec): if not hasattr(type_spec, 'i_target_node'): return None target_type_stmt = type_spec.i_target_node.search_one('type') type_spec = target_type_stmt.i_type_spec if isinstance(type_spec, BinaryTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, BitsTypeSpec): # This can happen in a Union raise EmitError('Illegal Code path') elif isinstance(type_spec, BooleanTypeSpec): meta_info_data.ptype = 'bool' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, Decimal64TypeSpec): meta_info_data.ptype = 'Decimal64' meta_info_data.prange.append( ('%s' % type_spec.min.s, '%s' % type_spec.max.s)) # ' :ref:`Decimal64 <ydk_models_types_Decimal64>`' meta_info_data.doc_link += ':py:class:`Decimal64 <ydk.types.Decimal64>`' elif isinstance(type_spec, EmptyTypeSpec): meta_info_data.ptype = 'Empty' # ' :ref:`Empty <ydk_models_types_Empty>`' meta_info_data.doc_link += ':py:class:`Empty <ydk.types.Empty>`' elif isinstance(prop.property_type, Enum): raise EmitError('Illegal Code path') elif isinstance(type_spec, IdentityrefTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, IntTypeSpec): meta_info_data.ptype = 'int' meta_info_data.doc_link += meta_info_data.ptype meta_info_data.prange.append((type_spec.min, type_spec.max)) elif isinstance(type_spec, LengthTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype meta_info_data.prange = get_length_limits(type_spec) elif isinstance(type_spec, PathTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, PatternTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype while hasattr(target_type_stmt, 'i_typedef') and target_type_stmt.i_typedef is not None: target_type_stmt = target_type_stmt.i_typedef.search_one( 'type') pattern = target_type_stmt.search_one('pattern') if pattern is not None: meta_info_data.pattern.append(pattern.arg.encode('ascii')) elif isinstance(type_spec, RangeTypeSpec): meta_info_data.ptype = get_range_base_type_name(type_spec) meta_info_data.prange = get_range_limits(type_spec) meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, StringTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, UnionTypeSpec): # validate against all the data types meta_info_data.mtype = 'REFERENCE_UNION' meta_info_data.ptype = 'str' meta_info_data.property_type = type_spec if len(type_spec.types) > 0: meta_info_data.doc_link += 'one of { ' for contained_type_stmt in type_spec.types: enum_type_stmt = types_extractor.get_enum_type_stmt(contained_type_stmt) bits_type_stmt = types_extractor.get_bits_type_stmt(contained_type_stmt) union_type_stmt = types_extractor.get_union_type_stmt(contained_type_stmt) contained_property_type = contained_type_stmt.i_type_spec if isinstance(contained_property_type, IdentityrefTypeSpec): contained_property_type = contained_property_type.base.i_identity.i_class elif enum_type_stmt is not None: # this is an enumeration if not hasattr(enum_type_stmt, 'i_enum'): raise EmitError('Failure to get i_enum') contained_property_type = enum_type_stmt.i_enum elif bits_type_stmt is not None: # bits contained_property_type = bits_type_stmt.i_bits elif union_type_stmt is not None: contained_property_type = union_type_stmt child_meta_info_data = get_meta_info_data( prop, contained_property_type, contained_type_stmt) meta_info_data.children.append(child_meta_info_data) if meta_info_data.doc_link[-1:] != ' ': meta_info_data.doc_link += ' | ' meta_info_data.doc_link += child_meta_info_data.doc_link meta_info_data.doc_link += ' }' elif isinstance(type_spec, TypeSpec) and type_spec.name == 'instance-identifier': # Treat as string meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype else: raise EmitError('Illegal path') return meta_info_data
def get_meta_info_data(prop, property_type, type_stmt, identity_subclasses=None): """ Gets an instance of MetaInfoData that has the useful information about the property. Args: prop: The property property_type : The type under consideration type_stmt : The type stmt currently under consideration """ clazz = prop.owner meta_info_data = MetaInfoData(prop) types_extractor = TypesExtractor() target_type_stmt = type_stmt mandatory = prop.stmt.search_one('mandatory') if mandatory is not None and mandatory.arg == 'true': meta_info_data.mandatory = True mandatory = prop.stmt.search_one('mandatory') if mandatory is not None and mandatory.arg == 'true': meta_info_data.mandatory = True if isinstance(property_type, Class): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() doc_link_template = ':py:class:`%s <%s.%s>`' if identity_subclasses is None: meta_info_data.doc_link = doc_link_template % ( property_type.name, property_type.get_py_mod_name(), property_type.qn() ) else: meta_info_data.doc_link = _get_identity_docstring(identity_subclasses, doc_link_template, property_type) meta_info_data.doc_link_description = 'one of the below types:' if prop.stmt.keyword == 'leaf-list': meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link elif prop.stmt.keyword == 'list': meta_info_data.mtype = 'REFERENCE_LIST' meta_info_data.doc_link_description = 'list of %s' % meta_info_data.doc_link_description elif property_type.is_identity(): meta_info_data.mtype = 'REFERENCE_IDENTITY_CLASS' else: meta_info_data.mtype = 'REFERENCE_CLASS' # if the class is local use just the local name if property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() elif isinstance(property_type, Enum): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = ':py:class:`%s <%s.%s>`' % ( property_type.name, property_type.get_py_mod_name(), property_type.qn()) meta_info_data.mtype = 'REFERENCE_ENUM_CLASS' if prop.is_many: meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() elif isinstance(property_type, Bits): meta_info_data.pmodule_name = "'%s'" % property_type.get_py_mod_name() meta_info_data.clazz_name = "'%s'" % property_type.qn() meta_info_data.doc_link = ':py:class:`%s <%s.%s>`' % ( property_type.name, property_type.get_py_mod_name(), property_type.qn()) meta_info_data.mtype = 'REFERENCE_BITS' if prop.is_many: meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of %s' % meta_info_data.doc_link if prop.property_type in clazz.owned_elements: meta_info_data.ptype = property_type.name else: meta_info_data.ptype = property_type.qn() else: if prop.stmt.keyword == 'leaf-list': meta_info_data.mtype = 'REFERENCE_LEAFLIST' meta_info_data.doc_link = 'list of ' elif prop.stmt.keyword == 'anyxml': meta_info_data.mtype = 'ANYXML_CLASS' meta_info_data.doc_link = 'anyxml' meta_info_data.ptype = 'object' return meta_info_data else: meta_info_data.mtype = 'ATTRIBUTE' meta_info_data.doc_link = '' type_spec = type_stmt.i_type_spec if isinstance(type_spec, PathTypeSpec): if prop.stmt.i_leafref_ptr is not None: reference_class = prop.stmt.i_leafref_ptr[0].parent.i_class reference_prop = prop.stmt.i_leafref_ptr[0].i_property meta_info_data.target_of_leafref = ':py:class:`%s <%s.%s>`' % (reference_prop.name, reference_class.get_py_mod_name(), reference_class.qn()) while isinstance(type_spec, PathTypeSpec): if not hasattr(type_spec, 'i_target_node'): return None target_type_stmt = type_spec.i_target_node.search_one('type') type_spec = target_type_stmt.i_type_spec if isinstance(type_spec, BinaryTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, BitsTypeSpec): # This can happen in a Union raise EmitError('Illegal Code path') elif isinstance(type_spec, BooleanTypeSpec): meta_info_data.ptype = 'bool' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, Decimal64TypeSpec): meta_info_data.ptype = 'Decimal64' meta_info_data.prange.append( ('%s' % type_spec.min.s, '%s' % type_spec.max.s)) # ' :ref:`Decimal64 <ydk_models_types_Decimal64>`' meta_info_data.doc_link += ':py:class:`Decimal64 <ydk.types.Decimal64>`' elif isinstance(type_spec, EmptyTypeSpec): meta_info_data.ptype = 'Empty' # ' :ref:`Empty <ydk_models_types_Empty>`' meta_info_data.doc_link += ':py:class:`Empty <ydk.types.Empty>`' elif isinstance(prop.property_type, Enum): raise EmitError('Illegal Code path') elif isinstance(type_spec, IdentityrefTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, IntTypeSpec): meta_info_data.ptype = 'int' if not isinstance(type_spec.min, int) or not isinstance(type_spec.max, int): meta_info_data.ptype = 'long' meta_info_data.doc_link += meta_info_data.ptype meta_info_data.prange.append((type_spec.min, type_spec.max)) elif isinstance(type_spec, LengthTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype meta_info_data.prange = get_length_limits(type_spec) elif isinstance(type_spec, PathTypeSpec): raise EmitError('Illegal Code path') elif isinstance(type_spec, PatternTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype while hasattr(target_type_stmt, 'i_typedef') and target_type_stmt.i_typedef is not None: target_type_stmt = target_type_stmt.i_typedef.search_one( 'type') pattern = target_type_stmt.search_one('pattern') if pattern is not None: meta_info_data.pattern.append(pattern.arg.encode('ascii')) elif isinstance(type_spec, RangeTypeSpec): meta_info_data.ptype = get_range_base_type_name(type_spec) meta_info_data.prange = get_range_limits(type_spec) meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, StringTypeSpec): meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype elif isinstance(type_spec, UnionTypeSpec): # validate against all the data types meta_info_data.mtype = 'REFERENCE_UNION' meta_info_data.ptype = 'str' meta_info_data.property_type = type_spec if len(type_spec.types) > 0: # meta_info_data.doc_link += 'one of { ' for contained_type_stmt in type_spec.types: contained_property_type = types_extractor.get_property_type(contained_type_stmt) child_meta_info_data = get_meta_info_data( prop, contained_property_type, contained_type_stmt, identity_subclasses) meta_info_data.children.append(child_meta_info_data) # if meta_info_data.doc_link[-1:] != ' ': # meta_info_data.doc_link += ' | ' # meta_info_data.doc_link += child_meta_info_data.doc_link # meta_info_data.doc_link += ' }' elif isinstance(type_spec, TypeSpec) and type_spec.name == 'instance-identifier': # Treat as string meta_info_data.ptype = 'str' meta_info_data.doc_link += meta_info_data.ptype else: raise EmitError('Illegal path') return meta_info_data