Fix Bug #138344: Generic C++ functions can't be assigned to a method in python.

This commit is contained in:
Gustavo J. A. M. Carneiro committed 2007-09-09 23:16:25 +01:00
1 parent 5b7ae2645d
commit d100de1a5b
6 files changed
+127 -32

No files matched your search

+15
View File
@@ -132,3 +132,18 @@ SomeObject * set_foobar_with_return_as_custodian(Foobar *foobar)
foobar++;
return new SomeObject("xxx");
}
std::string some_object_get_something_prefixed(const SomeObject *obj, const std::string something)
{
return obj->get_prefix() + something;
}
std::string some_object_val_get_something_prefixed(SomeObject obj, const std::string something)
{
return obj.get_prefix() + something;
}
std::string some_object_ref_get_something_prefixed(const SomeObject &obj, const std::string something)
{
return obj.get_prefix() + something;
}
+6
View File
@@ -294,6 +294,12 @@ public:
};
// A function that will appear as a method of SomeObject
// obj: transfer_ownership=false
std::string some_object_get_something_prefixed(const SomeObject *obj, const std::string something);
std::string some_object_val_get_something_prefixed(SomeObject obj, const std::string something);
std::string some_object_ref_get_something_prefixed(const SomeObject &obj, const std::string something);
// Transfer ownership of 'obj' to the library
+21
View File
@@ -152,6 +152,27 @@ def my_module_gen(out_file):
is_virtual=True, is_const=True))
## add a function that appears as a method of an object
SomeObject.add_method(
Function(ReturnValue.new('std::string'), 'some_object_get_something_prefixed',
[Parameter.new('SomeObject*', 'obj', transfer_ownership=False, is_const=True),
Parameter.new('std::string', 'something')]),
name='get_something_prefixed')
## add a function that appears as a method of an object
SomeObject.add_method(
Function(ReturnValue.new('std::string'), 'some_object_val_get_something_prefixed',
[Parameter.new('SomeObject', 'obj'),
Parameter.new('std::string', 'something')]),
name='val_get_something_prefixed')
## add a function that appears as a method of an object
SomeObject.add_method(
Function(ReturnValue.new('std::string'), 'some_object_ref_get_something_prefixed',
[Parameter.new('SomeObject&', 'obj', is_const=True),
Parameter.new('std::string', 'something')]),
name='ref_get_something_prefixed')
# ---
SomeObject.add_method(CppMethod(
ReturnValue.new('std::string'), 'call_get_prefix', []))
+12
View File
@@ -543,6 +543,18 @@ class TestFoo(unittest.TestCase):
f2 = obj.foo
self.assertEqual(f2.get_datum(), "hello")
def test_function_as_method(self):
obj = foo.SomeObject("xpto")
self.assertEqual(obj.get_something_prefixed("something"), "xptosomething")
def test_function_as_method_val(self):
obj = foo.SomeObject("xpto")
self.assertEqual(obj.val_get_something_prefixed("something"), "xptosomething")
def test_function_as_method_ref(self):
obj = foo.SomeObject("xpto")
self.assertEqual(obj.ref_get_something_prefixed("something"), "xptosomething")
if __name__ == '__main__':
unittest.main()
+66 -30
View File
@@ -14,6 +14,7 @@ from cppmethod import CppMethod, CppConstructor, CppNoConstructor, \
from cppattribute import (CppInstanceAttributeGetter, CppInstanceAttributeSetter,
CppStaticAttributeGetter, CppStaticAttributeSetter,
PyGetSetDef, PyMetaclass)
import settings
class CppHelperClass(object):
@@ -416,9 +417,19 @@ public:
from Python side
"""
assert name is None or isinstance(name, str)
assert isinstance(method, CppMethod)
if name is None:
name = method.method_name
if isinstance(method, CppMethod):
if name is None:
name = method.method_name
elif isinstance(method, function.Function):
assert name is not None
assert isinstance(method.parameters[0], CppClassParameterBase)
assert method.parameters[0].cpp_class is self
method.parameters[0].take_value_from_python_self = True
method.module = self.module
method.is_virtual = False
method.self_parameter_pystruct = self.pystruct
else:
raise TypeError
try:
overload = self.methods[name]
@@ -780,6 +791,11 @@ class CppClassParameterBase(Parameter):
## name of the PyFoo * variable used in parameter parsing
self.py_name = None
## it True, this parameter is 'fake', and instead of being
## passed a parameter from python it is assumed to be the
## 'self' parameter of a method wrapper
self.take_value_from_python_self = False
class CppClassReturnValueBase(ReturnValue):
"Class return handlers -- base class"
@@ -802,13 +818,15 @@ class CppClassParameter(CppClassParameterBase):
"parses python args to get C++ value"
assert isinstance(wrapper, ForwardWrapperBase)
assert isinstance(self.cpp_class, CppClass)
name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name)
self.py_name = name
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+name], self.name)
if self.take_value_from_python_self:
self.py_name = 'self'
else:
self.py_name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name)
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+self.py_name], self.name)
wrapper.call_params.append(
'*((%s *) %s)->obj' % (self.cpp_class.pystruct, name))
'*((%s *) %s)->obj' % (self.cpp_class.pystruct, self.py_name))
def convert_c_to_python(self, wrapper):
'''Write some code before calling the Python method.'''
@@ -854,31 +872,38 @@ class CppClassRefParameter(CppClassParameterBase):
assert isinstance(wrapper, ForwardWrapperBase)
assert isinstance(self.cpp_class, CppClass)
name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name)
self.py_name = name
if self.direction == Parameter.DIRECTION_IN:
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+name], self.name)
wrapper.call_params.append('*%s->obj' % (name,))
if self.take_value_from_python_self:
self.py_name = 'self'
else:
self.py_name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name)
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+self.py_name], self.name)
wrapper.call_params.append('*%s->obj' % (self.py_name,))
elif self.direction == Parameter.DIRECTION_OUT:
assert not self.take_value_from_python_self
self.py_name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name)
if self.cpp_class.allow_subclassing:
new_func = 'PyObject_GC_New'
else:
new_func = 'PyObject_New'
wrapper.before_call.write_code(
"%s = %s(%s, %s);" %
(name, new_func, self.cpp_class.pystruct,
(self.py_name, new_func, self.cpp_class.pystruct,
'&'+self.cpp_class.pytypestruct))
if self.cpp_class.allow_subclassing:
wrapper.after_call.write_code(
"%s->inst_dict = NULL;" % (name,))
"%s->inst_dict = NULL;" % (self.py_name,))
wrapper.before_call.write_code(
"%s->obj = new %s;" % (name, self.cpp_class.full_name))
wrapper.call_params.append('*%s->obj' % (name,))
wrapper.build_params.add_parameter("N", [name])
"%s->obj = new %s;" % (self.py_name, self.cpp_class.full_name))
wrapper.call_params.append('*%s->obj' % (self.py_name,))
wrapper.build_params.add_parameter("N", [self.py_name])
## well, personally I think inout here doesn't make much sense
## (it's just plain confusing), but might as well support it..
@@ -887,10 +912,15 @@ class CppClassRefParameter(CppClassParameterBase):
## modifications, i.e. the object is not explicitly returned
## but is instead modified by the callee.
elif self.direction == Parameter.DIRECTION_INOUT:
assert not self.take_value_from_python_self
self.py_name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name)
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+name], self.name)
'O!', ['&'+self.cpp_class.pytypestruct, '&'+self.py_name], self.name)
wrapper.call_params.append(
'*%s->obj' % (name))
'*%s->obj' % (self.py_name))
def convert_c_to_python(self, wrapper):
'''Write some code before calling the Python method.'''
@@ -1035,22 +1065,25 @@ class CppClassPtrParameter(CppClassParameterBase):
"parses python args to get C++ value"
assert isinstance(wrapper, ForwardWrapperBase)
assert isinstance(self.cpp_class, CppClass)
name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name)
self.py_name = name
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+name], self.name)
if self.take_value_from_python_self:
self.py_name = 'self'
else:
self.py_name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name)
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+self.py_name], self.name)
value = self.transformation.transform(
self, wrapper.declarations, wrapper.before_call, '%s->obj' % name)
self, wrapper.declarations, wrapper.before_call, '%s->obj' % self.py_name)
wrapper.call_params.append(value)
if self.transfer_ownership:
if self.cpp_class.incref_method is None:
wrapper.after_call.write_code('%s->obj = NULL;' % (name,))
wrapper.after_call.write_code('%s->obj = NULL;' % (self.py_name,))
else:
wrapper.before_call.write_code('%s->obj->%s();' % (
name, self.cpp_class.incref_method,))
self.py_name, self.cpp_class.incref_method,))
def convert_c_to_python(self, wrapper):
@@ -1387,3 +1420,6 @@ def implement_parameter_custodians(wrapper):
assert custodian_param.cpp_class.allow_subclassing
_add_ward(wrapper, "((PyObject *) %s)" % custodian_param.py_name,
"((PyObject *) %s)" % param.py_name)
import function
+7 -2
View File
@@ -7,7 +7,6 @@ from copy import copy
from typehandlers.base import ForwardWrapperBase
from typehandlers import codesink
import overloading
import cppclass
class Function(ForwardWrapperBase):
@@ -30,6 +29,7 @@ class Function(ForwardWrapperBase):
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
@@ -90,7 +90,11 @@ class Function(ForwardWrapperBase):
python_args = ''
flags = self.get_py_method_def_flags()
if 'METH_VARARGS' in flags:
python_args += "PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args"
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"
@@ -123,3 +127,4 @@ class OverloadedFunction(overloading.OverloadedWrapper):
RETURN_TYPE = 'PyObject *'
ERROR_RETURN = 'return NULL;'
import cppclass