Package pyplusplus :: Package decl_wrappers :: Module class_wrapper

# Source Code for Module pyplusplus.decl_wrappers.class_wrapper

      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 that configure class definition and class declaration exposing"""
      7
      8  import os
      9  import user_text
     10  import properties
     11  import decl_wrapper
     12  import scopedef_wrapper
     13  from pyplusplus import messages
     14  from pygccxml import declarations
     15  import indexing_suite1 as isuite1
     16  import indexing_suite2 as isuite2
     17
     18  ACCESS_TYPES = declarations.ACCESS_TYPES
     19  VIRTUALITY_TYPES = declarations.VIRTUALITY_TYPES
     20
     21 -class impl_details:
     22 -    class GUESS_VALUES: #guess always expose using scope values
     23          TRUE = 'true'
     24          FALSE = 'false'
     25          ALWAYS_TRUE = 'always true'
     26          all = [ TRUE,  FALSE, ALWAYS_TRUE ]
     27
     28
     29  always_expose_using_scope_documentation = \
     30  """boolean, configures how Py++ should generate code for class.
     31  Py can generate code using IDL like syntax:
     32
     33      class_< ... >( ... )
     34          .def( ... );
     35
     36  Or it can generate code using more complex form:
     37
     38      typedef bp::class_< my_class > my_class_exposer_t;
     39      my_class_exposer_t my_class_exposer = my_class_exposer_t( "my_class" );
     40      boost::python::scope my_class_scope( my_class_exposer );
     41      my_class_exposer.def( ... );
     42
     43  Also, the second way is much longer, it solves few problems:
     44
     45      - you can not expose enums and internal classes defined within the class using first method
     46      - you will get much better compilation errors
     47      - the code looks like regular C++ code after all :-)
     48
     49  By default, this property is set to False. Also, Py++ knows pretty well
     50  when it have to ignore this property and generate right code
     51  """
     52
     53 -class class_common_details_t( object ):
     54      """defines few properties that are common to
     55      L{class declaration<pygccxml.declarations.class_declaration_t>} and
     56      L{definition<pygccxml.declarations.class_t>} classes
     57      """
     58 -    def __init__(self):
     59          object.__init__( self )
     60          self._always_expose_using_scope = None
     61          self._indexing_suite = None
     62          self._equality_comparable = None
     63          self._less_than_comparable = None
     64          self._isuite_version = 1
     65          self._opaque = False
     66
     67 -    def _get_indexing_suite_version( self ):
     68          return self._isuite_version
     69 -    def _set_indexing_suite_version( self, version ):
     70          assert version in ( 1, 2 )
     71          if self._isuite_version != version:
     72              self._isuite_version = version
     73              self._indexing_suite = None
     74      indexing_suite_version = property( _get_indexing_suite_version, _set_indexing_suite_version
     75                                         , doc="indexing suite version")
     76
     77      @property
     78 -    def indexing_suite( self ):
     79          """reference to indexing suite configuration class.
     80
     81          If the class is not STD container, this property will contain None"
     82          """
     83          if self._indexing_suite is None:
     84              if self.container_traits:
     85                  if self._isuite_version == 1:
     86                      self._indexing_suite = isuite1.indexing_suite1_t( self )
     87                  else:
     88                      self._indexing_suite = isuite2.indexing_suite2_t( self )
     89          return self._indexing_suite
     90
     91 -    def guess_always_expose_using_scope_value( self ):
     92          if isinstance( self.indexing_suite, isuite2.indexing_suite2_t ) \
     93             and ( self.indexing_suite.disable_methods or self.indexing_suite.disabled_methods_groups ):
     94              return impl_details.GUESS_VALUES.ALWAYS_TRUE
     95          else:
     96              return impl_details.GUESS_VALUES.FALSE
     97
     98 -    def _get_always_expose_using_scope( self ):
     99          tmp = self.guess_always_expose_using_scope_value()
    100          if tmp == impl_details.GUESS_VALUES.ALWAYS_TRUE:
    101              return True
    102          if None is self._always_expose_using_scope:
    103              if impl_details.GUESS_VALUES.TRUE == tmp:
    104                  self._always_expose_using_scope = True
    105              else:
    106                  self._always_expose_using_scope = False
    107          return self._always_expose_using_scope
    108
    109 -    def _set_always_expose_using_scope( self, value ):
    110          self._always_expose_using_scope = value
    111      always_expose_using_scope = property( _get_always_expose_using_scope, _set_always_expose_using_scope
    112                                            , doc="please see L{class_wrapper.always_expose_using_scope_documentation} variable for documentation."  )
    113
    114 -    def _get_equality_comparable( self ):
    115          if None is self._equality_comparable:
    116              self._equality_comparable = declarations.has_public_equal( self )
    117          return self._equality_comparable
    118
    119 -    def _set_equality_comparable( self, value ):
    120          self._equality_comparable = value
    121
    122      equality_comparable = property( _get_equality_comparable, _set_equality_comparable
    123                                      , doc="indicates existence of public operator=" \
    124                                           +"Default value is calculated, based on information presented in the declarations tree" )
    125
    126 -    def _get_less_than_comparable( self ):
    127          if None is self._less_than_comparable:
    128              self._less_than_comparable = declarations.has_public_less( self )
    129          return self._less_than_comparable
    130
    131 -    def _set_less_than_comparable( self, value ):
    132          self._less_than_comparable = value
    133
    134      less_than_comparable = property( _get_less_than_comparable, _set_less_than_comparable
    135                                       , doc="indicates existence of public operator<. " \
    136                                            +"Default value is calculated, based on information presented in the declarations tree" )
    137
    138 -    def _get_opaque( self ):
    139          return self._opaque
    140
    141 -    def _set_opaque( self, value ):
    142          self._opaque = value
    143          self.ignore = value #don't expose opaque type
    144
    145      opaque = property( _get_opaque, _set_opaque
    146                        , doc="If True, Py++ will treat return types and arguments T* as opaque types." \
    147                              +"Thus it will be able to generate code, that uses " \
    148                              +" BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID macro in a right places." )
    149
    150      @property
    151 -    def class_var_name(self):
    152          return self.alias + '_exposer'
    153
    154  #this will only be exported if indexing suite is not None and only when needed
    155 -class class_declaration_t( class_common_details_t
    156                             , decl_wrapper.decl_wrapper_t
    157                             , declarations.class_declaration_t ):
    158 -    def __init__(self, *arguments, **keywords):
    159          class_common_details_t.__init__( self )
    160          declarations.class_declaration_t.__init__(self, *arguments, **keywords )
    161          decl_wrapper.decl_wrapper_t.__init__( self )
    162
    163 -class class_t( class_common_details_t
    164                 , scopedef_wrapper.scopedef_t
    165                 , declarations.class_t):
    166
    167 -    class EXPOSED_CLASS_TYPE:
    168          DECLARED = 'declared'
    169          WRAPPER = 'wrapper'
    170          ALL = ( DECLARED, WRAPPER )
    171
    172      FAKE_CONSTRUCTOR_TYPES = ( declarations.member_function_t, declarations.free_function_t )
    173      FAKE_CONSTRUCTOR_TYPE_NAMES = 'member and free functions'
    174
    175 -    def __init__(self, *arguments, **keywords):
    176          class_common_details_t.__init__( self )
    177          declarations.class_t.__init__(self, *arguments, **keywords )
    178          scopedef_wrapper.scopedef_t.__init__( self )
    179
    180          self._redefine_operators = False
    181          self._held_type = None
    182          self._noncopyable = None
    183          self._wrapper_alias = None
    184          self._registration_code_head = []
    185          self._registration_code_tail = []
    186          self._declaration_code = []
    187          self._wrapper_code = []
    188          self._destructor_code = []
    189          self._exception_translation_code = None
    190          self._properties = []
    191          self._redefined_funcs = None
    192          self._require_self_reference  = False
    193          self._exposed_class_type = self.EXPOSED_CLASS_TYPE.DECLARED
    194          self._expose_this = None
    195          self._expose_sizeof = None
    196          self._fake_constructors = []
    197          self._no_init = None
    198
    199      @property
    200 -    def fake_constructors(self):
    201          """list of fake constructors"""
    202          return self._fake_constructors
    203
    204 -    def add_fake_constructors( self, f ):
    205          """f - reference to a calldef_t object or list of them
    206
    207          boost::python::make_constructor allows to register a C++ function, as a
    208          class constructor.
    209          """
    210          if isinstance( f, declarations.calldef_t ):
    211              self._fake_constructors.add( f )
    212          else:
    213              self._fake_constructors.extend( f )
    214
    215 -    def _get_redefine_operators( self ):
    216          return self._redefine_operators
    217 -    def _set_redefine_operators( self, new_value ):
    218          self._redefine_operators = new_value
    219      redefine_operators = property( _get_redefine_operators, _set_redefine_operators
    220                                     , doc="tells Py++ to redefine operators from base class in this class, False by default")
    221
    222 -    def _get_exposed_class_type(self):
    223          return self._exposed_class_type
    224 -    def _set_exposed_class_type(self, class_type):
    225          assert class_type in self.EXPOSED_CLASS_TYPE.ALL
    226          self._class_type = class_type
    227      exposed_class_type = property( _get_exposed_class_type, _set_exposed_class_type
    228                            , doc="set this value to CLASS_TYPE.WRAPPER, if you need to transfer ownership of" \
    229                                  "polymorphic class" )
    230
    231 -    def _get_held_type(self):
    232          return self._held_type
    233 -    def _set_held_type(self, held_type):
    234          self._held_type = held_type
    235      held_type = property( _get_held_type, _set_held_type
    236                            , doc="string, this property tells Py++ what HeldType this class has" \
    237                                 +"Default value is calculated, based on information presented in exposed declarations" )
    238
    239 -    def _get_noncopyable(self):
    240          if self._noncopyable is None:
    241              self._noncopyable = declarations.is_noncopyable( self )
    242          return self._noncopyable
    243 -    def _set_noncopyable(self, noncopyable):
    244          self._noncopyable= noncopyable
    245      noncopyable = property( _get_noncopyable, _set_noncopyable
    246                              , doc="True if the class is noncopyable, False otherwies" \
    247                                   +"Default value is calculated, based on information presented in the declarations tree" )
    248
    249 -    def _get_wrapper_alias( self ):
    250          if None is self._wrapper_alias:
    251              self._wrapper_alias = self._generate_valid_name(self.partial_name) + "_wrapper"
    252          return self._wrapper_alias
    253 -    def _set_wrapper_alias( self, walias ):
    254          self._wrapper_alias = walias
    255      wrapper_alias = property( _get_wrapper_alias, _set_wrapper_alias
    256                                , doc="class-wrapper name")
    257
    258      @property
    259 -    def declaration_code( self ):
    260          """
    261          List of strings, that contains valid C++ code, that will be added to
    262          the class declaration section
    263          """
    264          return self._declaration_code
    265
    266      @property
    267 -    def registration_code_head( self ):
    268          """
    269          List of strings, that contains valid C++ code, that will be added to
    270          the head of the class registration section
    271          """
    272          return self._registration_code_head
    273
    274      @property
    275 -    def registration_code_tail( self ):
    276          """
    277          List of strings, that contains valid C++ code, that will be added to
    278          the tail of the class registration section
    279          """
    280          return self._registration_code_tail
    281
    282      @property
    283 -    def registration_code( self ):
    284          """
    285          List of strings, that contains all C++ code, that will be added to
    286          the class registration section
    287          """
    288          return self.registration_code_head + self.registration_code_tail
    289
    290      @property
    291 -    def wrapper_code( self ):
    292          """
    293          List of strings, that contains valid C++ code, that will be added to
    294          the class wrapper.
    295          """
    296          return self._wrapper_code
    297
    298 -    def _get_null_constructor_body(self):
    299          c = self.find_trivial_constructor()
    300          if c:
    301              return c.body
    302          else:
    303              return ''
    304 -    def _set_null_constructor_body(self, body):
    305          c = self.find_trivial_constructor()
    306          if c:
    307              c.body = body
    308      null_constructor_body = property( _get_null_constructor_body, _set_null_constructor_body
    309                                        , doc="null constructor code, that will be added as is to the null constructor of class-wrapper" )
    310
    311 -    def _get_copy_constructor_body(self):
    312          c = self.find_copy_constructor()
    313          if c:
    314              return c.body
    315          else:
    316              return ''
    317
    318 -    def _set_copy_constructor_body(self, body):
    319          c = self.find_copy_constructor()
    320          if c:
    321              c.body = body
    322      copy_constructor_body = property( _get_copy_constructor_body, _set_copy_constructor_body
    323                                        , doc="copy constructor code, that will be added as is to the copy constructor of class-wrapper")
    324
    325      @property
    326 -    def destructor_code(self):
    327          """list of code to be added to wrapper destructor"""
    328          return self._destructor_code
    329
    330 -    def add_destructor_code(self, code):
    331          """adds code to the class-wrapper destructor"""
    332          self._destructor_code.append( code )
    333
    334      @property
    335 -    def exception_argument_name( self ):
    336          """exception argument name for translate exception function
    337
    338          If you don't understand what this argument is, please take a look on
    339          Boost.Python documentation: http://www.boost.org/libs/python/doc/v2/exception_translator.html
    340          """
    341          return 'exc'
    342
    343 -    def _get_exception_translation_code( self ):
    344          return self._exception_translation_code
    345 -    def _set_exception_translation_code( self, code ):
    346          self._exception_translation_code = code
    347      exception_translation_code = property( _get_exception_translation_code, _set_exception_translation_code
    348                                             , doc="C++ exception to Python exception translation code" \
    349                                                  +"\nExample: PyErr_SetString(PyExc_RuntimeError, exc.what()); " \
    350                                                  +"\nPy++ will generate the rest of the code." \
    351                                                  +"\nPay attention: the exception variable name is exc." )
    352
    353 -    def translate_exception_to_string( self, python_exception_type, to_string ):
    354          """registers exception translation to string
    355
    356          @param python_exception_type: Python exception type, for example PyExc_RuntimeError
    357          @type python_exception_type: str
    358
    359          @param to_string: C++ expression that extracts information from exception.
    360                            The type of expression should be char*.
    361          @type to_string: str
    362          """
    363          #NICE TO HAVE:
    364          #1. exception\assert\warning should be raised if python_exception_type
    365          #   does not contain valid Python exception
    366          #2. Py++ can validate, that member function returns char*
    367          code = "PyErr_SetString( %(exception_type)s, %(to_string)s ); " \
    368                 % { 'exception_type' : python_exception_type, 'to_string' : to_string }
    369          self.exception_translation_code = code
    370
    371 -    def add_declaration_code( self, code ):
    372          """adds the code to the declaration section"""
    373          self.declaration_code.append( user_text.user_text_t( code ) )
    374
    375 -    def add_registration_code( self, code, works_on_instance=True, tail=True ):
    376          """adds the code to the class registration section
    377
    378          @param works_on_instance: If true, the custom code can be applied directly to obj inst. Example: ObjInst.code
    379          @type works_on_instance: bool
    380
    381          @param tail: if True, the custom code is appended to the end of the class registration code.
    382          @type tail: bool
    383          """
    384          if tail:
    385              self.registration_code_tail.append( user_text.class_user_text_t( code, works_on_instance ) )
    386          else:
    387              self.registration_code_head.append( user_text.class_user_text_t( code, works_on_instance ) )
    388
    389      #preserving backward computability
    390      add_code = add_registration_code
    391
    392 -    def add_wrapper_code( self, code ):
    393          """adds code to the class wrapper class definition"""
    394          self.wrapper_code.append( user_text.user_text_t( code ) )
    395
    396 -    def set_constructors_body( self, body ):
    397          """Sets the body for all constructors"""
    398          constrs = self.constructors(allow_empty=True, recursive=False)
    399          if constrs:
    400              constrs.body = body
    401          self.null_constructor_body = body
    402          self.copy_constructor_body = body
    403
    404 -    def _exportable_impl( self ):
    405          if not self.name:
    406              named_parent = declarations.get_named_parent( self )
    407              if not named_parent:
    408                  return messages.W1057 % str( self )
    409              if isinstance( named_parent, declarations.namespace_t ):
    410                  return messages.W1018 % str( self )
    411          if self.class_type == declarations.CLASS_TYPES.UNION:
    412              if self.is_wrapper_needed():
    413                  return messages.W1059 % str( self )
    414              if self.name:
    415                  return messages.W1060 % str( self )
    416          if isinstance( self.parent, declarations.namespace_t ):
    417              return ''
    418          if not self in self.parent.public_members:
    419              return messages.W1019
    420          return ''
    421
    422 -    def get_exportable_members( self, sort=None ):
    423          """returns list of internal declarations that should\\could be exported"""
    424          #TODO: obviously this function should be shorter. Almost all logic of this class
    425          #      should be spread between decl_wrapper classes
    426          members = filter( lambda mv: mv.ignore == False and mv.exportable, self.public_members )
    427          #protected and private virtual functions that not overridable and not pure
    428          #virtual should not be exported
    429          for member in self.protected_members:
    430              if not isinstance( member, declarations.calldef_t ):
    431                  continue
    432              else:
    433                  members.append( member )
    434
    435          vfunction_selector = lambda member: isinstance( member, declarations.member_function_t ) \
    436                                              and member.virtuality == declarations.VIRTUALITY_TYPES.PURE_VIRTUAL
    437          members.extend( filter( vfunction_selector, self.private_members ) )
    438
    439          def is_exportable( decl ):
    440              #filter out non-public member operators - Py++ does not support them right now
    441              if isinstance( decl, declarations.member_operator_t ) \
    442                 and decl.access_type != declarations.ACCESS_TYPES.PUBLIC:
    443                  return False
    444              #remove artificial constructors
    445              if isinstance( decl, declarations.constructor_t ) and decl.is_artificial:
    446                  return False
    447              if decl.ignore == True or decl.exportable == False:
    448                  return False
    449              return True
    450          #-#if declarations.has_destructor( self ) \
    451          #-#   and not declarations.has_public_destructor( self ):
    452          members = filter( is_exportable, members )
    453          sorted_members = members
    454          if sort:
    455              sorted_members = sort( members )
    456          return sorted_members
    457
    458      @property
    459 -    def properties( self ):
    460          """list of properties"""
    461          return self._properties
    462
    463 -    def add_property( self, name, fget, fset=None, doc='' ):
    464          """adds new property to the class
    465
    466          @param name: name of the property
    467          @type name: str
    468
    469          @param fget: reference to the class member function
    470          @param fset: reference to the class member function, could be None
    471          @param doc: documentation string
    472          """
    473          self._properties.append( properties.property_t( name, fget, fset, doc ) )
    474
    475 -    def add_properties( self, recognizer=None, exclude_accessors=False ):
    476          props = properties.find_properties( self, recognizer, exclude_accessors )
    477          self.properties.extend( props )
    478
    479 -    def add_static_property( self, name, fget, fset=None, doc='' ):
    480          """adds new static property to the class"""
    481          self._properties.append( properties.property_t( name, fget, fset, doc, True ) )
    482
    483 -    def redefined_funcs( self ):
    484          """returns list of member functions that should be defined in class wrapper
    485
    486          It comes useful in 3 tier hierarchy:
    487          struct base{
    488              virtual void do_nothing() = 0;
    489          };
    490
    491          struct derived{
    492              virtual void do_something() = 0;
    493          };
    494
    495          struct concrete{
    496              virtual void do_nothing(){}
    497              virtual void do_something(){}
    498          };
    499
    500          derived_wrapper should define do_nothing function, otherwise the generated
    501          code will not compile
    502          """
    503
    504          if isinstance( self._redefined_funcs, list ):
    505              return self._redefined_funcs
    506
    507          all_included = declarations.custom_matcher_t( lambda decl: decl.ignore == False and decl.exportable )
    508          all_protected = declarations.access_type_matcher_t( 'protected' ) & all_included
    509          all_pure_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.PURE_VIRTUAL )
    510          all_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.VIRTUAL ) \
    511                        & ( declarations.access_type_matcher_t( 'public' ) \
    512                            | declarations.access_type_matcher_t( 'protected' ))
    513          all_not_pure_virtual = ~all_pure_virtual
    514
    515          query = all_protected | all_pure_virtual
    516          mf_query = query | all_virtual
    517          relevant_opers = declarations.custom_matcher_t( lambda decl: decl.symbol in ('()', '[]') )
    518          funcs = []
    519          defined_funcs = []
    520
    521          for base in self.recursive_bases:
    522              if base.access == ACCESS_TYPES.PRIVATE:
    523                  continue
    524              base_cls = base.related_class
    525
    526              funcs.extend( base_cls.member_functions( mf_query, recursive=False, allow_empty=True ) )
    527              funcs.extend( base_cls.member_operators( relevant_opers & query, recursive=False, allow_empty=True ) )
    528
    529              defined_funcs.extend( base_cls.member_functions( all_not_pure_virtual, recursive=False, allow_empty=True ) )
    530              defined_funcs.extend( base_cls.member_operators( all_not_pure_virtual & relevant_opers, recursive=False, allow_empty=True ) )
    531
    532          not_reimplemented_funcs = set()
    533          is_same_function = declarations.is_same_function
    534          for f in funcs:
    535              cls_fs = self.calldefs( name=f.name, recursive=False, allow_empty=True )
    536              for cls_f in cls_fs:
    537                  if is_same_function( f, cls_f ):
    538                      break
    539              else:
    540                  #should test whether this function has been added or not
    541                  for f_impl in not_reimplemented_funcs:
    542                      if is_same_function( f, f_impl ):
    543                          if declarations.is_base_and_derived( f_impl.parent, f.parent ):
    544                              #add function from the most derived class
    545                              not_reimplemented_funcs.remove( f_impl )
    546                              not_reimplemented_funcs.add( f )
    547                          break
    548                  else:
    549                      #should test whether this function is implemented in base class
    550                      if f.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL:
    551                          not_reimplemented_funcs.add( f )
    552                      else:
    553                          for f_defined in defined_funcs:
    554                              if is_same_function( f, f_defined ):
    555                                  break
    556                          else:
    557                              not_reimplemented_funcs.add( f )
    558          functions = filter( lambda f: ( False == f.ignore and True == f.exportable )
    559                                        or all_pure_virtual( f )
    560                              , list( not_reimplemented_funcs ) )
    561
    562
    563          #Boost.Python is not able to call for non-virtual function, from the base
    564          #class if there is a virtual function with the same within base class
    565          #See override_bug tester for more information
    566
    567          def buggy_bpl_filter( f ):
    568              if f.parent is self:
    569                  return False
    570              if f.access_type != ACCESS_TYPES.PUBLIC:
    571                  return False
    572              if f.virtuality != VIRTUALITY_TYPES.NOT_VIRTUAL:
    573                  return False
    574              #we need to check that we don't have "same" function in this class
    575              this_funs = self.decls( name=f.name
    576                                      , decl_type=declarations.calldef_t
    577                                      , recursive=False
    578                                      , allow_empty=True )
    579              for this_f in this_funs:
    580                  if is_same_function( this_f, f ):
    581                      #there is already the function in the class, so no need to redefined it
    582                      return False
    583              else:
    584                  return True
    585
    586          tmp = {} # id : f
    587          for redefined_f in functions:
    588              #redefined is virtual, I am not interested in virtual functions
    589              for rfo in redefined_f.overloads:
    590                  if id(rfo) in tmp:
    591                      continue
    592                  if buggy_bpl_filter( rfo ):
    593                      tmp[ id(rfo) ] = rfo
    594          functions.extend( tmp.values() )
    595
    596          functions.sort( cmp=lambda f1, f2: cmp( ( f1.name, f1.location.as_tuple() )
    597                                                  , ( f2.name, f2.location.as_tuple() ) ) )
    598
    599          self._redefined_funcs = functions
    600          return self._redefined_funcs
    601
    602 -    def is_wrapper_needed(self):
    603          """returns an explanation( list of str ) why wrapper is needed.
    604
    605          If wrapper is not needed than [] will be returned.
    606          """
    607          explanation = []
    608          if self.wrapper_code:
    609              explanation.append( messages.W1020 )
    610
    611          if self.null_constructor_body:
    612              explanation.append( messages.W1021 )
    613
    614          if self.copy_constructor_body:
    615              explanation.append( messages.W1022 )
    616
    617          if self.destructor_code:
    618              explanation.append( messages.W1055 )
    619
    620          redefined_funcs = self.redefined_funcs()
    621          if redefined_funcs:
    622              funcs = map( lambda f: f.name, redefined_funcs )
    623              explanation.append( messages.W1023 % ', '.join(funcs) )
    624
    625          for member in self.get_exportable_members():
    626              if isinstance( member, declarations.destructor_t ):
    627                  continue
    628              if isinstance( member, declarations.variable_t ):
    629                  explanation.extend( member.is_wrapper_needed() )
    630              if isinstance( member, declarations.class_t ) and member.is_wrapper_needed():
    631                  explanation.append( messages.W1028 % member.name)
    632              if isinstance( member, declarations.calldef_t ):
    633                  if isinstance( member, declarations.constructor_t ) and member.body:
    634                      explanation.append( messages.W1029 )
    635                  if member.virtuality != VIRTUALITY_TYPES.NOT_VIRTUAL:
    636                      explanation.append( messages.W1030 % member.name )
    637                  if member.access_type in ( ACCESS_TYPES.PROTECTED, ACCESS_TYPES.PRIVATE ):
    638                      explanation.append( messages.W1031 % member.name)
    639          return explanation
    640
    641 -    def _readme_impl( self ):
    642          explanation = self.is_wrapper_needed()
    643          for fc in self.fake_constructors:
    644              if fc.ignore:
    645                  explanation.append( messages.W1062 % ( str( self ), str( fc ) ) )
    646              if not fc.exportable:
    647                  explanation.append( messages.W1063 % ( str( self ), str( fc ) ) )
    648              if not isinstance( fc, self.FAKE_CONSTRUCTOR_TYPES ):
    649                  explanation.append( messages.W1064
    650                                      % ( str( fc ), str( self ), self.FAKE_CONSTRUCTOR_TYPE_NAMES ) )
    651          return explanation
    652
    653 -    def guess_always_expose_using_scope_value( self ):
    654          def is_assign( oper ):
    655              if oper.symbol != '=':
    656                  return False
    657              if oper.is_artificial:
    658                  return False
    659              if oper.access_type != ACCESS_TYPES.PUBLIC:
    660                  return False
    661              return True
    662          #MSVC 7.1 has problem with taking reference to operator=
    663          if self.member_operators( is_assign, allow_empty=True, recursive=False ):
    664              return impl_details.GUESS_VALUES.ALWAYS_TRUE
    665          return super(class_t, self).guess_always_expose_using_scope_value()
    666
    667 -    def _get_require_self_reference(self):
    668          return self._require_self_reference
    669 -    def _set_require_self_reference(self, require_self_reference):
    670          self._require_self_reference = require_self_reference
    671      require_self_reference = property( _get_require_self_reference, _set_require_self_reference
    672                       , doc="boolean, if True the first argument to the constructor will be reference to self object" )
    673
    674 -    def _get_expose_this( self ):
    675          return self._expose_this
    676 -    def _set_expose_this( self, new_value ):
    677          self._expose_this = new_value
    678      expose_this = property( _get_expose_this, _set_expose_this
    679                             , doc="boolean, if True an object address( this pointer ) will be exposed to Python as integer.")
    680
    681 -    def _get_expose_sizeof( self ):
    682          return self._expose_sizeof
    683 -    def _set_expose_sizeof( self, new_value ):
    684          self._expose_sizeof = new_value
    685      expose_sizeof = property( _get_expose_sizeof, _set_expose_sizeof
    686                                , doc="boolean, if True the sizeof(obj) will be exposed to Python as integer.")
    687
    688      @property
    689 -    def introduces_new_scope(self):
    690          """returns True, if during exposing this class, new scope will be created
    691
    692          For example, anonymous structs will be exposed in a parent scope.
    693          """
    694          if not self.name:
    695              return False
    696          elif self.class_type == declarations.CLASS_TYPES.UNION:
    697              return False
    698          else:
    699              return True
    700
    701 -    def _get_no_init( self ):
    702          if None is self._no_init and False == bool( self.indexing_suite ):
    703              #select all public constructors and exclude copy constructor
    704              cs = self.constructors( lambda c: not c.is_copy_constructor and c.access_type == 'public'
    705                                      , recursive=False, allow_empty=True )
    706
    707              has_suitable_constructor = bool( cs )
    708              if cs and len(cs) == 1 and cs[0].is_trivial_constructor and self.find_noncopyable_vars():
    709                  has_suitable_constructor = False
    710
    711              has_nonpublic_destructor = declarations.has_destructor( self ) \
    712                                         and not declarations.has_public_destructor( self )
    713
    714              trivial_constructor = self.find_trivial_constructor()
    715
    716              if has_nonpublic_destructor \
    717                 or ( self.is_abstract and not self.is_wrapper_needed() ) \
    718                 or not has_suitable_constructor:
    719                  self._no_init = True
    720              elif not trivial_constructor or trivial_constructor.access_type != 'public':
    721                  exportable_cs = filter( lambda c: c.exportable and c.ignore == False
    722                                          , cs )
    723                  if not exportable_cs:
    724                      self._no_init = True
    725              else:
    726                  pass
    727          if None is self._no_init:
    728              self._no_init = False
    729          return self._no_init
    730 -    def _set_no_init( self, value ):
    731          self._no_init = value
    732
    733      no_init = property( _get_no_init, _set_no_init
    734                          , doc="If True, class will be registered with 'boost::python::no_init'" )
    735