diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index b29a488..7807a7e 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -700,7 +700,7 @@ QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQtSlotInfo* info = o->m_ml; while (info) { - results << info->fullSignature(info->isInstanceDecorator()); + results << info->fullSignature(); info = info->nextInfo(); } } else if (object->ob_type == &PythonQtClassWrapper_Type) { @@ -708,7 +708,7 @@ QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQtSlotInfo* info = o->classInfo()->constructors(); while (info) { - results << info->fullSignature(false); + results << info->fullSignature(); info = info->nextInfo(); } } else { diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index 89c697a..409206b 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -537,7 +537,7 @@ QString PythonQtClassInfo::help() h += "Constructors:\n"; PythonQtSlotInfo* constr = constructors(); while (constr) { - h += constr->fullSignature(false) + "\n"; + h += constr->fullSignature() + "\n"; constr = constr->nextInfo(); } } @@ -557,7 +557,7 @@ QString PythonQtClassInfo::help() if (signa.startsWith("delete_")) continue; if (signa.startsWith("static_")) continue; PythonQtSlotInfo slot(m, i); - h += slot.fullSignature(false)+ "\n"; + h += slot.fullSignature()+ "\n"; } } } @@ -581,7 +581,7 @@ QString PythonQtClassInfo::help() QListIterator it(PythonQt::priv()->getDecoratorSlots(nameIt.next())); while (it.hasNext()) { PythonQtSlotInfo* slot = it.next(); - h += slot->fullSignature(slot->isInstanceDecorator()) + "\n"; + h += slot->fullSignature() + "\n"; } } diff --git a/src/PythonQtClassWrapper.cpp b/src/PythonQtClassWrapper.cpp index 15d4381..b563505 100644 --- a/src/PythonQtClassWrapper.cpp +++ b/src/PythonQtClassWrapper.cpp @@ -157,17 +157,26 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) } dict = PyDict_Copy(dict); - QStringList l = wrapper->classInfo()->memberList(true); + QStringList l = wrapper->classInfo()->memberList(false); foreach (QString name, l) { PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); - PyDict_SetItemString(dict, name.toLatin1().data(), o); - Py_DECREF(o); + if (o) { + PyDict_SetItemString(dict, name.toLatin1().data(), o); + Py_DECREF(o); + } else { + // it must have been a property or child, which we do not know as a class object... + } } if (wrapper->classInfo()->constructors()) { - PyDict_SetItemString(dict, "__init__", PyCFunction_New(&PythonQtClassWrapper_methods[0], obj)); + PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[0], obj); + PyDict_SetItemString(dict, "__init__", func); + Py_DECREF(func); + } + for (int i = 1;i<3;i++) { + PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj); + PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func); + Py_DECREF(func); } - PyDict_SetItemString(dict, PythonQtClassWrapper_methods[1].ml_name, PyCFunction_New(&PythonQtClassWrapper_methods[1], obj)); - PyDict_SetItemString(dict, PythonQtClassWrapper_methods[2].ml_name, PyCFunction_New(&PythonQtClassWrapper_methods[2], obj)); return dict; } @@ -176,7 +185,8 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) if (member._type == PythonQtMemberInfo::EnumValue) { return PyInt_FromLong(member._enumValue); } else - if (member._type == PythonQtMemberInfo::Slot && member._slot->isClassDecorator()) { + if (member._type == PythonQtMemberInfo::Slot) { + // we return all slots, even the instance slots, since they are callable as unbound slots with self argument return PythonQtSlotFunction_New(member._slot, obj, NULL); } } diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index bbccb90..ea795ae 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -252,7 +252,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) PyObject* dict = PyDict_New(); foreach (QString name, l) { PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data()); - PyDict_SetItemString(dict, name.toLatin1().data(), Py_None); + PyDict_SetItemString(dict, name.toLatin1().data(), o); Py_DECREF(o); } // Note: we do not put children into the dict, is would look confusing?! diff --git a/src/PythonQtMethodInfo.cpp b/src/PythonQtMethodInfo.cpp index 52c78af..5d987f1 100644 --- a/src/PythonQtMethodInfo.cpp +++ b/src/PythonQtMethodInfo.cpp @@ -228,8 +228,9 @@ void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QB //------------------------------------------------------------------------------------------------- -QString PythonQtSlotInfo::fullSignature(bool skipFirstArg) +QString PythonQtSlotInfo::fullSignature() { + bool skipFirstArg = isInstanceDecorator(); QString result = _meta.typeName(); QByteArray sig = slotName(); QList names = _meta.parameterNames(); diff --git a/src/PythonQtMethodInfo.h b/src/PythonQtMethodInfo.h index 412eee6..22107c0 100644 --- a/src/PythonQtMethodInfo.h +++ b/src/PythonQtMethodInfo.h @@ -156,7 +156,7 @@ public: QObject* decorator() { return _decorator; } //! get the full signature including return type - QString fullSignature(bool skipFirstArg); + QString fullSignature(); //! get the short slot name QByteArray slotName(); diff --git a/src/PythonQtSlot.cpp b/src/PythonQtSlot.cpp index ff374e5..ec296af 100644 --- a/src/PythonQtSlot.cpp +++ b/src/PythonQtSlot.cpp @@ -148,7 +148,7 @@ bool PythonQtCallSlot(QObject* objectToCall, PyObject* args, bool strict, Python } } } else { - QString e = QString("Called ") + info->fullSignature(skipFirst) + ", return type is ignored because it is unknown to PythonQt."; + QString e = QString("Called ") + info->fullSignature() + ", return type is ignored because it is unknown to PythonQt."; PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); result = NULL; } @@ -177,10 +177,40 @@ PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self; return PythonQtSlotFunction_CallImpl(self->_obj, info, args, kw, self->_wrappedPtr); } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { - return PythonQtSlotFunction_CallImpl(NULL, info, args, kw); - } else { - return NULL; + if (info->isClassDecorator()) { + return PythonQtSlotFunction_CallImpl(NULL, info, args, kw); + } else { + // otherwise, it is an unbound call and we have an instanceDecorator or normal slot... + PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self; + 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()->className())) { + PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg; + // strip the first argument... + PyObject* newargs = PyTuple_New(argc-1); + for (int i = 0;i_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(QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * /*kw*/, void* firstArg, void** directReturnValuePointer) @@ -196,7 +226,6 @@ PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* if (directReturnValuePointer) { *directReturnValuePointer = NULL; } - if (info->nextInfo()) { // overloaded slot call, try on all slots with strict conversion first bool strict = true; @@ -221,8 +250,7 @@ PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* 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) { - bool skipFirst = i->isInstanceDecorator(); - e += QString(i->fullSignature(skipFirst)) + "\n"; + e += QString(i->fullSignature()) + "\n"; i = i->nextInfo(); } PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); @@ -234,11 +262,11 @@ PyObject *PythonQtSlotFunction_CallImpl(QObject* objectToCall, PythonQtSlotInfo* PyErr_Clear(); ok = PythonQtCallSlot(objectToCall, args, false, info, firstArg, &r, directReturnValuePointer); if (!ok && !PyErr_Occurred()) { - QString e = QString("Called ") + info->fullSignature(skipFirst) + " with wrong arguments: " + PythonQtConv::PyObjGetString(args); + 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(skipFirst) + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args); + QString e = QString("Called ") + info->fullSignature() + " with wrong number of arguments: " + PythonQtConv::PyObjGetString(args); PyErr_SetString(PyExc_ValueError, e.toLatin1().data()); } } @@ -366,12 +394,20 @@ static PyMemberDef meth_members[] = { }; static PyObject * -meth_repr(PythonQtSlotFunctionObject *m) +meth_repr(PythonQtSlotFunctionObject *f) { - return PyString_FromFormat("", - m->m_ml->metaMethod()->signature(), - m->m_self->ob_type->tp_name, - m->m_self); + if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) { + PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self; + return PyString_FromFormat("", + f->m_ml->metaMethod()->signature(), + f->m_self->ob_type->tp_name, + f->m_self); + } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) { + PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self; + return PyString_FromFormat("", + f->m_ml->metaMethod()->signature(), + self->classInfo()->className()); + } } static int