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"""Contains definition of call policies classes""" 7 8from . import algorithm 9from . import python_traits 10from pygccxml import declarations 11 12#keeps file name, where `Py++` defined call policies will be defined 13PYPP_CALL_POLICIES_HEADER_FILE = "__call_policies.pypp.hpp" 14 15class CREATION_POLICY: 16 """Implementation details""" 17 AS_INSTANCE = 'as instance' 18 AS_TEMPLATE_ARGUMENT = 'as template argument' 19 20class call_policy_t(object): 21 """base class for all classes, which generate "call policies" code""" 22 def __init__(self): 23 object.__init__(self) 24 25 def create(self, function_creator, creation_policy=CREATION_POLICY.AS_INSTANCE): 26 """Creates code from the call policies class instance. 27 :param function_creator: parent code creator 28 :type function_creator: :class:`code_creators.function_t` or :class:`code_creators.constructor_t` 29 30 :param creation_policy: indicates whether we this call policy used as template 31 argument or as an instance 32 :type creation_policy: :class:`decl_wrappers.CREATION_POLICY` 33 """ 34 code = self._create_impl( function_creator ) 35 if code and creation_policy == CREATION_POLICY.AS_INSTANCE: 36 code = code + '()' 37 return code 38 39 def create_type(self): 40 """return call policies class declaration as string""" 41 return self.create( None, CREATION_POLICY.AS_TEMPLATE_ARGUMENT ) 42 43 def create_template_arg( self, function_creator ): 44 """return call policies class declaration as string""" 45 return self.create( function_creator, CREATION_POLICY.AS_TEMPLATE_ARGUMENT ) 46 47 def is_default( self ): 48 """return True is self is instance of :class:`decl_wrappers.default_call_policies_t` class""" 49 return False 50 51 def is_predefined( self ): 52 """return True if call policy is defined in Boost.Python library, False otherwise""" 53 return True 54 55 def _create_impl( self, function_creator ): 56 raise NotImplementedError() 57 58 @property 59 def header_file(self): 60 """return a name of the header file the call policy is defined in""" 61 return "boost/python.hpp" 62 63class default_call_policies_t(call_policy_t): 64 """implements code generation for boost::python::default_call_policies""" 65 def __init__( self ): 66 call_policy_t.__init__( self ) 67 68 def _create_impl(self, function_creator ): 69 return algorithm.create_identifier( function_creator, '::boost::python::default_call_policies' ) 70 71 def is_default( self ): 72 return True 73 74 def __str__(self): 75 return 'default_call_policies' 76 77def default_call_policies(): 78 """create ::boost::python::default_call_policies call policies code generator""" 79 return default_call_policies_t() 80 81class compound_policy_t( call_policy_t ): 82 """base class for all call policies, except the default one""" 83 def __init__( self, base=None ): 84 call_policy_t.__init__( self ) 85 self._base = base 86 if not base: 87 self._base = default_call_policies_t() 88 89 def _get_base_policy( self ): 90 return self._base 91 def _set_base_policy( self, new_policy ): 92 self._base = new_policy 93 base_policy = property( _get_base_policy, _set_base_policy 94 , doc="base call policy, by default is reference to :class:`decl_wrappers.default_call_policies_t` call policy") 95 96 def _get_args(self, function_creator): 97 return [] 98 99 def _get_name(self, function_creator): 100 raise NotImplementedError() 101 102 def _create_impl( self, function_creator ): 103 args = self._get_args(function_creator) 104 if not self._base.is_default(): 105 args.append( self._base.create( function_creator, CREATION_POLICY.AS_TEMPLATE_ARGUMENT ) ) 106 name = algorithm.create_identifier( function_creator, self._get_name(function_creator) ) 107 return declarations.templates.join( name, args ) 108 109 def __str__(self): 110 name = self._get_name(None).replace('::boost::python::', '' ) 111 args = [text.replace( '::boost::python::', '' ) for text in self._get_args( None )] 112 return declarations.templates.join( name, args ) 113 114class return_argument_t( compound_policy_t ): 115 """implements code generation for boost::python::return_argument call policies""" 116 def __init__( self, position=1, base=None): 117 compound_policy_t.__init__( self, base ) 118 self._position = position 119 120 def _get_position( self ): 121 return self._position 122 def _set_position( self, new_position): 123 self._position = new_position 124 position = property( _get_position, _set_position ) 125 126 def _get_name(self, function_creator): 127 if self.position == 1: 128 return '::boost::python::return_self' 129 else: 130 return '::boost::python::return_arg' 131 132 def _get_args(self, function_creator): 133 if self.position == 1: 134 return [] 135 else: 136 return [ str( self.position ) ] 137 138def return_arg( arg_pos, base=None ): 139 """create boost::python::return_arg call policies code generator""" 140 return return_argument_t( arg_pos, base ) 141 142def return_self(base=None): 143 """create boost::python::return_self call policies code generator""" 144 return return_argument_t( 1, base ) 145 146class return_internal_reference_t( compound_policy_t ): 147 """implements code generation for boost::python::return_internal_reference call policies""" 148 def __init__( self, position=1, base=None): 149 compound_policy_t.__init__( self, base ) 150 self._position = position 151 152 def _get_position( self ): 153 return self._position 154 def _set_position( self, new_position): 155 self._position = new_position 156 position = property( _get_position, _set_position ) 157 158 def _get_name(self, function_creator): 159 return '::boost::python::return_internal_reference' 160 161 def _get_args(self, function_creator): 162 if self.position == 1: 163 return [] #don't generate default template arguments 164 else: 165 return [ str( self.position ) ] 166 167def return_internal_reference( arg_pos=1, base=None): 168 """create boost::python::return_internal_reference call policies code generator""" 169 return return_internal_reference_t( arg_pos, base ) 170 171class with_custodian_and_ward_t( compound_policy_t ): 172 """implements code generation for boost::python::with_custodian_and_ward call policies""" 173 def __init__( self, custodian, ward, base=None): 174 compound_policy_t.__init__( self, base ) 175 self._custodian = custodian 176 self._ward = ward 177 178 def _get_custodian( self ): 179 return self._custodian 180 def _set_custodian( self, new_custodian): 181 self._custodian = new_custodian 182 custodian = property( _get_custodian, _set_custodian ) 183 184 def _get_ward( self ): 185 return self._ward 186 def _set_ward( self, new_ward): 187 self._ward = new_ward 188 ward = property( _get_ward, _set_ward ) 189 190 def _get_name(self, function_creator): 191 return '::boost::python::with_custodian_and_ward' 192 193 def _get_args(self, function_creator): 194 return [ str( self.custodian ), str( self.ward ) ] 195 196def with_custodian_and_ward( custodian, ward, base=None): 197 """create boost::python::with_custodian_and_ward call policies code generator""" 198 return with_custodian_and_ward_t( custodian, ward, base ) 199 200class with_custodian_and_ward_postcall_t( with_custodian_and_ward_t ): 201 """implements code generation for boost::python::with_custodian_and_ward_postcall call policies""" 202 def __init__( self, custodian, ward, base=None): 203 with_custodian_and_ward_t.__init__( self, custodian, ward, base ) 204 205 def _get_name(self, function_creator): 206 return '::boost::python::with_custodian_and_ward_postcall' 207 208def with_custodian_and_ward_postcall( custodian, ward, base=None): 209 """create boost::python::with_custodian_and_ward_postcall call policies code generator""" 210 return with_custodian_and_ward_postcall_t( custodian, ward, base ) 211 212class return_value_policy_t( compound_policy_t ): 213 """implements code generation for boost::python::return_value_policy call policies""" 214 def __init__( self, result_converter_generator, base=None): 215 compound_policy_t.__init__( self, base ) 216 self._result_converter_generator = result_converter_generator 217 218 def _get_result_converter_generator( self ): 219 return self._result_converter_generator 220 def _set_result_converter_generator( self, new_result_converter_generator): 221 self._result_converter_generator = new_result_converter_generator 222 result_converter_generator = property( _get_result_converter_generator 223 , _set_result_converter_generator ) 224 225 def _get_name(self, function_creator): 226 return '::boost::python::return_value_policy' 227 228 def _get_args(self, function_creator): 229 if function_creator: 230 rcg = algorithm.create_identifier( function_creator, self.result_converter_generator ) 231 return [ rcg ] 232 else: 233 return [self.result_converter_generator] 234 235 def is_predefined( self ): 236 """Returns True if call policy is defined in Boost.Python library, False otherwise""" 237 global return_addressof 238 global return_pointee_value 239 if self.result_converter_generator in (return_pointee_value, return_addressof ): 240 return False 241 else: 242 return True 243 244 @property 245 def header_file(self): 246 """Return name of the header file to be included""" 247 if self.is_predefined(): 248 return super( return_value_policy_t, self ).header_file 249 else: 250 return PYPP_CALL_POLICIES_HEADER_FILE 251 252 253copy_const_reference = '::boost::python::copy_const_reference' 254copy_non_const_reference = '::boost::python::copy_non_const_reference' 255manage_new_object = '::boost::python::manage_new_object' 256reference_existing_object = '::boost::python::reference_existing_object' 257return_by_value = '::boost::python::return_by_value' 258return_opaque_pointer = '::boost::python::return_opaque_pointer' 259return_pointee_value = '::pyplusplus::call_policies::return_pointee_value' 260return_addressof = '::pyplusplus::call_policies::return_addressof' 261 262def return_value_policy( result_converter_generator, base=None): 263 """create boost::python::return_value_policy call policies code generator""" 264 return return_value_policy_t( result_converter_generator, base ) 265 266def is_return_opaque_pointer_policy( policy ): 267 """returns True is policy represents return_value_policy<return_opaque_pointer>, False otherwise""" 268 return isinstance( policy, return_value_policy_t ) \ 269 and policy.result_converter_generator == return_opaque_pointer 270 271class custom_call_policies_t(call_policy_t): 272 """implements code generation for user defined call policies""" 273 def __init__( self, call_policies, header_file=None ): 274 call_policy_t.__init__( self ) 275 self.__call_policies = call_policies 276 self.__header_file = header_file 277 278 def _create_impl(self, function_creator ): 279 return str( self.__call_policies ) 280 281 def __str__(self): 282 return 'custom call policies' 283 284 def get_header_file( self ): 285 return self.__header_file 286 def set_header_file( self, header_file_name ): 287 self.__header_file = header_file_name 288 header_file = property( get_header_file, set_header_file 289 , doc="""Return name of the header file to be included""" ) 290 291def custom_call_policies(call_policies, header_file=None): 292 """create custom\\user defined call policies code generator""" 293 return custom_call_policies_t(call_policies, header_file) 294 295class memory_managers: 296 """implements code generation for `Py++` defined memory managers 297 298 For complete documentation and usage example see "Call policies" document. 299 """ 300 none = 'none' 301 delete_ = 'delete_' 302 all = [ none, delete_ ] 303 304 @staticmethod 305 def create( manager, function_creator=None): 306 mem_manager = 'pyplusplus::call_policies::memory_managers::' + manager 307 if function_creator: 308 mem_manager = algorithm.create_identifier( function_creator, mem_manager ) 309 return mem_manager 310 311class convert_array_to_tuple_t( compound_policy_t ): 312 """implements code generation for `Py++` defined "as_tuple" value policy 313 314 For complete documentation and usage example see "Call policies" document. 315 """ 316 def __init__( self, array_size, memory_manager, make_object_call_policies=None, base=None): 317 compound_policy_t.__init__( self, base ) 318 self._array_size = array_size 319 self._memory_manager = memory_manager 320 self._make_objec_call_policies = make_object_call_policies 321 322 def is_predefined( self ): 323 """Returns True if call policy is defined in Boost.Python library, False otherwise""" 324 return False 325 326 @property 327 def header_file(self): 328 """Return name of the header file to be included""" 329 return PYPP_CALL_POLICIES_HEADER_FILE 330 331 def _get_array_size( self ): 332 return self._array_size 333 def _set_array_size( self, new_array_size): 334 self._array_size = new_array_size 335 array_size = property( _get_array_size, _set_array_size ) 336 337 def _get_memory_manager( self ): 338 return self._memory_manager 339 def _set_memory_manager( self, new_memory_manager): 340 self._memory_manager = new_memory_manager 341 memory_manager = property( _get_memory_manager, _set_memory_manager ) 342 343 def _get_make_objec_call_policies( self ): 344 if None is self._make_objec_call_policies: 345 self._make_objec_call_policies = default_call_policies() 346 return self._make_objec_call_policies 347 def _set_make_objec_call_policies( self, new_make_objec_call_policies): 348 self._make_objec_call_policies = new_make_objec_call_policies 349 make_objec_call_policies = property( _get_make_objec_call_policies, _set_make_objec_call_policies ) 350 351 def _get_name(self, function_creator): 352 return '::boost::python::return_value_policy' 353 354 def _get_args(self, function_creator): 355 as_tuple_args = [ str( self.array_size ) ] 356 as_tuple_args.append( memory_managers.create( self.memory_manager, function_creator ) ) 357 if not self.make_objec_call_policies.is_default(): 358 as_tuple_args.append( self.make_objec_call_policies.create_template_arg( function_creator ) ) 359 as_tuple = '::pyplusplus::call_policies::arrays::as_tuple' 360 if function_creator: 361 as_tuple = algorithm.create_identifier( function_creator, as_tuple ) 362 return [ declarations.templates.join( as_tuple, as_tuple_args ) ] 363 364def convert_array_to_tuple( array_size, memory_manager, make_object_call_policies=None, base=None ): 365 """create boost::python::return_value_policy< py++::as_tuple > call policies code generator""" 366 return convert_array_to_tuple_t( array_size, memory_manager, make_object_call_policies, base ) 367 368class return_range_t( call_policy_t ): 369 """implements code generation for `Py++` defined "return_range" call policies 370 371 For complete documentation and usage example see "Call policies" document. 372 """ 373 HEADER_FILE = "__return_range.pypp.hpp" 374 def __init__( self, get_size_class, value_type, value_policies): 375 call_policy_t.__init__( self ) 376 self._value_type = value_type 377 self._get_size_class = get_size_class 378 self._value_policies = value_policies 379 380 def is_predefined( self ): 381 """Returns True if call policy is defined in Boost.Python library, False otherwise""" 382 return False 383 384 @property 385 def header_file(self): 386 """Return name of the header file to be included""" 387 return self.HEADER_FILE 388 389 def _get_get_size_class( self ): 390 return self._get_size_class 391 def _set_get_size_class( self, new_get_size_class): 392 self._get_size_class = new_get_size_class 393 get_size_class = property( _get_get_size_class, _set_get_size_class ) 394 395 def _get_value_type( self ): 396 return self._value_type 397 def _set_value_type( self, new_value_type): 398 self._value_type = new_value_type 399 value_type = property( _get_value_type, _set_value_type ) 400 401 def _get_value_policies( self ): 402 return self._value_policies 403 def _set_value_policies( self, new_value_policies): 404 self._value_policies = new_value_policies 405 value_policies = property( _get_value_policies, _set_value_policies ) 406 407 def _create_impl(self, function_creator ): 408 name = algorithm.create_identifier( function_creator, '::pyplusplus::call_policies::return_range' ) 409 args = [ self.get_size_class, self.value_type.decl_string ] 410 if not self.value_policies.is_default(): 411 args.append( self.value_policies.create_type() ) 412 return declarations.templates.join( name, args ) 413 414def return_range( function, get_size_class, value_policies=None ): 415 """create `Py++` defined return_range call policies code generator""" 416 r_type = function.return_type 417 if not declarations.is_pointer( r_type ): 418 raise TypeError( 'Function "%s" return type should be pointer, got "%s"' 419 % r_type.decl_string ) 420 421 value_type = declarations.remove_pointer( r_type ) 422 if None is value_policies: 423 if python_traits.is_immutable( value_type ): 424 value_policies = default_call_policies() 425 else: 426 raise RuntimeError( "return_range call policies requieres specification of value_policies" ) 427 return return_range_t( get_size_class, value_type, value_policies ) 428 429