Implement and test CppClassPtrParameter c_to_python conversion.
This commit is contained in:
1 parent
236e26ce7f
commit
97d03d682c
3 files changed
+144
-6
No files matched your search
@@ -143,10 +143,10 @@ def my_module_gen(out_file):
|
||||
direction=Parameter.DIRECTION_INOUT)],
|
||||
is_virtual=True, is_const=True))
|
||||
|
||||
#SomeObject.add_method(CppMethod(
|
||||
# ReturnValue.new('std::string'), 'get_prefix_with_foo_ptr',
|
||||
# [Parameter.new('Foo*', 'foo', transfer_ownership=False)],
|
||||
# is_virtual=True, is_const=True))
|
||||
SomeObject.add_method(CppMethod(
|
||||
ReturnValue.new('std::string'), 'get_prefix_with_foo_ptr',
|
||||
[Parameter.new('Foo*', 'foo', transfer_ownership=False, is_const=True)],
|
||||
is_virtual=True, is_const=True))
|
||||
|
||||
|
||||
# ---
|
||||
|
||||
@@ -522,5 +522,20 @@ class TestFoo(unittest.TestCase):
|
||||
self.assertEqual(prefix, "123zbr456zbr")
|
||||
|
||||
|
||||
def test_subclass_with_virtual_with_foo_parameter_ptr(self):
|
||||
class Test(foo.SomeObject):
|
||||
def __init__(self, prefix, extra_prefix):
|
||||
super(Test, self).__init__(prefix)
|
||||
self.extra_prefix = extra_prefix
|
||||
def _get_prefix_with_foo_ptr(self, fooval):
|
||||
prefix = super(Test, self)._get_prefix_with_foo_ptr(fooval)
|
||||
return prefix + self.extra_prefix + fooval.get_datum()
|
||||
|
||||
t = Test("123", "456")
|
||||
foo1 = foo.Foo("zbr")
|
||||
prefix = t.get_prefix_with_foo_ptr(foo1)
|
||||
self.assertEqual(prefix, "123zbr456zbr")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
+125
-2
@@ -821,7 +821,7 @@ class CppClassParameter(CppClassParameterBase):
|
||||
(self.py_name, new_func, self.cpp_class.pystruct, '&'+self.cpp_class.pytypestruct))
|
||||
if self.cpp_class.allow_subclassing:
|
||||
wrapper.before_call.write_code(
|
||||
"%s->inst_dict = NULL;" % (py_name,))
|
||||
"%s->inst_dict = NULL;" % (self.py_name,))
|
||||
wrapper.before_call.write_code(
|
||||
"%s->obj = new %s(%s);" % (self.py_name, self.cpp_class.full_name, self.value))
|
||||
wrapper.build_params.add_parameter("N", [self.py_name])
|
||||
@@ -903,7 +903,7 @@ class CppClassRefParameter(CppClassParameterBase):
|
||||
(self.py_name, new_func, self.cpp_class.pystruct, '&'+self.cpp_class.pytypestruct))
|
||||
if self.cpp_class.allow_subclassing:
|
||||
wrapper.before_call.write_code(
|
||||
"%s->inst_dict = NULL;" % (py_name,))
|
||||
"%s->inst_dict = NULL;" % (self.py_name,))
|
||||
|
||||
if self.direction == Parameter.DIRECTION_IN:
|
||||
wrapper.before_call.write_code(
|
||||
@@ -1049,6 +1049,128 @@ class CppClassPtrParameter(CppClassParameterBase):
|
||||
name, self.cpp_class.incref_method,))
|
||||
|
||||
|
||||
def convert_c_to_python(self, wrapper):
|
||||
"""foo"""
|
||||
|
||||
## Value transformations
|
||||
value = self.transformation.untransform(
|
||||
self, wrapper.declarations, wrapper.after_call, self.value)
|
||||
|
||||
## declare wrapper variable
|
||||
py_name = wrapper.declarations.declare_variable(
|
||||
self.cpp_class.pystruct+'*', 'py_'+self.cpp_class.name)
|
||||
self.py_name = py_name
|
||||
|
||||
def write_create_new_wrapper():
|
||||
"""Code path that creates a new wrapper for the parameter"""
|
||||
|
||||
## Find out what Python wrapper to use, in case
|
||||
## automatic_type_narrowing is active and we are not forced to
|
||||
## make a copy of the object
|
||||
if (self.cpp_class.automatic_type_narrowing
|
||||
and (self.transfer_ownership or self.cpp_class.incref_method is not None)):
|
||||
|
||||
typeid_map_name = self.cpp_class.get_type_narrowing_root().typeid_map_name
|
||||
wrapper_type = wrapper.declarations.declare_variable(
|
||||
'PyTypeObject*', 'wrapper_type', '0')
|
||||
wrapper.before_call.write_code(
|
||||
'%s = %s.lookup_wrapper(typeid(*%s), &%s);'
|
||||
% (wrapper_type, typeid_map_name, value, self.cpp_class.pytypestruct))
|
||||
else:
|
||||
wrapper_type = '&'+self.cpp_class.pytypestruct
|
||||
|
||||
## Create the Python wrapper object
|
||||
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);" %
|
||||
(py_name, new_func, self.cpp_class.pystruct, wrapper_type))
|
||||
self.py_name = py_name
|
||||
|
||||
if self.cpp_class.allow_subclassing:
|
||||
wrapper.before_call.write_code(
|
||||
"%s->inst_dict = NULL;" % (py_name,))
|
||||
|
||||
## Assign the C++ value to the Python wrapper
|
||||
if self.transfer_ownership:
|
||||
wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
|
||||
wrapper.build_params.add_parameter("N", [py_name])
|
||||
else:
|
||||
if self.cpp_class.incref_method is None:
|
||||
## The PyObject gets a temporary pointer to the
|
||||
## original value; the pointer is converted to a
|
||||
## copy in case the callee retains a reference to
|
||||
## the object after the call.
|
||||
|
||||
if self.direction == Parameter.DIRECTION_IN:
|
||||
|
||||
wrapper.before_call.write_code(
|
||||
"%s->obj = new %s(*%s);" %
|
||||
(self.py_name, self.cpp_class.full_name, self.value))
|
||||
|
||||
wrapper.build_params.add_parameter("N", [self.py_name])
|
||||
else:
|
||||
## out/inout case:
|
||||
## the callee receives a "temporary wrapper", which loses
|
||||
## the ->obj pointer after the python call; this is so
|
||||
## that the python code directly manipulates the object
|
||||
## received as parameter, instead of a copy.
|
||||
if self.is_const:
|
||||
unconst_value = "const_cast<%s*>(%s)" % (self.cpp_class.full_name, value)
|
||||
else:
|
||||
unconst_value = value
|
||||
wrapper.before_call.write_code(
|
||||
"%s->obj = %s;" % (self.py_name, unconst_value))
|
||||
wrapper.build_params.add_parameter("O", [self.py_name])
|
||||
wrapper.before_call.add_cleanup_code("Py_DECREF(%s);" % self.py_name)
|
||||
|
||||
## if after the call we notice the callee kept a reference
|
||||
## to the pyobject, we then swap pywrapper->obj for a copy
|
||||
## of the original object. Else the ->obj pointer is
|
||||
## simply erased (we never owned this object in the first
|
||||
## place).
|
||||
wrapper.after_call.write_code(
|
||||
"if (%s->ob_refcnt == 1)\n"
|
||||
" %s->obj = NULL;\n"
|
||||
"else\n"
|
||||
" %s->obj = new %s(*%s);" %
|
||||
(self.py_name, self.py_name, self.py_name,
|
||||
self.cpp_class.full_name, value))
|
||||
|
||||
else:
|
||||
## The PyObject gets a new reference to the same obj
|
||||
wrapper.before_call.write_code(
|
||||
"%s->%s();" % (value, self.cpp_class.incref_method))
|
||||
wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
|
||||
wrapper.build_params.add_parameter("N", [py_name])
|
||||
## closes def write_create_new_wrapper():
|
||||
|
||||
if self.cpp_class.helper_class is None:
|
||||
write_create_new_wrapper()
|
||||
else:
|
||||
wrapper.before_call.write_code("if (typeid(*(%s)) == typeid(%s))\n{"
|
||||
% (value, self.cpp_class.helper_class.name))
|
||||
wrapper.before_call.indent()
|
||||
|
||||
wrapper.before_call.write_code(
|
||||
"%s = reinterpret_cast<%s*>(reinterpret_cast<%s*>(%s)->m_pyself);"
|
||||
% (py_name, self.cpp_class.pystruct,
|
||||
self.cpp_class.helper_class.name, value))
|
||||
|
||||
wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
|
||||
wrapper.before_call.write_code("Py_INCREF(%s);" % py_name)
|
||||
wrapper.before_call.unindent()
|
||||
wrapper.before_call.write_code("} else {")
|
||||
wrapper.before_call.indent()
|
||||
write_create_new_wrapper()
|
||||
wrapper.before_call.unindent()
|
||||
wrapper.before_call.write_code("}")
|
||||
|
||||
|
||||
|
||||
|
||||
def _add_ward(wrapper, custodian, ward):
|
||||
wards = wrapper.declarations.declare_variable(
|
||||
'PyObject*', 'wards')
|
||||
@@ -1165,6 +1287,7 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
|
||||
wrapper.after_call.write_code(
|
||||
"%s->%s();" % (value, self.cpp_class.incref_method))
|
||||
wrapper.after_call.write_code("%s->obj = %s;" % (py_name, value))
|
||||
## closes def write_create_new_wrapper():
|
||||
|
||||
if self.cpp_class.helper_class is None:
|
||||
write_create_new_wrapper()
|
||||
|
||||
Reference in new issue
Block a user