Package pyplusplus :: Package decl_wrappers :: Module variable_wrapper |

# Source Code for Module pyplusplus.decl_wrappers.variable_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 global and member variable exposing"""
      7
      8  import decl_wrapper
      9  import python_traits
     10  import call_policies
     11  import python_traits
     12  from pyplusplus import messages
     13  from pygccxml import declarations
     14
     15 -class variable_t(decl_wrapper.decl_wrapper_t, declarations.variable_t):
     16      """defines a set of properties, that will instruct Py++ how to expose the variable"""
     17 -    def __init__(self, *arguments, **keywords):
     18          declarations.variable_t.__init__(self, *arguments, **keywords )
     19          decl_wrapper.decl_wrapper_t.__init__( self )
     20          self._getter_call_policies = None
     21          self._setter_call_policies = None
     22          self._apply_smart_ptr_wa = False
     23          self._is_read_only = None
     24          self._use_make_functions = None
     25          self._expose_address = None
     26          self._expose_value = None
     27
     28      __call_policies_doc__ = \
     29      """There are usecase, when exporting member variable forces Py++ to
     30      create accessors functions. Sometime, those functions requires call policies.
     31      To be more specific: when you export member variable that has reference or
     32      pointer type, you need to tell Boost.Python library how to manage object
     33      life-time. In all cases, Py++ will give reasonable default value. I am
     34      sure, that there are use cases, when you will have to change it. You should
     35      use this property to change it.
     36      """
     37
     38 -    def get_getter_call_policies( self ):
     39          if None is self._getter_call_policies:
     40              if self.apply_smart_ptr_wa:
     41                  value_policy = ''
     42                  if self.is_read_only:
     43                     value_policy = call_policies.copy_const_reference
     44                  else:
     45                      value_policy = call_policies.copy_non_const_reference
     46                  self._getter_call_policies = call_policies.return_value_policy( value_policy )
     47              elif self.use_make_functions:
     48                  self._getter_call_policies = call_policies.return_internal_reference()
     49              else:
     50                  pass
     51          return self._getter_call_policies
     52 -    def set_getter_call_policies( self, call_policies ):
     53          self._getter_call_policies = call_policies
     54      getter_call_policies = property( get_getter_call_policies, set_getter_call_policies
     55                                       , doc=__call_policies_doc__ )
     56
     57 -    def get_setter_call_policies( self ):
     58          if None is self._getter_call_policies:
     59              if self.apply_smart_ptr_wa or self.use_make_functions:
     60                  self._setter_call_policies = call_policies.default_call_policies()
     61          return self._setter_call_policies
     62 -    def set_setter_call_policies( self, call_policies ):
     63          self._setter_call_policies = call_policies
     64      setter_call_policies = property( get_setter_call_policies, set_setter_call_policies
     65                                       , doc=__call_policies_doc__ )
     66
     67      __use_make_functions_doc__ = \
     68      """Generate code using make_getter and make_setter functions
     69
     70      Basically you don't need to use this, untill you have one of the next use-cases:
     71      * member variable is smart pointer - in this case Boost.Python has small problem
     72        to expose it right. Using the functions is a work around to the problem.
     73      * member variable defined custom r-value converter - may be you don't know
     74        but the conversion is applied only on functions arguments. So you need to
     75        use make_getter/make_setter in order to allow user to enjoy from the
     76        conversion.
     77
     78      Setting "apply_smart_ptr_wa" and/or "use_make_functions" to "True" will tell
     79      Py++ to generate such code.
     80      """
     81
     82 -    def get_apply_smart_ptr_wa( self ):
     83          return self._apply_smart_ptr_wa
     84 -    def set_apply_smart_ptr_wa( self, value):
     85          self._apply_smart_ptr_wa = value
     86      apply_smart_ptr_wa = property( get_apply_smart_ptr_wa, set_apply_smart_ptr_wa
     87                                       , doc=__use_make_functions_doc__ )
     88
     89 -    def get_use_make_functions( self ):
     90          return self._use_make_functions
     91 -    def set_use_make_functions( self, value ):
     92          self._use_make_functions = value
     93      use_make_functions = property( get_use_make_functions, set_use_make_functions
     94                                     , doc=__use_make_functions_doc__)
     95
     96 -    def __should_be_exposed_by_address_only(self):
     97          type_ = declarations.remove_alias( self.type )
     98          type_ = declarations.remove_const( type_ )
     99          type_ = declarations.remove_pointer( type_ )
    100          if not declarations.class_traits.is_my_case( type_ ):
    101              return False
    102          cls = declarations.class_traits.get_declaration( type_ )
    103          if cls.class_type == declarations.CLASS_TYPES.UNION:
    104              return True
    105          elif not cls.name:
    106              return True
    107          else:
    108              return False
    109
    110      __expose_address_doc__ = \
    111      """There are some cases when Boost.Python doesn't provide a convenient way
    112      to expose the variable to Python. For example:
    113
    114      double* x[10];
    115      //or
    116      char* buffer; //in case you want to modify the buffer in place
    117
    118      In this cases Py++ doesn't help too. In these cases it is possible to expose
    119      the actual address of the variable. After that, you can use built-in "ctypes"
    120      package to edit the content of the variable.
    121      """
    122 -    def get_expose_address( self ):
    123          if None is self._expose_address:
    124              self._expose_address = self.__should_be_exposed_by_address_only()
    125          return self._expose_address
    126 -    def set_expose_address( self, value ):
    127          self._expose_address = value
    128      expose_address = property( get_expose_address, set_expose_address
    129                                 , doc= __expose_address_doc__ )
    130
    131      __expose_value_doc__ = \
    132      """Boost.Python is not able to expose unions. Using ctypes module
    133      it is possible to get access to the data stored in a variable, which
    134      has some union type.
    135
    136      This property controls whether Py++ should expose the variable value
    137      or not. In case, this variable has type union, this property will be False.
    138      """
    139 -    def get_expose_value( self ):
    140          if None is self._expose_value:
    141              self._expose_value = not self.__should_be_exposed_by_address_only()
    142          return self._expose_value
    143 -    def set_expose_value( self, value ):
    144          self._expose_value = value
    145      expose_value = property( get_expose_value, set_expose_value
    146                               , doc= __expose_value_doc__ )
    147
    148 -    def __find_out_is_read_only(self):
    149          type_ = declarations.remove_alias( self.type )
    150
    151          if isinstance( type_, declarations.const_t ):
    152              return True
    153
    154          if declarations.is_pointer( type_ ):
    155              type_ = declarations.remove_pointer( type_ )
    156
    157          if declarations.is_reference( type_ ):
    158              type_ = declarations.remove_reference( type_ )
    159
    160          if isinstance( type_, declarations.const_t ):
    161              return True
    162
    163          if self.apply_smart_ptr_wa:
    164              return False #all smart pointers has assign operator
    165
    166          if isinstance( type_, declarations.declarated_t ) \
    167             and isinstance( type_.declaration, declarations.class_t ) \
    168             and not declarations.has_public_assign( type_.declaration ):
    169              return True
    170          return False
    171
    172 -    def get_is_read_only( self ):
    173          if None is self._is_read_only:
    174              self._is_read_only = self.__find_out_is_read_only()
    175          return self._is_read_only
    176 -    def set_is_read_only( self, v ):
    177          self._is_read_only = v
    178      is_read_only = property( get_is_read_only, set_is_read_only )
    179
    180 -    def _exportable_impl( self ):
    181          if not self.parent.name and self.is_wrapper_needed():
    182              #return messages.W1057 % str( self )
    183              return messages.W1058 % str( self )
    184          if not self.name:
    185              return messages.W1033
    186          if self.bits == 0 and self.name == "":
    187              return messages.W1034
    188          if not self.expose_address:
    189              if declarations.is_array( self.type ) and declarations.array_size( self.type ) < 1:
    190                  return messages.W1045
    191          type_ = declarations.remove_alias( self.type )
    192          type_ = declarations.remove_const( type_ )
    193          if declarations.is_pointer( type_ ):
    194              if not self.expose_address and self.type_qualifiers.has_static:
    195                  return messages.W1035
    196              if not self.expose_address and python_traits.is_immutable( type_.base ):
    197                  return messages.W1036
    198
    199              units = declarations.decompose_type( type_ )
    200              ptr2functions = filter( lambda unit: isinstance( unit, declarations.calldef_type_t )
    201                                      , units )
    202              if ptr2functions:
    203                  return messages.W1037
    204          type_ = declarations.remove_pointer( type_ )
    205          if declarations.class_traits.is_my_case( type_ ):
    206              cls = declarations.class_traits.get_declaration( type_ )
    207              if not cls.name:
    208                  return messages.W1038
    209              #if cls.class_type == declarations.CLASS_TYPES.UNION:
    210              #    return messages.W1061 % ( str( self ), str( cls ) )
    211          if isinstance( self.parent, declarations.class_t ):
    212              if self.access_type != declarations.ACCESS_TYPES.PUBLIC:
    213                  return messages.W1039
    214          if declarations.is_array( type_ ):
    215              item_type = declarations.array_item_type( type_ )
    216              if declarations.is_pointer( item_type ):
    217                  item_type_no_ptr = declarations.remove_pointer( item_type )
    218                  if python_traits.is_immutable( item_type_no_ptr ):
    219                      return messages.W1056
    220          return ''
    221
    222 -    def is_wrapper_needed(self):
    223          """returns an explanation( list of str ) why wrapper is needed.
    224
    225          If wrapper is not needed than [] will be returned.
    226          """
    227          explanation = []
    228          if self.bits:
    229              explanation.append( messages.W1024 % self.name )
    230          if declarations.is_pointer( self.type ):
    231              explanation.append( messages.W1025 % self.name )
    232          if declarations.is_reference( self.type ):
    233              explanation.append( messages.W1026 % self.name )
    234          if declarations.is_array( self.type ):
    235              explanation.append( messages.W1027 % self.name)
    236          return explanation
    237