##// END OF EJS Templates
Start Python 3.x Port...
Start Python 3.x Port The main python interpreter works, BUT: Many tests still fail, Qt integration is broken

File last commit:

r206:316b4928f53f
r206:316b4928f53f
Show More
PythonQtSlot.cpp
735 lines | 23.8 KiB | text/x-c | CppLexer
/*
*
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
* 28359 Bremen, Germany or:
*
* http://www.mevis.de
*
*/
//----------------------------------------------------------------------------------
/*!
// \file PythonQtSlot.cpp
// \author Florian Link
// \author Last changed by $Author: florian $
// \date 2006-05
*/
//----------------------------------------------------------------------------------
#include "PythonQt.h"
#include "PythonQtSlot.h"
#include "PythonQtInstanceWrapper.h"
#include "PythonQtClassInfo.h"
#include "PythonQtMisc.h"
#include "PythonQtConversion.h"
#include <iostream>
#include <exception>
#include <stdexcept>
#include <QByteArray>
#if PY_MAJOR_VERSION >= 3
#define PY3K
#endif
#define PYTHONQT_MAX_ARGS 32
bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
{
static unsigned int recursiveEntry = 0;
if (directReturnValuePointer) {
*directReturnValuePointer = NULL;
}
// store the current storage position, so that we can get back to this state after a slot is called
// (do this locally, so that we have all positions on the stack
PythonQtValueStoragePosition globalValueStoragePos;
PythonQtValueStoragePosition globalPtrStoragePos;
PythonQtValueStoragePosition globalVariantStoragePos;
PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);
recursiveEntry++;
// the arguments that are passed to qt_metacall
void* argList[PYTHONQT_MAX_ARGS];
PyObject* result = NULL;
int argc = info->parameterCount();
const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();
const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
// set return argument to NULL
argList[0] = NULL;
bool ok = true;
bool skipFirst = false;
if (info->isInstanceDecorator()) {
skipFirst = true;
// for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
void* arg1 = firstArgument;
if (!arg1) {
arg1 = objectToCall;
}
if (arg1) {
// upcast to correct parent class
arg1 = ((char*)arg1)+info->upcastingOffset();
}
argList[1] = &arg1;
if (ok) {
for (int i = 2; i<argc && ok; i++) {
const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
if (argList[i]==NULL) {
ok = false;
break;
}
}
}
} else {
for (int i = 1; i<argc && ok; i++) {
const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
if (argList[i]==NULL) {
ok = false;
break;
}
}
}
if (ok) {
// parameters are ok, now create the qt return value which is assigned to by metacall
if (returnValueParam.typeId != QMetaType::Void) {
// create empty default value for the return value
if (!directReturnValuePointer) {
// create empty default value for the return value
argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
if (argList[0]==NULL) {
// return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and
// pass its internal pointer
PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
if (info && info->pythonQtClassWrapper()) {
PyObject* emptyTuple = PyTuple_New(0);
// 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
if (result) {
argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
}
Py_DECREF(emptyTuple);
}
}
} else {
// we can use our pointer directly!
argList[0] = directReturnValuePointer;
}
}
PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
if (profilingCB) {
const char* className = NULL;
if (info->decorator()) {
className = info->decorator()->metaObject()->className();
} else {
className = objectToCall->metaObject()->className();
}
#if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
profilingCB(PythonQt::Enter, className, info->metaMethod()->methodSignature());
#else
profilingCB(PythonQt::Enter, className, info->metaMethod()->signature());
#endif
}
// invoke the slot via metacall
bool hadException = false;
QObject* obj = info->decorator()?info->decorator():objectToCall;
if (!obj) {
hadException = true;
PyErr_SetString(PyExc_RuntimeError, "Trying to call a slot on a deleted QObject!");
} else {
try {
obj->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
} catch (std::bad_alloc & e) {
hadException = true;
QByteArray what("std::bad_alloc: ");
what += e.what();
PyErr_SetString(PyExc_MemoryError, what.constData());
} catch (std::runtime_error & e) {
hadException = true;
QByteArray what("std::runtime_error: ");
what += e.what();
PyErr_SetString(PyExc_RuntimeError, what.constData());
} catch (std::logic_error & e) {
hadException = true;
QByteArray what("std::logic_error: ");
what += e.what();
PyErr_SetString(PyExc_RuntimeError, what.constData());
} catch (std::exception& e) {
hadException = true;
QByteArray what("std::exception: ");
what += e.what();
#ifdef PY3K
PyErr_SetString(PyExc_RuntimeError, what.constData());
#else
PyErr_SetString(PyExc_StandardError, what.constData());
#endif
}
}
if (profilingCB) {
profilingCB(PythonQt::Leave, NULL, NULL);
}
// handle the return value (which in most cases still needs to be converted to a Python object)
if (!hadException) {
if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
if (directReturnValuePointer) {
result = NULL;
} else {
// the resulting object maybe present already, because we created it above at 1)...
if (!result) {
result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
}
}
} else {
QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class.";
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
result = NULL;
}
} else {
result = NULL;
}
}
recursiveEntry--;
// reset the parameter storage position to the stored pos to "pop" the parameter stack
PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);
*pythonReturnValue = result;
// NOTE: it is important to only return here, otherwise the stack will not be popped!!!
return result || (directReturnValuePointer && *directReturnValuePointer);
}
//-----------------------------------------------------------------------------------
static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
{
PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, kw);
}
PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, PyObject *args, PyObject *kw)
{
if (PyObject_TypeCheck(m_self, &PythonQtInstanceWrapper_Type)) {
PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) m_self;
if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
return NULL;
} else {
return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
}
} else if (m_self->ob_type == &PythonQtClassWrapper_Type) {
PythonQtClassWrapper* type = (PythonQtClassWrapper*) m_self;
if (info->isClassDecorator()) {
return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
} else {
// otherwise, it is an unbound call and we have an instanceDecorator or normal slot...
Py_ssize_t argc = PyTuple_Size(args);
if (argc>0) {
PyObject* firstArg = PyTuple_GET_ITEM(args, 0);
if (PyObject_TypeCheck(firstArg, (PyTypeObject*)&PythonQtInstanceWrapper_Type)
&& ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
return NULL;
}
// strip the first argument...
PyObject* newargs = PyTuple_GetSlice(args, 1, argc);
PyObject* result = PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, newargs, kw, self->_wrappedPtr);
Py_DECREF(newargs);
return result;
} else {
// first arg is not of correct type!
QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument, got " + firstArg->ob_type->tp_name;
PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
return NULL;
}
} else {
// wrong number of args
QString error = "slot " + info->fullSignature() + " requires " + type->classInfo()->className() + " instance as first argument.";
PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
return NULL;
}
}
}
return NULL;
}
PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer)
{
int argc = args?PyTuple_Size(args):0;
#ifdef PYTHONQT_DEBUG
std::cout << "called " << info->metaMethod()->typeName() << " " << info->metaMethod()->signature() << std::endl;
#endif
PyObject* r = NULL;
bool ok = false;
if (directReturnValuePointer) {
*directReturnValuePointer = NULL;
}
if (info->nextInfo()) {
// overloaded slot call, try on all slots with strict conversion first
bool strict = true;
PythonQtSlotInfo* i = info;
while (i) {
bool skipFirst = i->isInstanceDecorator();
if (i->parameterCount()-1-(skipFirst?1:0) == argc) {
PyErr_Clear();
ok = PythonQtCallSlot(classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer);
if (PyErr_Occurred() || ok) break;
}
i = i->nextInfo();
if (!i) {
if (strict) {
// one more run without being strict
strict = false;
i = info;
}
}
}
if (!ok && !PyErr_Occurred()) {
QString e = QString("Could not find matching overload for given arguments:\n" + PythonQtConv::PyObjGetString(args) + "\n The following slots are available:\n");
PythonQtSlotInfo* i = info;
while (i) {
e += QString(i->fullSignature()) + "\n";
i = i->nextInfo();
}
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
}
} else {
// simple (non-overloaded) slot call
bool skipFirst = info->isInstanceDecorator();
if (info->parameterCount()-1-(skipFirst?1:0) == argc) {
PyErr_Clear();
ok = PythonQtCallSlot(classInfo, objectToCall, args, false, info, firstArg, &r, directReturnValuePointer);
if (!ok && !PyErr_Occurred()) {
QString e = QString("Called ") + info->fullSignature() + " with wrong arguments: " + PythonQtConv::PyObjGetString(args);
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
}
} else {
QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args);
PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
}
}
return r;
}
PyObject *
PythonQtSlotFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
{
PythonQtSlotFunctionObject *op;
op = pythonqtslot_free_list;
if (op != NULL) {
pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(op->m_self);
PyObject_INIT(op, &PythonQtSlotFunction_Type);
}
else {
op = PyObject_GC_New(PythonQtSlotFunctionObject, &PythonQtSlotFunction_Type);
if (op == NULL)
return NULL;
}
op->m_ml = ml;
Py_XINCREF(self);
op->m_self = self;
Py_XINCREF(module);
op->m_module = module;
PyObject_GC_Track(op);
return (PyObject *)op;
}
PythonQtSlotInfo*
PythonQtSlotFunction_GetSlotInfo(PyObject *op)
{
if (!PythonQtSlotFunction_Check(op)) {
PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", __FILE__, __LINE__);
return NULL;
}
return ((PythonQtSlotFunctionObject *)op) -> m_ml;
}
PyObject *
PythonQtSlotFunction_GetSelf(PyObject *op)
{
if (!PythonQtSlotFunction_Check(op)) {
PyErr_Format(PyExc_SystemError, "%s:%d: bad argument to internal function", __FILE__, __LINE__);
return NULL;
}
return ((PythonQtSlotFunctionObject *)op) -> m_self;
}
/* Methods (the standard built-in methods, that is) */
static void
meth_dealloc(PythonQtSlotFunctionObject *m)
{
PyObject_GC_UnTrack(m);
Py_XDECREF(m->m_self);
Py_XDECREF(m->m_module);
m->m_self = (PyObject *)pythonqtslot_free_list;
pythonqtslot_free_list = m;
}
static PyObject *
meth_get__doc__(PythonQtSlotFunctionObject * /*m*/, void * /*closure*/)
{
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
meth_get__name__(PythonQtSlotFunctionObject *m, void * /*closure*/)
{
#if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
#ifdef PY3K
return PyUnicode_FromString(m->m_ml->metaMethod()->methodSignature());
#else
return PyString_FromString(m->m_ml->metaMethod()->methodSignature());
#endif
#else
#ifdef PY3K
return PyUnicode_FromString(m->m_ml->metaMethod()->signature());
#else
return PyString_FromString(m->m_ml->metaMethod()->signature());
#endif
#endif
}
static int
meth_traverse(PythonQtSlotFunctionObject *m, visitproc visit, void *arg)
{
int err;
if (m->m_self != NULL) {
err = visit(m->m_self, arg);
if (err)
return err;
}
if (m->m_module != NULL) {
err = visit(m->m_module, arg);
if (err)
return err;
}
return 0;
}
static PyObject *
meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/)
{
PyObject *self;
#ifndef PY3K
if (PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"method.__self__ not accessible in restricted mode");
return NULL;
}
#endif
self = m->m_self;
if (self == NULL)
self = Py_None;
Py_INCREF(self);
return self;
}
static PyGetSetDef meth_getsets [] = {
{const_cast<char*>("__doc__"), (getter)meth_get__doc__, NULL, NULL},
{const_cast<char*>("__name__"), (getter)meth_get__name__, NULL, NULL},
{const_cast<char*>("__self__"), (getter)meth_get__self__, NULL, NULL},
{NULL, NULL, NULL,NULL},
};
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
#define PY_WRITE_RESTRICTED WRITE_RESTRICTED
#endif
#define OFF(x) offsetof(PythonQtSlotFunctionObject, x)
static PyMemberDef meth_members[] = {
{const_cast<char*>("__module__"), T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
{NULL}
};
static PyObject *PythonQtSlotFunction_parameterTypes(PythonQtSlotFunctionObject* type)
{
return PythonQtMemberFunction_parameterTypes(type->m_ml);
}
static PyObject *PythonQtSlotFunction_parameterNames(PythonQtSlotFunctionObject* type)
{
return PythonQtMemberFunction_parameterNames(type->m_ml);
}
static PyObject *PythonQtSlotFunction_typeName(PythonQtSlotFunctionObject* type)
{
return PythonQtMemberFunction_typeName(type->m_ml);
}
PyObject *PythonQtMemberFunction_parameterTypes(PythonQtSlotInfo* theInfo)
{
PythonQtSlotInfo* info = theInfo;
int count = 0;
while (info) {
info = info->nextInfo();
count++;
}
info = theInfo;
PyObject* result = PyTuple_New(count);
for (int j = 0;j<count;j++) {
QList<QByteArray> types = info->metaMethod()->parameterTypes();
PyObject* tuple = PyTuple_New(types.count());
for (int i = 0; i<types.count();i++) {
#ifdef PY3K
PyTuple_SET_ITEM(tuple, i, PyUnicode_FromString(types.at(i).constData()));
#else
PyTuple_SET_ITEM(tuple, i, PyString_FromString(types.at(i).constData()));
#endif
}
info = info->nextInfo();
PyTuple_SET_ITEM(result, j, tuple);
}
return result;
}
PyObject *PythonQtMemberFunction_parameterNames(PythonQtSlotInfo* theInfo)
{
PythonQtSlotInfo* info = theInfo;
int count = 0;
while (info) {
info = info->nextInfo();
count++;
}
info = theInfo;
PyObject* result = PyTuple_New(count);
for (int j = 0;j<count;j++) {
QList<QByteArray> names = info->metaMethod()->parameterNames();
PyObject* tuple = PyTuple_New(names.count());
for (int i = 0; i<names.count();i++) {
#ifdef PY3K
PyTuple_SET_ITEM(tuple, i, PyUnicode_FromString(names.at(i).constData()));
#else
PyTuple_SET_ITEM(tuple, i, PyString_FromString(names.at(i).constData()));
#endif
}
info = info->nextInfo();
PyTuple_SET_ITEM(result, j, tuple);
}
return result;
}
PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo)
{
PythonQtSlotInfo* info = theInfo;
int count = 0;
while (info) {
info = info->nextInfo();
count++;
}
info = theInfo;
PyObject* result = PyTuple_New(count);
for (int j = 0;j<count;j++) {
QByteArray name = info->metaMethod()->typeName();
#ifdef PY3K
PyTuple_SET_ITEM(result, j, PyUnicode_FromString(name.constData()));
#else
PyTuple_SET_ITEM(result, j, PyString_FromString(name.constData()));
#endif
info = info->nextInfo();
}
return result;
}
static PyMethodDef meth_methods[] = {
{"parameterTypes", (PyCFunction)PythonQtSlotFunction_parameterTypes, METH_NOARGS,
"Returns a tuple of tuples of the C++ parameter types for all overloads of the slot"
},
{"parameterNames", (PyCFunction)PythonQtSlotFunction_parameterNames, METH_NOARGS,
"Returns a tuple of tuples of the C++ parameter type names (if available), for all overloads of the slot"
},
{"typeName", (PyCFunction)PythonQtSlotFunction_typeName, METH_NOARGS,
"Returns a tuple of the C++ return value types of each slot overload"
},
{NULL, NULL, 0 , NULL} /* Sentinel */
};
static PyObject *
meth_repr(PythonQtSlotFunctionObject *f)
{
if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
#ifdef PY3K
return PyUnicode_FromFormat("<unbound qt slot %s of %s type>",
#else
return PyString_FromFormat("<unbound qt slot %s of %s type>",
#endif
f->m_ml->slotName().data(),
self->classInfo()->className());
} else {
#ifdef PY3K
return PyUnicode_FromFormat("<qt slot %s of %s instance at %p",
#else
return PyString_FromFormat("<qt slot %s of %s instance at %p>",
#endif
f->m_ml->slotName().data(),
f->m_self->ob_type->tp_name,
f->m_self);
}
}
static int
meth_compare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b)
{
if (a->m_self != b->m_self)
return (a->m_self < b->m_self) ? -1 : 1;
if (a->m_ml == b->m_ml)
return 0;
#if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
if (strcmp(a->m_ml->metaMethod()->methodSignature(), b->m_ml->metaMethod()->methodSignature()) < 0)
#else
if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
#endif
return -1;
else
return 1;
}
static long
meth_hash(PythonQtSlotFunctionObject *a)
{
long x,y;
if (a->m_self == NULL)
x = 0;
else {
x = PyObject_Hash(a->m_self);
if (x == -1)
return -1;
}
y = _Py_HashPointer((void*)(a->m_ml));
if (y == -1)
return -1;
x ^= y;
if (x == -1)
x = -2;
return x;
}
// for python 3.x
static PyObject*
meth_richcompare(PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b, int op)
{
int x = meth_compare(a, b);
bool r;
if (op == Py_LT)
r = x < 0;
else if (op == Py_LE)
r = x < 1;
else if (op == Py_EQ)
r = x == 0;
else if (op == Py_NE)
r = x != 0;
else if (op == Py_GE)
r = x > -1;
else if (op == Py_GT)
r = x > 0;
if (r)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
PyTypeObject PythonQtSlotFunction_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"builtin_qt_slot",
sizeof(PythonQtSlotFunctionObject),
0,
(destructor)meth_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
#ifdef PY3K
0,
#else
(cmpfunc)meth_compare, /* tp_compare */
#endif
(reprfunc)meth_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)meth_hash, /* tp_hash */
PythonQtSlotFunction_Call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */
(traverseproc)meth_traverse, /* tp_traverse */
0, /* tp_clear */
(richcmpfunc)meth_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
meth_methods, /* tp_methods */
meth_members, /* tp_members */
meth_getsets, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};
/* Clear out the free list */
void
PythonQtSlotFunction_Fini(void)
{
while (pythonqtslot_free_list) {
PythonQtSlotFunctionObject *v = pythonqtslot_free_list;
pythonqtslot_free_list = (PythonQtSlotFunctionObject *)(v->m_self);
PyObject_GC_Del(v);
}
}