Package pyplusplus :: Package module_creator :: Module dependencies_manager

Source Code for Module pyplusplus.module_creator.dependencies_manager

  1  # Copyright 2004-2008 Roman Yakovenko. 
  2  # Distributed under the Boost Software License, Version 1.0. (See 
  3  # accompanying file LICENSE_1_0.txt or copy at 
  4  # http://www.boost.org/LICENSE_1_0.txt) 
  5   
  6  """defines class, which informs user about used, but unexposed declarations""" 
  7   
  8  import os 
  9  from pyplusplus import utils 
 10  from pyplusplus import messages 
 11  from pygccxml import declarations 
 12  from pyplusplus import decl_wrappers 
 13   
14 -class duplicated_names_reporter_t(object):
15 - def __init__( self, decls, value_getter, msg ):
16 self.decls = decls 17 self.get_value = value_getter 18 self.msg = msg
19
20 - def __select( self ):
21 duplicated = {} 22 for decl in self.decls: 23 value = self.get_value( decl ) 24 if not duplicated.has_key( value ): 25 duplicated[ value ] = set() 26 duplicated[ value ].add( decl ) 27 result = duplicated.copy() 28 for value, buggy_decls in duplicated.items(): 29 if 1 == len( buggy_decls ): 30 del result[ value ] 31 return result
32
33 - def __report_single( self, control_decl, duplicated, logger ):
34 value = self.get_value( control_decl ) 35 if value not in duplicated: 36 return 37 buggy_decls = duplicated[value].copy() 38 buggy_decls.remove( control_decl ) 39 warning = self.msg % ( value, os.linesep.join( map( str, buggy_decls ) ) ) 40 logger.warn( "%s;%s" % ( str( control_decl ), warning ) )
41
42 - def report( self, logger ):
43 duplicated = self.__select() 44 for decl in self.decls: 45 self.__report_single( decl, duplicated, logger )
46 47 duplicated_aliases_reporter \ 48 = lambda decls: duplicated_names_reporter_t( decls, lambda d: d.alias, messages.W1047 ) 49 50 duplicated_wrapper_aliases_reporter \ 51 = lambda decls: duplicated_names_reporter_t( decls, lambda d: d.wrapper_alias, messages.W1065 ) 52 53
54 -class manager_t( object ):
55 - def __init__( self, logger ):
56 object.__init__( self ) 57 self.__exported_decls = [] 58 self.__logger = logger
59
60 - def add_exported( self, decl ):
61 self.__exported_decls.append( decl )
62
63 - def __is_std_decl( self, decl ):
64 #Every class under std should be exported by Boost.Python and\\or Py++ 65 #Also this is not the case right now, I prefer to hide the warnings 66 dpath = declarations.declaration_path( decl ) 67 if len( dpath ) < 3: 68 return False 69 if dpath[1] != 'std': 70 return False 71 if decl.name.startswith( 'pair<' ): 72 #special case 73 return False 74 return True
75
76 - def __build_dependencies( self, decl ):
77 if self.__is_std_decl( decl ): 78 #TODO add element_type to the list of dependencies 79 return [] #std declarations should be exported by Py++! 80 if decl.already_exposed: 81 return [] 82 dependencies = decl.i_depend_on_them(recursive=False) 83 84 if isinstance( decl, declarations.class_t ): 85 dependencies = filter( lambda d: d.access_type != declarations.ACCESS_TYPES.PRIVATE 86 , dependencies ) 87 88 return dependencies
89
90 - def __has_unexposed_dependency( self, exported_ids, depend_on_decl, dependency ):
91 sptr_traits = declarations.smart_pointer_traits 92 93 if None is depend_on_decl: 94 return 95 96 if self.__is_std_decl( depend_on_decl ): 97 return 98 99 if sptr_traits.is_smart_pointer( depend_on_decl ): 100 try: 101 value_type = sptr_traits.value_type( depend_on_decl ) 102 return self.__has_unexposed_dependency( exported_ids, value_type, dependency ) 103 except RuntimeError: 104 pass 105 106 if isinstance( depend_on_decl, decl_wrappers.decl_wrapper_t ): 107 if depend_on_decl.already_exposed: 108 return 109 if isinstance( depend_on_decl, declarations.class_types ): 110 if depend_on_decl.opaque: 111 return 112 if dependency.hint == "base class": 113 return #base class for some class don't have to be exported 114 if isinstance( depend_on_decl, declarations.variable_t ): 115 if not decl.expose_value: 116 return 117 118 if isinstance( dependency.decl, declarations.variable_t ): 119 #the only dependency of the variable is its type 120 if not dependency.decl.expose_value: 121 return 122 123 if dependency.hint == "return type": 124 #in this case we don't check, the return type but the function 125 if isinstance( dependency.decl, declarations.calldef_t ): 126 if dependency.decl.return_type and dependency.decl.call_policies \ 127 and decl_wrappers.is_return_opaque_pointer_policy( dependency.decl.call_policies ): 128 return 129 130 return id( depend_on_decl ) not in exported_ids
131
133 used_not_exported = [] 134 exported_ids = set( map( lambda d: id( d ), self.__exported_decls ) ) 135 for decl in self.__exported_decls: 136 for dependency in self.__build_dependencies( decl ): 137 depend_on_decl = dependency.find_out_depend_on_declaration() 138 if self.__has_unexposed_dependency( exported_ids, depend_on_decl, dependency ): 139 if messages.filter_disabled_msgs([messages.W1040], depend_on_decl.disabled_messages ): 140 #need to report dependency errors 141 used_not_exported.append(dependency) 142 return used_not_exported
143
144 - def __group_by_unexposed( self, dependencies ):
145 groups = {} 146 for dependency in dependencies: 147 depend_on_decl = dependency.find_out_depend_on_declaration() 148 if not groups.has_key( id( depend_on_decl ) ): 149 groups[ id( depend_on_decl ) ] = [] 150 groups[ id( depend_on_decl ) ].append( dependency ) 151 return groups
152
153 - def __create_dependencies_msg( self, dependencies ):
154 depend_on_decl = dependencies[0].find_out_depend_on_declaration() 155 decls = [] 156 for dependency in dependencies: 157 decls.append( os.linesep + ' ' + str( dependency.declaration ) ) 158 return "%s;%s" % ( depend_on_decl, messages.W1040 % ''.join( decls ) )
159
160 - def __report_duplicated_aliases( self ):
161 decls = filter( lambda decl: isinstance( decl, declarations.class_types ) \ 162 and isinstance( decl.parent, declarations.namespace_t ) 163 , self.__exported_decls ) 164 165 dar = duplicated_aliases_reporter( decls ) 166 dar.report( self.__logger ) 167 168 classes = filter( lambda c: isinstance( c, declarations.class_t ), decls ) 169 query = lambda decl: isinstance( decl, declarations.class_types ) \ 170 and decl.ignore == False \ 171 and decl._already_exposed == False 172 173 for cls in classes: 174 internal_decls = cls.decls( query, recursive=False, allow_empty=True) 175 dar = duplicated_aliases_reporter( internal_decls ) 176 dar.report( self.__logger )
177
179 decls = filter( lambda decl: isinstance( decl, declarations.class_t ) \ 180 and isinstance( decl.parent, declarations.namespace_t ) 181 , self.__exported_decls ) 182 183 dwar = duplicated_wrapper_aliases_reporter( decls ) 184 dwar.report( self.__logger ) 185 186 query = lambda decl: decl.ignore == False and decl._already_exposed == False 187 188 for cls in decls: 189 internal_decls = cls.classes( query, recursive=False, allow_empty=True) 190 dwar = duplicated_wrapper_aliases_reporter( internal_decls ) 191 dwar.report( self.__logger )
192
193 - def inform_user( self ):
194 used_not_exported_decls = self.__find_out_used_but_not_exported() 195 groups = self.__group_by_unexposed( used_not_exported_decls ) 196 for group in groups.itervalues(): 197 self.__logger.warn( self.__create_dependencies_msg( group ) ) 198 self.__report_duplicated_aliases() 199 self.__report_duplicated_wrapper_aliases()
200