Support C++ instance attributes through getter/setter methods (Bug #136993)
This commit is contained in:
1 parent
7fdd88415d
commit
5b7ae2645d
4 files changed
+44
-9
No files matched your search
@@ -114,6 +114,9 @@ def my_module_gen(out_file):
|
||||
SomeObject = CppClass('SomeObject', allow_subclassing=True)
|
||||
mod.add_class(SomeObject)
|
||||
|
||||
SomeObject.add_instance_attribute(ReturnValue.new('Foo'), 'foo',
|
||||
getter='get_foo_value',
|
||||
setter='set_foo_value')
|
||||
SomeObject.add_instance_attribute(ReturnValue.new('std::string'), 'm_prefix')
|
||||
SomeObject.add_static_attribute(ReturnValue.new('std::string'), 'staticData')
|
||||
|
||||
|
||||
@@ -536,6 +536,13 @@ class TestFoo(unittest.TestCase):
|
||||
prefix = t.get_prefix_with_foo_ptr(foo1)
|
||||
self.assertEqual(prefix, "123zbr456zbr")
|
||||
|
||||
def test_attribute_with_getset(self):
|
||||
obj = foo.SomeObject("")
|
||||
f1 = foo.Foo("hello")
|
||||
obj.foo = f1
|
||||
f2 = obj.foo
|
||||
self.assertEqual(f2.get_datum(), "hello")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -30,19 +30,24 @@ class CppInstanceAttributeGetter(PyGetter):
|
||||
'''
|
||||
A getter for a C++ instance attribute.
|
||||
'''
|
||||
def __init__(self, value_type, class_, attribute_name):
|
||||
def __init__(self, value_type, class_, attribute_name, getter=None):
|
||||
"""
|
||||
value_type -- a ReturnValue object handling the value type;
|
||||
class_ -- the class (CppClass object)
|
||||
attribute_name -- name of attribute
|
||||
getter -- None, or name of a method of the class used to get the value
|
||||
"""
|
||||
super(CppInstanceAttributeGetter, self).__init__(
|
||||
value_type, [], "return NULL;", "return NULL;", no_c_retval=True)
|
||||
self.class_ = class_
|
||||
self.attribute_name = attribute_name
|
||||
self.getter = getter
|
||||
self.c_function_name = "_wrap_%s__get_%s" % (self.class_.pystruct,
|
||||
self.attribute_name)
|
||||
value_type.value = "self->obj->%s" % self.attribute_name
|
||||
if self.getter is None:
|
||||
value_type.value = "self->obj->%s" % self.attribute_name
|
||||
else:
|
||||
value_type.value = "self->obj->%s()" % self.getter
|
||||
|
||||
def generate_call(self):
|
||||
"virtual method implementation; do not call"
|
||||
@@ -104,19 +109,20 @@ class CppInstanceAttributeSetter(PySetter):
|
||||
'''
|
||||
A setter for a C++ instance attribute.
|
||||
'''
|
||||
def __init__(self, value_type, class_, attribute_name):
|
||||
def __init__(self, value_type, class_, attribute_name, setter=None):
|
||||
"""
|
||||
value_type -- a ReturnValue object handling the value type;
|
||||
class_ -- the class (CppClass object)
|
||||
attribute_name -- name of attribute
|
||||
setter -- None, or name of a method of the class used to set the value
|
||||
"""
|
||||
super(CppInstanceAttributeSetter, self).__init__(
|
||||
value_type, [], "return -1;")
|
||||
self.class_ = class_
|
||||
self.attribute_name = attribute_name
|
||||
self.setter = setter
|
||||
self.c_function_name = "_wrap_%s__set_%s" % (self.class_.pystruct,
|
||||
self.attribute_name)
|
||||
value_type.value = "self->obj->%s" % self.attribute_name
|
||||
|
||||
def generate(self, code_sink):
|
||||
"""
|
||||
@@ -127,11 +133,26 @@ class CppInstanceAttributeSetter(PySetter):
|
||||
self.before_call.write_code(
|
||||
'py_retval = Py_BuildValue("(O)", value);')
|
||||
self.before_call.add_cleanup_code('Py_DECREF(py_retval);')
|
||||
|
||||
if self.setter is not None:
|
||||
## if we have a setter method, redirect the value to a temporary variable
|
||||
value_var = self.declarations.declare_variable(self.return_value.ctype, 'tmp_value')
|
||||
self.return_value.value = value_var
|
||||
else:
|
||||
## else the value is written directly to a C++ instance attribute
|
||||
self.return_value.value = "self->obj->%s" % self.attribute_name
|
||||
|
||||
self.return_value.convert_python_to_c(self)
|
||||
|
||||
parse_tuple_params = ['py_retval']
|
||||
parse_tuple_params.extend(self.parse_params.get_parameters())
|
||||
self.before_call.write_error_check('!PyArg_ParseTuple(%s)' %
|
||||
(', '.join(parse_tuple_params),))
|
||||
|
||||
if self.setter is not None:
|
||||
## if we have a setter method, now is the time to call it
|
||||
self.after_call.write_code("self->obj->%s(%s);" % (self.setter, value_var))
|
||||
|
||||
## cleanup and return
|
||||
self.after_call.write_cleanup()
|
||||
self.after_call.write_code('return 0;')
|
||||
|
||||
@@ -472,19 +472,23 @@ public:
|
||||
setter = CppStaticAttributeSetter(value_type, self, name)
|
||||
self.static_attributes.add_attribute(name, getter, setter)
|
||||
|
||||
def add_instance_attribute(self, value_type, name, is_const=False):
|
||||
def add_instance_attribute(self, value_type, name, is_const=False,
|
||||
getter=None, setter=None):
|
||||
"""
|
||||
value_type -- a ReturnValue object
|
||||
name -- attribute name (i.e. the name of the class member variable)
|
||||
is_const -- True if the attribute is const, i.e. cannot be modified
|
||||
getter -- None, or name of a method of this class used to get the value
|
||||
setter -- None, or name of a method of this class used to set the value
|
||||
"""
|
||||
assert isinstance(value_type, ReturnValue)
|
||||
getter = CppInstanceAttributeGetter(value_type, self, name)
|
||||
getter_wrapper = CppInstanceAttributeGetter(value_type, self, name, getter=getter)
|
||||
if is_const:
|
||||
setter = None
|
||||
setter_wrapper = None
|
||||
assert setter is None
|
||||
else:
|
||||
setter = CppInstanceAttributeSetter(value_type, self, name)
|
||||
self.instance_attributes.add_attribute(name, getter, setter)
|
||||
setter_wrapper = CppInstanceAttributeSetter(value_type, self, name, setter=setter)
|
||||
self.instance_attributes.add_attribute(name, getter_wrapper, setter_wrapper)
|
||||
|
||||
def generate_forward_declarations(self, code_sink):
|
||||
"""Generates forward declarations for the instance and type
|
||||
|
||||
Reference in new issue
Block a user