def generate_python_call(self): """code to call the python method""" if settings._get_deprecated_virtuals(): params = ['m_pyself', '(char *) "_%s"' % self.method_name] else: params = ['m_pyself', '(char *) "%s"' % self.method_name] build_params = self.build_params.get_parameters() if build_params[0][0] == '"': build_params[0] = '(char *) ' + build_params[0] params.extend(build_params) self.before_call.write_code('py_retval = PyObject_CallMethod(%s);' % (', '.join(params),)) self.before_call.write_error_check('py_retval == NULL', failure_cleanup='PyErr_Print();') self.before_call.add_cleanup_code('Py_DECREF(py_retval);')
def generate_call(self, class_=None): "virtual method implementation; do not call" #assert isinstance(class_, CppClass) if class_ is None: class_ = self._class if self.template_parameters: template_params = '< %s >' % ', '.join(self.template_parameters) else: template_params = '' if self.return_value.ctype == 'void': retval_assign = '' else: if self.return_value.REQUIRES_ASSIGNMENT_CONSTRUCTOR: retval_assign = '%s retval = ' % (self.return_value.ctype,) else: retval_assign = 'retval = ' if class_.helper_class is not None and self.is_virtual and not self.is_pure_virtual\ and not settings._get_deprecated_virtuals(): helper = self.before_call.declare_variable(type_="%s *" % class_.helper_class.name, name="helper_class", initializer=( "dynamic_cast<%s*> (self->obj)" % class_.helper_class.name)) else: helper = None if self.is_static: method = '%s::%s%s' % (class_.full_name, self.method_name, template_params) else: method = 'self->obj->%s%s' % (self.method_name, template_params) if self.throw: self.before_call.write_code('try\n{') self.before_call.indent() if self.is_static: self.before_call.write_code(retval_assign + ( '%s::%s%s(%s);' % (class_.full_name, self.method_name, template_params, ", ".join(self.call_params)))) else: if helper is None: self.before_call.write_code(retval_assign + ( 'self->obj->%s%s(%s);' % (self.method_name, template_params, ", ".join(self.call_params)))) else: self.before_call.write_code(retval_assign + ( '(%s == NULL)? (self->obj->%s%s(%s)) : (self->obj->%s::%s%s(%s));' % (helper, self.method_name, template_params, ", ".join(self.call_params), class_.full_name, self.method_name, template_params, ", ".join(self.call_params) ))) if self.throw: for exc in self.throw: self.before_call.unindent() self.before_call.write_code('} catch (%s const &exc) {' % exc.full_name) self.before_call.indent() self.before_call.write_cleanup() exc.write_convert_to_python(self.before_call, 'exc') self.before_call.write_code('return NULL;') self.before_call.unindent() self.before_call.write_code('}')
def generate(self, code_sink): """generates the proxy virtual method""" if self.method.is_const: decl_post_modifiers = ['const'] else: decl_post_modifiers = [] if self.method.throw: decl_post_modifiers.append("throw (%s)" % (', '.join([ex.full_name for ex in self.method.throw]),)) ## if the python subclass doesn't define a virtual method, ## just chain to parent class and don't do anything else call_params = ', '.join([param.name for param in self.parameters]) py_method = self.declarations.declare_variable('PyObject*', 'py_method') if settings._get_deprecated_virtuals(): self.before_call.write_code('%s = PyObject_GetAttrString(m_pyself, (char *) "_%s"); PyErr_Clear();' % (py_method, self.method_name)) else: self.before_call.write_code('%s = PyObject_GetAttrString(m_pyself, (char *) "%s"); PyErr_Clear();' % (py_method, self.method_name)) self.before_call.add_cleanup_code('Py_XDECREF(%s);' % py_method) self.before_call.write_code( r'if (%s == NULL || Py_TYPE(%s) == &PyCFunction_Type) {' % (py_method, py_method)) if self.return_value.ctype == 'void': if not (self.method.is_pure_virtual or self.method.visibility == 'private'): self.before_call.write_code(r' %s::%s(%s);' % (self.class_.full_name, self.method_name, call_params)) self.before_call.indent() self.before_call.write_cleanup() self.before_call.write_code('return;') self.before_call.unindent() else: if self.method.is_pure_virtual or self.method.visibility == 'private': from . import cppclass if isinstance(self.return_value, cppclass.CppClassReturnValue) \ and self.return_value.cpp_class.has_trivial_constructor: pass else: self.set_error_return(''' PyErr_Print(); Py_FatalError("Error detected, but parent virtual is pure virtual or private virtual, " "and return is a class without trival constructor");''') else: self.set_error_return("return %s::%s(%s);" % (self.class_.full_name, self.method_name, call_params)) self.before_call.indent() self.before_call.write_cleanup() self.before_call.write_code(self.error_return) self.before_call.unindent() self.before_call.write_code('}') ## Set "m_pyself->obj = this" around virtual method call invocation self_obj_before = self.declarations.declare_variable( '%s*' % self.class_.full_name, 'self_obj_before') self.before_call.write_code("%s = reinterpret_cast< %s* >(m_pyself)->obj;" % (self_obj_before, self.class_.pystruct)) if self.method.is_const: this_expression = ("const_cast< %s* >((const %s*) this)" % (self.class_.full_name, self.class_.full_name)) else: this_expression = "(%s*) this" % (self.class_.full_name) self.before_call.write_code("reinterpret_cast< %s* >(m_pyself)->obj = %s;" % (self.class_.pystruct, this_expression)) self.before_call.add_cleanup_code("reinterpret_cast< %s* >(m_pyself)->obj = %s;" % (self.class_.pystruct, self_obj_before)) super(CppVirtualMethodProxy, self).generate( code_sink, '::'.join((self._helper_class.name, self.method_name)), decl_modifiers=[], decl_post_modifiers=decl_post_modifiers)