Files
pybindgen/pybindgen/function.py
T

135 lines
4.9 KiB
Python

"""
C function wrapper
"""
from copy import copy
from typehandlers.base import ForwardWrapperBase
from typehandlers import codesink
import overloading
import settings
class Function(ForwardWrapperBase):
"""
Class that generates a wrapper to a C function.
"""
def __init__(self, return_value, function_name, parameters, docstring=None, unblock_threads=None):
"""
return_value -- the function return value
function_name -- name of the C function
parameters -- the function parameters
"""
if unblock_threads is None:
unblock_threads = settings.unblock_threads
super(Function, self).__init__(
return_value, parameters,
parse_error_return="return NULL;",
error_return="return NULL;",
unblock_threads=unblock_threads)
self._module = None
self.function_name = function_name
self.wrapper_base_name = None
self.wrapper_actual_name = None
self.docstring = docstring
self.self_parameter_pystruct = None
def clone(self):
"""Creates a semi-deep copy of this function wrapper. The returned
function wrapper clone contains copies of all parameters, so
they can be modified at will.
"""
func = Function(self.return_value,
self.function_name,
[copy(param) for param in self.parameters],
docstring=self.docstring)
func._module = self._module
func.wrapper_base_name = self.wrapper_base_name
func.wrapper_actual_name = self.wrapper_actual_name
return func
def get_module(self):
"""Get the Module object this function belongs to"""
return self._module
def set_module(self, module):
"""Set the Module object this function belongs to"""
self._module = module
self.wrapper_base_name = "_wrap_%s%s" % (module.prefix, self.function_name)
module = property(get_module, set_module)
def generate_call(self):
"virtual method implementation; do not call"
if self._module.cpp_namespace_prefix:
namespace = self._module.cpp_namespace_prefix + '::'
else:
namespace = ''
if self.return_value.ctype == 'void':
self.before_call.write_code(
'%s%s(%s);' % (namespace, self.function_name,
", ".join(self.call_params)))
else:
self.before_call.write_code(
'retval = %s%s(%s);' % (namespace, self.function_name,
", ".join(self.call_params)))
def _before_return_hook(self):
"hook that post-processes parameters and check for custodian=<n> CppClass parameters"
cppclass.implement_parameter_custodians(self)
def generate(self, code_sink, wrapper_name=None, extra_wrapper_params=()):
"""
Generates the wrapper code
code_sink -- a CodeSink instance that will receive the generated code
wrapper_name -- name of wrapper function
"""
if wrapper_name is None:
self.wrapper_actual_name = self.wrapper_base_name
else:
self.wrapper_actual_name = wrapper_name
tmp_sink = codesink.MemoryCodeSink()
self.generate_body(tmp_sink)
code_sink.writeln("static PyObject *")
python_args = ''
flags = self.get_py_method_def_flags()
if 'METH_VARARGS' in flags:
if self.self_parameter_pystruct is None:
self_param = 'PyObject * PYBINDGEN_UNUSED(dummy)'
else:
self_param = '%s *self' % self.self_parameter_pystruct
python_args += "%s, PyObject *args" % self_param
if 'METH_KEYWORDS' in flags:
python_args += ", PyObject *kwargs"
prototype_line = "%s(%s" % (self.wrapper_actual_name, python_args)
if extra_wrapper_params:
prototype_line += ", " + ", ".join(extra_wrapper_params)
prototype_line += ')'
code_sink.writeln(prototype_line)
code_sink.writeln('{')
code_sink.indent()
tmp_sink.flush_to(code_sink)
code_sink.unindent()
code_sink.writeln('}')
def get_py_method_def(self, name):
"""Returns an array element to use in a PyMethodDef table.
Should only be called after code generation.
name -- python function/method name
"""
flags = self.get_py_method_def_flags()
return "{\"%s\", (PyCFunction) %s, %s, %s }," % \
(name, self.wrapper_actual_name, '|'.join(flags),
(self.docstring is None and "NULL" or ('"'+self.docstring+'"')))
class OverloadedFunction(overloading.OverloadedWrapper):
"""Adds support for overloaded functions"""
RETURN_TYPE = 'PyObject *'
ERROR_RETURN = 'return NULL;'
import cppclass