##// END OF EJS Templates
Updated from current MeVisLab development...
florianlink -
r173:7f1e2590af31
parent child
Show More
@@ -0,0 +1,350
1 /*
2 *
3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
28 *
29 * http://www.mevis.de
30 *
31 */
32
33 //----------------------------------------------------------------------------------
34 /*!
35 // \file PythonQtSignal.cpp
36 // \author Florian Link
37 // \author Last changed by $Author: florian $
38 // \date 2012-02
39 */
40 //----------------------------------------------------------------------------------
41
42 #include "PythonQt.h"
43 #include "PythonQtSignal.h"
44 #include "PythonQtInstanceWrapper.h"
45 #include "PythonQtClassInfo.h"
46 #include "PythonQtMisc.h"
47 #include "PythonQtConversion.h"
48 #include "PythonQtSlot.h"
49
50 #include <iostream>
51
52 #include <exception>
53 #include <stdexcept>
54
55 #include <QByteArray>
56
57 //-----------------------------------------------------------------------------------
58
59 static PythonQtSignalFunctionObject *PythonQtSignal_free_list = NULL;
60
61 PyObject *PythonQtSignalFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
62 {
63 PythonQtSignalFunctionObject* f = (PythonQtSignalFunctionObject*)func;
64 return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, kw);
65 }
66
67 PyObject *
68 PythonQtSignalFunction_New(PythonQtSlotInfo *ml, PyObject *self, PyObject *module)
69 {
70 PythonQtSignalFunctionObject *op;
71 op = PythonQtSignal_free_list;
72 if (op != NULL) {
73 PythonQtSignal_free_list = (PythonQtSignalFunctionObject *)(op->m_self);
74 PyObject_INIT(op, &PythonQtSignalFunction_Type);
75 }
76 else {
77 op = PyObject_GC_New(PythonQtSignalFunctionObject, &PythonQtSignalFunction_Type);
78 if (op == NULL)
79 return NULL;
80 }
81 op->m_ml = ml;
82 Py_XINCREF(self);
83 op->m_self = self;
84 Py_XINCREF(module);
85 op->m_module = module;
86 PyObject_GC_Track(op);
87 return (PyObject *)op;
88 }
89
90 /* Methods (the standard built-in methods, that is) */
91
92 static void
93 meth_dealloc(PythonQtSignalFunctionObject *m)
94 {
95 PyObject_GC_UnTrack(m);
96 Py_XDECREF(m->m_self);
97 Py_XDECREF(m->m_module);
98 m->m_self = (PyObject *)PythonQtSignal_free_list;
99 PythonQtSignal_free_list = m;
100 }
101
102 static PyObject *
103 meth_get__doc__(PythonQtSignalFunctionObject * /*m*/, void * /*closure*/)
104 {
105 Py_INCREF(Py_None);
106 return Py_None;
107 }
108
109 static PyObject *
110 meth_get__name__(PythonQtSignalFunctionObject *m, void * /*closure*/)
111 {
112 return PyString_FromString(m->m_ml->metaMethod()->signature());
113 }
114
115 static int
116 meth_traverse(PythonQtSignalFunctionObject *m, visitproc visit, void *arg)
117 {
118 int err;
119 if (m->m_self != NULL) {
120 err = visit(m->m_self, arg);
121 if (err)
122 return err;
123 }
124 if (m->m_module != NULL) {
125 err = visit(m->m_module, arg);
126 if (err)
127 return err;
128 }
129 return 0;
130 }
131
132 static PyObject *
133 meth_get__self__(PythonQtSignalFunctionObject *m, void * /*closure*/)
134 {
135 PyObject *self;
136 if (PyEval_GetRestricted()) {
137 PyErr_SetString(PyExc_RuntimeError,
138 "method.__self__ not accessible in restricted mode");
139 return NULL;
140 }
141 self = m->m_self;
142 if (self == NULL)
143 self = Py_None;
144 Py_INCREF(self);
145 return self;
146 }
147
148 static PyGetSetDef meth_getsets [] = {
149 {const_cast<char*>("__doc__"), (getter)meth_get__doc__, NULL, NULL},
150 {const_cast<char*>("__name__"), (getter)meth_get__name__, NULL, NULL},
151 {const_cast<char*>("__self__"), (getter)meth_get__self__, NULL, NULL},
152 {NULL, NULL, NULL,NULL},
153 };
154
155 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 6
156 #define PY_WRITE_RESTRICTED WRITE_RESTRICTED
157 #endif
158
159 #define OFF(x) offsetof(PythonQtSignalFunctionObject, x)
160
161 static PyMemberDef meth_members[] = {
162 {const_cast<char*>("__module__"), T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
163 {NULL}
164 };
165
166 static PyObject *PythonQtSignalFunction_parameterTypes(PythonQtSignalFunctionObject* type)
167 {
168 return PythonQtMemberFunction_parameterTypes(type->m_ml);
169 }
170
171 static PyObject *PythonQtSignalFunction_parameterNames(PythonQtSignalFunctionObject* type)
172 {
173 return PythonQtMemberFunction_parameterNames(type->m_ml);
174 }
175
176 static PyObject *PythonQtSignalFunction_typeName(PythonQtSignalFunctionObject* type)
177 {
178 return PythonQtMemberFunction_typeName(type->m_ml);
179 }
180
181 static PyObject *PythonQtSignalFunction_connect(PythonQtSignalFunctionObject* type, PyObject *args)
182 {
183 if (PyObject_TypeCheck(type->m_self, &PythonQtInstanceWrapper_Type)) {
184 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) type->m_self;
185 if (self->_obj) {
186 Py_ssize_t argc = PyTuple_Size(args);
187 if (argc==1) {
188 // connect with Python callable
189 PyObject* callable = PyTuple_GET_ITEM(args, 0);
190 bool result = PythonQt::self()->addSignalHandler(self->_obj, QByteArray("2") + type->m_ml->metaMethod()->signature(), callable);
191 return PythonQtConv::GetPyBool(result);
192 } else {
193 PyErr_SetString(PyExc_ValueError, "Called connect with wrong number of arguments");
194 }
195 }
196 }
197 return NULL;
198 }
199
200 static PyObject *PythonQtSignalFunction_disconnect(PythonQtSignalFunctionObject* type, PyObject *args)
201 {
202 if (PyObject_TypeCheck(type->m_self, &PythonQtInstanceWrapper_Type)) {
203 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) type->m_self;
204 if (self->_obj) {
205 Py_ssize_t argc = PyTuple_Size(args);
206 QByteArray signal = QByteArray("2") + type->m_ml->metaMethod()->signature();
207 if (argc==1) {
208 // disconnect with Python callable
209 PyObject* callable = PyTuple_GET_ITEM(args, 0);
210 bool result = PythonQt::self()->removeSignalHandler(self->_obj, signal, callable);
211 return PythonQtConv::GetPyBool(result);
212 } else if (argc==0) {
213 bool result = PythonQt::self()->removeSignalHandler(self->_obj, signal, NULL);
214 result |= QObject::disconnect(self->_obj, signal, NULL, NULL);
215 return PythonQtConv::GetPyBool(result);
216 } else {
217 PyErr_SetString(PyExc_ValueError, "Called disconnect with wrong number of arguments");
218 }
219 }
220 }
221 return NULL;
222 }
223
224 static PyObject *PythonQtSignalFunction_emit(PythonQtSignalFunctionObject* func, PyObject *args)
225 {
226 PythonQtSignalFunctionObject* f = (PythonQtSignalFunctionObject*)func;
227 return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, NULL);
228 }
229
230 static PyMethodDef meth_methods[] = {
231 {"parameterTypes", (PyCFunction)PythonQtSignalFunction_parameterTypes, METH_NOARGS,
232 "Returns a tuple of tuples of the C++ parameter types for all overloads of the signal"
233 },
234 {"parameterNames", (PyCFunction)PythonQtSignalFunction_parameterNames, METH_NOARGS,
235 "Returns a tuple of tuples of the C++ parameter type names (if available), for all overloads of the signal"
236 },
237 {"typeName", (PyCFunction)PythonQtSignalFunction_typeName, METH_NOARGS,
238 "Returns a tuple of the C++ return value types of each signal overload"
239 },
240 {"connect", (PyCFunction)PythonQtSignalFunction_connect, METH_VARARGS,
241 "Connects the signal to the Python callable"
242 },
243 {"disconnect", (PyCFunction)PythonQtSignalFunction_disconnect, METH_VARARGS,
244 "Disconnects the signal from the given Python callable or disconnects all if no argument is passed."
245 },
246 {"emit", (PyCFunction)PythonQtSignalFunction_emit, METH_VARARGS,
247 "Emits the signal with given arguments"
248 },
249 {NULL, NULL, 0 , NULL} /* Sentinel */
250 };
251
252 static PyObject *
253 meth_repr(PythonQtSignalFunctionObject *f)
254 {
255 if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
256 PythonQtClassWrapper* self = (PythonQtClassWrapper*) f->m_self;
257 return PyString_FromFormat("<unbound qt signal %s of %s type>",
258 f->m_ml->slotName().data(),
259 self->classInfo()->className());
260 } else {
261 return PyString_FromFormat("<qt signal %s of %s instance at %p>",
262 f->m_ml->slotName().data(),
263 f->m_self->ob_type->tp_name,
264 f->m_self);
265 }
266 }
267
268 static int
269 meth_compare(PythonQtSignalFunctionObject *a, PythonQtSignalFunctionObject *b)
270 {
271 if (a->m_self != b->m_self)
272 return (a->m_self < b->m_self) ? -1 : 1;
273 if (a->m_ml == b->m_ml)
274 return 0;
275 if (strcmp(a->m_ml->metaMethod()->signature(), b->m_ml->metaMethod()->signature()) < 0)
276 return -1;
277 else
278 return 1;
279 }
280
281 static long
282 meth_hash(PythonQtSignalFunctionObject *a)
283 {
284 long x,y;
285 if (a->m_self == NULL)
286 x = 0;
287 else {
288 x = PyObject_Hash(a->m_self);
289 if (x == -1)
290 return -1;
291 }
292 y = _Py_HashPointer((void*)(a->m_ml));
293 if (y == -1)
294 return -1;
295 x ^= y;
296 if (x == -1)
297 x = -2;
298 return x;
299 }
300
301
302 PyTypeObject PythonQtSignalFunction_Type = {
303 PyObject_HEAD_INIT(&PyType_Type)
304 0,
305 "builtin_qt_signal",
306 sizeof(PythonQtSignalFunctionObject),
307 0,
308 (destructor)meth_dealloc, /* tp_dealloc */
309 0, /* tp_print */
310 0, /* tp_getattr */
311 0, /* tp_setattr */
312 (cmpfunc)meth_compare, /* tp_compare */
313 (reprfunc)meth_repr, /* tp_repr */
314 0, /* tp_as_number */
315 0, /* tp_as_sequence */
316 // TODO: implement tp_as_mapping to support overload resolution on the signal
317 0, /* tp_as_mapping */
318 (hashfunc)meth_hash, /* tp_hash */
319 PythonQtSignalFunction_Call, /* tp_call */
320 0, /* tp_str */
321 PyObject_GenericGetAttr, /* tp_getattro */
322 0, /* tp_setattro */
323 0, /* tp_as_buffer */
324 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
325 0, /* tp_doc */
326 (traverseproc)meth_traverse, /* tp_traverse */
327 0, /* tp_clear */
328 0, /* tp_richcompare */
329 0, /* tp_weaklistoffset */
330 0, /* tp_iter */
331 0, /* tp_iternext */
332 meth_methods, /* tp_methods */
333 meth_members, /* tp_members */
334 meth_getsets, /* tp_getset */
335 0, /* tp_base */
336 0, /* tp_dict */
337 };
338
339 /* Clear out the free list */
340
341 void
342 PythonQtSignalFunction_Fini(void)
343 {
344 while (PythonQtSignal_free_list) {
345 PythonQtSignalFunctionObject *v = PythonQtSignal_free_list;
346 PythonQtSignal_free_list = (PythonQtSignalFunctionObject *)(v->m_self);
347 PyObject_GC_Del(v);
348 }
349 }
350
@@ -0,0 +1,68
1 #ifndef _PythonQtSignal_H
2 #define _PythonQtSignal_H
3
4 /*
5 *
6 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * Further, this software is distributed without any warranty that it is
19 * free of the rightful claim of any third person regarding infringement
20 * or the like. Any license provided herein, whether implied or
21 * otherwise, applies only to this software file. Patent licenses, if
22 * any, provided herein do not apply to combinations of this program with
23 * other software, or any other product whatsoever.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
30 * 28359 Bremen, Germany or:
31 *
32 * http://www.mevis.de
33 *
34 */
35
36 //----------------------------------------------------------------------------------
37 /*!
38 // \file PythonQtSignal.h
39 // \author Florian Link
40 // \author Last changed by $Author: florian $
41 // \date 2006-05
42 */
43 //----------------------------------------------------------------------------------
44
45 #include "PythonQtPythonInclude.h"
46
47 #include "PythonQtSystem.h"
48 #include "structmember.h"
49
50 class PythonQtSlotInfo;
51
52 extern PYTHONQT_EXPORT PyTypeObject PythonQtSignalFunction_Type;
53
54 #define PythonQtSignalFunction_Check(op) ((op)->ob_type == &PythonQtSignalFunction_Type)
55
56 PyObject* PythonQtSignalFunction_New(PythonQtSlotInfo *, PyObject *,
57 PyObject *);
58
59 //! defines a python object that stores a Qt signal info
60 typedef struct {
61 PyObject_HEAD
62 PythonQtSlotInfo *m_ml; /* Description of the C function to call */
63 PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
64 PyObject *m_module; /* The __module__ attribute, can be anything */
65 } PythonQtSignalFunctionObject;
66
67
68 #endif
@@ -43,6 +43,7
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 #include "PythonQtSignal.h"
46 47 #include "PythonQtSignalReceiver.h"
47 48 #include "PythonQtConversion.h"
48 49 #include "PythonQtStdIn.h"
@@ -167,6 +168,11 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
167 168 }
168 169 Py_INCREF(&PythonQtSlotFunction_Type);
169 170
171 if (PyType_Ready(&PythonQtSignalFunction_Type) < 0) {
172 std::cerr << "could not initialize PythonQtSignalFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
173 }
174 Py_INCREF(&PythonQtSignalFunction_Type);
175
170 176 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
171 177 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
172 178 // add our own python object types for classes
@@ -412,6 +418,20 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
412 418 if (info) {
413 419 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
414 420 ptr = info->castDownIfPossible(ptr, &info);
421
422 // if downcasting found out that the object is a QObject,
423 // handle it like one:
424 if (info && info->isQObject()) {
425 QObject* qptr = (QObject*)ptr;
426 // if the object is a derived object, we want to switch the class info to the one of the derived class:
427 if (name!=(qptr->metaObject()->className())) {
428 registerClass(qptr->metaObject());
429 info = _knownClassInfos.value(qptr->metaObject()->className());
430 }
431 wrap = createNewPythonQtInstanceWrapper(qptr, info);
432 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
433 return (PyObject*)wrap;
434 }
415 435 }
416 436
417 437 if (!info || info->pythonQtClassWrapper()==NULL) {
@@ -602,7 +622,6 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
602 622 QStringList l = name.split('.');
603 623 PythonQtObjectPtr p = module;
604 624 PythonQtObjectPtr prev;
605 QString s;
606 625 QByteArray b;
607 626 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
608 627 prev = p;
@@ -784,97 +803,171 QStringList PythonQt::introspection(PyObject* module, const QString& objectname,
784 803 }
785 804
786 805 if (object) {
787 if (type == CallOverloads) {
788 if (PythonQtSlotFunction_Check(object)) {
789 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
790 PythonQtSlotInfo* info = o->m_ml;
791
792 while (info) {
793 results << info->fullSignature();
794 info = info->nextInfo();
795 }
796 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
797 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
798 PythonQtSlotInfo* info = o->classInfo()->constructors();
806 results = introspectObject(object, type);
807 }
808
809 return results;
810 }
799 811
800 while (info) {
801 results << info->fullSignature();
802 info = info->nextInfo();
803 }
812 QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
813 {
814 QStringList results;
815
816 if (type == CallOverloads) {
817 if (PythonQtSlotFunction_Check(object)) {
818 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
819 PythonQtSlotInfo* info = o->m_ml;
820
821 while (info) {
822 results << info->fullSignature();
823 info = info->nextInfo();
824 }
825 } else if (PythonQtSignalFunction_Check(object)) {
826 PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
827 PythonQtSlotInfo* info = o->m_ml;
828
829 while (info) {
830 results << info->fullSignature();
831 info = info->nextInfo();
832 }
833 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
834 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
835 PythonQtSlotInfo* info = o->classInfo()->constructors();
836
837 while (info) {
838 results << info->fullSignature();
839 info = info->nextInfo();
840 }
841 } else {
842 QString signature = _p->getSignature(object);
843 if (!signature.isEmpty()) {
844 results << signature;
804 845 } else {
805 //TODO: use pydoc!
806 846 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
807 847 if (doc) {
808 848 results << PyString_AsString(doc);
809 849 Py_DECREF(doc);
810 850 }
811 851 }
852 }
853 } else {
854 PyObject* keys = NULL;
855 bool isDict = false;
856 if (PyDict_Check(object)) {
857 keys = PyDict_Keys(object);
858 isDict = true;
812 859 } else {
813 PyObject* keys = NULL;
814 bool isDict = false;
815 if (PyDict_Check(object)) {
816 keys = PyDict_Keys(object);
817 isDict = true;
818 } else {
819 keys = PyObject_Dir(object);
820 }
821 if (keys) {
822 int count = PyList_Size(keys);
823 PyObject* key;
824 PyObject* value;
825 QString keystr;
826 for (int i = 0;i<count;i++) {
827 key = PyList_GetItem(keys,i);
828 if (isDict) {
829 value = PyDict_GetItem(object, key);
830 Py_INCREF(value);
831 } else {
832 value = PyObject_GetAttr(object, key);
833 }
834 if (!value) continue;
835 keystr = PyString_AsString(key);
836 static const QString underscoreStr("__tmp");
837 if (!keystr.startsWith(underscoreStr)) {
838 switch (type) {
839 case Anything:
860 keys = PyObject_Dir(object);
861 }
862 if (keys) {
863 int count = PyList_Size(keys);
864 PyObject* key;
865 PyObject* value;
866 QString keystr;
867 for (int i = 0;i<count;i++) {
868 key = PyList_GetItem(keys,i);
869 if (isDict) {
870 value = PyDict_GetItem(object, key);
871 Py_INCREF(value);
872 } else {
873 value = PyObject_GetAttr(object, key);
874 }
875 if (!value) continue;
876 keystr = PyString_AsString(key);
877 static const QString underscoreStr("__tmp");
878 if (!keystr.startsWith(underscoreStr)) {
879 switch (type) {
880 case Anything:
881 results << keystr;
882 break;
883 case Class:
884 if (value->ob_type == &PyClass_Type || value->ob_type == &PyType_Type) {
885 results << keystr;
886 }
887 break;
888 case Variable:
889 if (value->ob_type != &PyClass_Type
890 && value->ob_type != &PyCFunction_Type
891 && value->ob_type != &PyFunction_Type
892 && value->ob_type != &PyMethod_Type
893 && value->ob_type != &PyModule_Type
894 && value->ob_type != &PyType_Type
895 && value->ob_type != &PythonQtSlotFunction_Type
896 ) {
897 results << keystr;
898 }
899 break;
900 case Function:
901 if (value->ob_type == &PyCFunction_Type ||
902 value->ob_type == &PyFunction_Type ||
903 value->ob_type == &PyMethod_Type ||
904 value->ob_type == &PythonQtSlotFunction_Type
905 ) {
840 906 results << keystr;
841 break;
842 case Class:
843 if (value->ob_type == &PyClass_Type) {
844 results << keystr;
845 }
846 break;
847 case Variable:
848 if (value->ob_type != &PyClass_Type
849 && value->ob_type != &PyCFunction_Type
850 && value->ob_type != &PyFunction_Type
851 && value->ob_type != &PyModule_Type
852 ) {
853 results << keystr;
854 }
855 break;
856 case Function:
857 if (value->ob_type == &PyFunction_Type ||
858 value->ob_type == &PyMethod_Type
859 ) {
860 results << keystr;
861 }
862 break;
863 case Module:
864 if (value->ob_type == &PyModule_Type) {
865 results << keystr;
866 }
867 break;
868 default:
869 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
870 907 }
908 break;
909 case Module:
910 if (value->ob_type == &PyModule_Type) {
911 results << keystr;
912 }
913 break;
914 default:
915 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
871 916 }
872 Py_DECREF(value);
873 917 }
874 Py_DECREF(keys);
918 Py_DECREF(value);
875 919 }
920 Py_DECREF(keys);
921 }
922 }
923 return results;
924 }
925
926 PyObject* PythonQt::getObjectByType(const QString& typeName)
927 {
928 PythonQtObjectPtr sys;
929 sys.setNewRef(PyImport_ImportModule("sys"));
930 PythonQtObjectPtr modules = lookupObject(sys, "modules");
931 Q_ASSERT(PyDict_Check(modules));
932
933 QStringList tmp = typeName.split(".");
934 QString simpleTypeName = tmp.takeLast();
935 QString moduleName = tmp.join(".");
936
937 PyObject* object = NULL;
938 PyObject* moduleObject = PyDict_GetItemString(modules, moduleName.toLatin1().constData());
939 if (moduleObject) {
940 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
941 }
942
943 if (!object) {
944 moduleObject = PyDict_GetItemString(modules, "__builtin__");
945 if (moduleObject) {
946 object = PyObject_GetAttrString(moduleObject, simpleTypeName.toLatin1().constData());
947 }
948 }
949
950 return object;
951 }
952
953 QStringList PythonQt::introspectType(const QString& typeName, ObjectType type)
954 {
955 QStringList results;
956 PyObject* object = getObjectByType(typeName);
957 if (!object) {
958 // the last item may be a member, split it away and try again
959 QStringList tmp = typeName.split(".");
960 QString memberName = tmp.takeLast();
961 QString typeName = tmp.takeLast();
962 PyObject* typeObject = getObjectByType(typeName);
963 if (typeObject) {
964 object = PyObject_GetAttrString(typeObject, memberName.toLatin1().constData());
876 965 }
877 966 }
967 if (object) {
968 results = introspectObject(object, type);
969 Py_DECREF(object);
970 }
878 971 return results;
879 972 }
880 973
@@ -1190,6 +1283,107 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ
1190 1283 }
1191 1284 }
1192 1285
1286 QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name)
1287 {
1288 QStringList tmp = name.split(".");
1289 QString methodName = tmp.takeLast();
1290 QString variableName = tmp.join(".");
1291 // TODO: the variableName may be a type name, this needs to be handled differently,
1292 // because it is not necessarily known in the module context
1293 PythonQtObjectPtr variableObject = lookupObject(module, variableName);
1294 if (variableObject.isNull()) {
1295 return "";
1296 }
1297
1298 return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
1299 }
1300
1301 QString PythonQt::getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName)
1302 {
1303 PythonQtObjectPtr typeObject = getObjectByType(typeName);
1304 if (typeObject.isNull()) {
1305 return "";
1306 }
1307 return getReturnTypeOfWrappedMethodHelper(typeObject, methodName, typeName + "." + methodName);
1308 }
1309
1310 QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context)
1311 {
1312 PythonQtObjectPtr methodObject;
1313 if (PyDict_Check(variableObject)) {
1314 methodObject = PyDict_GetItemString(variableObject, methodName.toLatin1().constData());
1315 } else {
1316 methodObject.setNewRef(PyObject_GetAttrString(variableObject, methodName.toLatin1().constData()));
1317 }
1318 if (methodObject.isNull()) {
1319 return "";
1320 }
1321
1322 QString type;
1323
1324 if (methodObject->ob_type == &PyClass_Type || methodObject->ob_type == &PyType_Type) {
1325 // the methodObject is not a method, but the name of a type/class. This means
1326 // a constructor is called. Return the context.
1327 type = context;
1328 } else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1329 QString className;
1330
1331 if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1332 // the type name of wrapped instance is the class name
1333 className = variableObject->ob_type->tp_name;
1334 } else {
1335 PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1336 if (classNameObject) {
1337 Q_ASSERT(PyString_Check(classNameObject));
1338 className = PyString_AsString(classNameObject);
1339 Py_DECREF(classNameObject);
1340 }
1341 }
1342
1343 if (!className.isEmpty()) {
1344 PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1345 if (info) {
1346 PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1347 if (slotInfo) {
1348 if (slotInfo->metaMethod()) {
1349 type = slotInfo->metaMethod()->typeName();
1350 if (!type.isEmpty()) {
1351 QChar c = type.at(type.length()-1);
1352 while (c == '*' || c == '&') {
1353 type.truncate(type.length()-1);
1354 if (!type.isEmpty()) {
1355 c = type.at(type.length()-1);
1356 } else {
1357 break;
1358 }
1359 }
1360 // split away template arguments
1361 type = type.split("<").first();
1362 // split away const
1363 type = type.split(" ").last().trimmed();
1364
1365 // if the type is a known class info, then create the full type name, i.e. include the
1366 // module name. For example, the slot may return a QDate, then this looks up the
1367 // name _PythonQt.QtCore.QDate.
1368 PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1369 if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1370 PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1371 Q_ASSERT(PyString_Check(s));
1372 type = QString(PyString_AsString(s)) + "." + type;
1373 Py_DECREF(s);
1374 s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__name__");
1375 Q_ASSERT(PyString_Check(s));
1376 Py_DECREF(s);
1377 }
1378 }
1379 }
1380 }
1381 }
1382 }
1383 }
1384 return type;
1385 }
1386
1193 1387 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1194 1388 {
1195 1389 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
@@ -1349,4 +1543,150 void* PythonQtPrivate::unwrapForeignWrapper( const QByteArray& classname, PyObje
1349 1543 }
1350 1544 }
1351 1545 return NULL;
1352 } No newline at end of file
1546 }
1547
1548 bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const
1549 {
1550 // This implementation is the same as in inspect.ismethoddescriptor(), inspect.py.
1551 if (PyObject_HasAttrString(object, "__get__") &&
1552 !PyObject_HasAttrString(object, "__set__") &&
1553 !PyMethod_Check(object) &&
1554 !PyFunction_Check(object) &&
1555 !PyClass_Check(object)) {
1556 return true;
1557 }
1558 return false;
1559 }
1560
1561 QString PythonQtPrivate::getSignature(PyObject* object)
1562 {
1563 QString signature;
1564
1565 if (object) {
1566 PyMethodObject* method = NULL;
1567 PyFunctionObject* func = NULL;
1568
1569 bool decrefMethod = false;
1570
1571 if (object->ob_type == &PyClass_Type || object->ob_type == &PyType_Type) {
1572 method = (PyMethodObject*)PyObject_GetAttrString(object, "__init__");
1573 decrefMethod = true;
1574 } else if (object->ob_type == &PyFunction_Type) {
1575 func = (PyFunctionObject*)object;
1576 } else if (object->ob_type == &PyMethod_Type) {
1577 method = (PyMethodObject*)object;
1578 }
1579 if (method) {
1580 if (PyFunction_Check(method->im_func)) {
1581 func = (PyFunctionObject*)method->im_func;
1582 } else if (isMethodDescriptor((PyObject*)method)) {
1583 QString docstr;
1584 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
1585 if (doc) {
1586 docstr = PyString_AsString(doc);
1587 Py_DECREF(doc);
1588 }
1589
1590 PyObject* s = PyObject_GetAttrString(object, "__name__");
1591 if (s) {
1592 Q_ASSERT(PyString_Check(s));
1593 signature = PyString_AsString(s);
1594 if (docstr.startsWith(signature + "(")) {
1595 signature = docstr;
1596 } else {
1597 signature += "(...)";
1598 if (!docstr.isEmpty()) {
1599 signature += "\n\n" + docstr;
1600 }
1601 }
1602 Py_DECREF(s);
1603 }
1604 }
1605 }
1606
1607 if (func) {
1608 QString funcName;
1609 PyObject* s = PyObject_GetAttrString((PyObject*)func, "__name__");
1610 if (s) {
1611 Q_ASSERT(PyString_Check(s));
1612 funcName = PyString_AsString(s);
1613 Py_DECREF(s);
1614 }
1615 if (method && funcName == "__init__") {
1616 PyObject* s = PyObject_GetAttrString(object, "__name__");
1617 if (s) {
1618 Q_ASSERT(PyString_Check(s));
1619 funcName = PyString_AsString(s);
1620 Py_DECREF(s);
1621 }
1622 }
1623
1624 QStringList arguments;
1625 QStringList defaults;
1626 QString varargs;
1627 QString varkeywords;
1628 // NOTE: This implementation is based on function getargs() in inspect.py.
1629 // inspect.getargs() can handle anonymous (tuple) arguments, while this code does not.
1630 // It can be implemented, but it may be rarely needed and not necessary.
1631 PyCodeObject* code = (PyCodeObject*)func->func_code;
1632 if (code->co_varnames) {
1633 int nargs = code->co_argcount;
1634 Q_ASSERT(PyTuple_Check(code->co_varnames));
1635 for (int i=0; i<nargs; i++) {
1636 PyObject* name = PyTuple_GetItem(code->co_varnames, i);
1637 Q_ASSERT(PyString_Check(name));
1638 arguments << PyString_AsString(name);
1639 }
1640 if (code->co_flags & CO_VARARGS) {
1641 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1642 Q_ASSERT(PyString_Check(s));
1643 varargs = PyString_AsString(s);
1644 nargs += 1;
1645 }
1646 if (code->co_flags & CO_VARKEYWORDS) {
1647 PyObject* s = PyTuple_GetItem(code->co_varnames, nargs);
1648 Q_ASSERT(PyString_Check(s));
1649 varkeywords = PyString_AsString(s);
1650 }
1651 }
1652
1653 PyObject* defaultsTuple = func->func_defaults;
1654 if (defaultsTuple) {
1655 Q_ASSERT(PyTuple_Check(defaultsTuple));
1656 for (Py_ssize_t i=0; i<PyTuple_Size(defaultsTuple); i++) {
1657 PyObject* d = PyTuple_GetItem(defaultsTuple, i);
1658 PyObject* s = PyObject_Repr(d);
1659 Q_ASSERT(PyString_Check(s));
1660 defaults << PyString_AsString(s);
1661 Py_DECREF(s);
1662 }
1663 }
1664
1665 int firstdefault = arguments.size() - defaults.size();
1666 for (int i=0; i<arguments.size(); i++) {
1667 if (!signature.isEmpty()) { signature += ", "; }
1668 if (!method || i>0 || arguments[i] != "self") {
1669 signature += arguments[i];
1670 if (i >= firstdefault) {
1671 signature += "=" + defaults[i-firstdefault];
1672 }
1673 }
1674 }
1675 if (!varargs.isEmpty()) {
1676 if (!signature.isEmpty()) { signature += ", "; }
1677 signature += "*" + varargs;
1678 }
1679 if (!varkeywords.isEmpty()) {
1680 if (!signature.isEmpty()) { signature += ", "; }
1681 signature += "**" + varkeywords;
1682 }
1683 signature = funcName + "(" + signature + ")";
1684 }
1685
1686 if (method && decrefMethod) {
1687 Py_DECREF(method);
1688 }
1689 }
1690
1691 return signature;
1692 }
@@ -333,11 +333,22 public:
333 333
334 334 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
335 335 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
336 //! read vars etc. in scope of the given \c object
337 QStringList introspectObject(PyObject* object, ObjectType type);
338 //! read vars etc. in scope of the type object called \c typename. First the typename
339 //! of the form module.type is split into module and type. Then the module is looked up
340 //! in sys.modules. If the module or type is not found there, then the type is looked up in
341 //! the __builtin__ module.
342 QStringList introspectType(const QString& typeName, ObjectType type);
336 343
337 344 //! returns the found callable object or NULL
338 345 //! @return new reference
339 346 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
340
347
348 //! returns the return type of the method of a wrapped c++ object referenced by \c objectname
349 QString getReturnTypeOfWrappedMethod(PyObject* module, const QString& objectname);
350 //! returns the return type of the method \c methodName of a wrapped c++ type referenced by \c typeName
351 QString getReturnTypeOfWrappedMethod(const QString& typeName, const QString& methodName);
341 352 //@}
342 353
343 354 //---------------------------------------------------------------------------
@@ -501,6 +512,10 signals:
501 512
502 513 private:
503 514 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
515
516 QString getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& variableObject, const QString& methodName, const QString& context);
517
518 PyObject* getObjectByType(const QString& typeName);
504 519
505 520 //! callback for stdout redirection, emits pythonStdOut signal
506 521 static void stdOutRedirectCB(const QString& str);
@@ -626,6 +641,12 public:
626 641
627 642 //! returns the profiling callback, which may be NULL
628 643 PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
644
645 //! determines the signature of the given callable object (similar as pydoc)
646 QString getSignature(PyObject* object);
647
648 //! returns true if the object is a method descriptor (same as inspect.ismethoddescriptor() in inspect.py)
649 bool isMethodDescriptor(PyObject* object) const;
629 650
630 651 private:
631 652 //! Setup the shared library suffixes by getting them from the "imp" module.
@@ -96,7 +96,7 void PythonQtClassInfo::clearCachedMembers()
96 96 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
97 97 while (i.hasNext()) {
98 98 PythonQtMemberInfo member = i.next().value();
99 if (member._type== PythonQtMemberInfo::Slot) {
99 if (member._type== PythonQtMemberInfo::Slot || member._type== PythonQtMemberInfo::Signal) {
100 100 PythonQtSlotInfo* info = member._slot;
101 101 while (info) {
102 102 PythonQtSlotInfo* next = info->nextInfo();
@@ -462,18 +462,14 QStringList PythonQtClassInfo::propertyList()
462 462 return l;
463 463 }
464 464
465 QStringList PythonQtClassInfo::memberList(bool metaOnly)
465 QStringList PythonQtClassInfo::memberList()
466 466 {
467 467 decorator();
468 468
469 469 QStringList l;
470 470 QString h;
471 if (_isQObject && _meta && !metaOnly) {
472 l = propertyList();
473 }
474
475 471 // normal slots of QObject (or wrapper QObject)
476 if (!metaOnly && _meta) {
472 if (_meta) {
477 473 int numMethods = _meta->methodCount();
478 474 bool skipQObj = !_isQObject;
479 475 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
@@ -493,7 +489,7 QStringList PythonQtClassInfo::memberList(bool metaOnly)
493 489 QList<PythonQtClassInfo*> infos;
494 490 recursiveCollectClassInfos(infos);
495 491 foreach(PythonQtClassInfo* info, infos) {
496 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
492 info->listDecoratorSlotsFromDecoratorProvider(l, false);
497 493 }
498 494 }
499 495
@@ -866,3 +862,33 void PythonQtClassInfo::clearNotFoundCachedMembers()
866 862 }
867 863 }
868 864 }
865
866 //-------------------------------------------------------------------------
867
868 PythonQtMemberInfo::PythonQtMemberInfo( PythonQtSlotInfo* info )
869 {
870 if (info->metaMethod()->methodType() == QMetaMethod::Signal) {
871 _type = Signal;
872 } else {
873 _type = Slot;
874 }
875 _slot = info;
876 _enumValue = NULL;
877 }
878
879 PythonQtMemberInfo::PythonQtMemberInfo( const PythonQtObjectPtr& enumValue )
880 {
881 _type = EnumValue;
882 _slot = NULL;
883 _enumValue = enumValue;
884 _enumWrapper = NULL;
885 }
886
887 PythonQtMemberInfo::PythonQtMemberInfo( const QMetaProperty& prop )
888 {
889 _type = Property;
890 _slot = NULL;
891 _enumValue = NULL;
892 _property = prop;
893 _enumWrapper = NULL;
894 } No newline at end of file
@@ -44,31 +44,16 class PythonQtSlotInfo;
44 44
45 45 struct PythonQtMemberInfo {
46 46 enum Type {
47 Invalid, Slot, EnumValue, EnumWrapper, Property, NotFound
47 Invalid, Slot, Signal, EnumValue, EnumWrapper, Property, NotFound
48 48 };
49 49
50 50 PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { }
51 51
52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
53 _type = Slot;
54 _slot = info;
55 _enumValue = NULL;
56 }
52 PythonQtMemberInfo(PythonQtSlotInfo* info);
57 53
58 PythonQtMemberInfo(const PythonQtObjectPtr& enumValue) {
59 _type = EnumValue;
60 _slot = NULL;
61 _enumValue = enumValue;
62 _enumWrapper = NULL;
63 }
54 PythonQtMemberInfo(const PythonQtObjectPtr& enumValue);
64 55
65 PythonQtMemberInfo(const QMetaProperty& prop) {
66 _type = Property;
67 _slot = NULL;
68 _enumValue = NULL;
69 _property = prop;
70 _enumWrapper = NULL;
71 }
56 PythonQtMemberInfo(const QMetaProperty& prop);
72 57
73 58 Type _type;
74 59
@@ -159,8 +144,8 public:
159 144 //! get list of all properties (on QObjects only, otherwise the list is empty)
160 145 QStringList propertyList();
161 146
162 //! get list of all members
163 QStringList memberList(bool metaOnly = false);
147 //! get list of all members (excluding properties, which can be listed with propertyList())
148 QStringList memberList();
164 149
165 150 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
166 151 int metaTypeId() { return _metaTypeId; }
@@ -44,6 +44,7
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtSlot.h"
47 #include "PythonQtSignal.h"
47 48 #include "PythonQtClassInfo.h"
48 49 #include "PythonQtConversion.h"
49 50 #include "PythonQtInstanceWrapper.h"
@@ -291,40 +292,8 PyObject *PythonQtClassWrapper_inherits(PythonQtClassWrapper *type, PyObject *ar
291 292 return PythonQtConv::GetPyBool(wrapper->classInfo()->inherits(name));
292 293 }
293 294
294 PyObject *PythonQtClassWrapper__init__(PythonQtClassWrapper *type, PyObject *args)
295 {
296 Py_ssize_t argc = PyTuple_Size(args);
297 if (argc>0) {
298 // we need to call __init__ of the instance
299 PyObject* self = PyTuple_GET_ITEM(args, 0);
300 if (PyObject_TypeCheck(self, (PyTypeObject*)type->classInfo()->pythonQtClassWrapper())) {
301 PyObject* newargs = PyTuple_New(argc-1);
302 for (int i = 0;i<argc-1; i++) {
303 PyTuple_SET_ITEM(newargs, i,PyTuple_GET_ITEM(args, i+1));
304 }
305 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
306 int result = PythonQtInstanceWrapper_init(wrapper, newargs, NULL);
307 Py_DECREF(newargs);
308 if (result==0) {
309 Py_INCREF(Py_None);
310 return Py_None;
311 } else {
312 // init failed!
313 }
314 } else {
315 // self not of correct type!
316 }
317 } else {
318 // wrong number of args
319 }
320 return NULL;
321 }
322
323 295
324 296 static PyMethodDef PythonQtClassWrapper_methods[] = {
325 {"__init__", (PyCFunction)PythonQtClassWrapper__init__, METH_VARARGS,
326 "Init function"
327 },
328 297 {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS,
329 298 "Return the classname of the object"
330 299 },
@@ -354,14 +323,14 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
354 323 }
355 324
356 325 if (qstrcmp(attributeName, "__dict__")==0) {
357 PyObject* dict = ((PyTypeObject *)wrapper)->tp_dict;
326 PyObject* objectDict = ((PyTypeObject *)wrapper)->tp_dict;
358 327 if (!wrapper->classInfo()) {
359 Py_INCREF(dict);
360 return dict;
328 Py_INCREF(objectDict);
329 return objectDict;
361 330 }
362 dict = PyDict_Copy(dict);
363
364 QStringList l = wrapper->classInfo()->memberList(false);
331 PyObject* dict = PyDict_New();
332
333 QStringList l = wrapper->classInfo()->memberList();
365 334 foreach (QString name, l) {
366 335 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
367 336 if (o) {
@@ -369,21 +338,33 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
369 338 Py_DECREF(o);
370 339 } else {
371 340 // it must have been a property or child, which we do not know as a class object...
341 PyErr_Clear();
372 342 }
373 343 }
374 344 if (wrapper->classInfo()->constructors()) {
375 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[0], obj);
345 PyObject* initName = PyString_FromString("__init__");
346 PyObject* func = PyType_Type.tp_getattro(obj, initName);
347 Py_DECREF(initName);
376 348 PyDict_SetItemString(dict, "__init__", func);
377 349 Py_DECREF(func);
378 350 }
379 for (int i = 1; PythonQtClassWrapper_methods[i].ml_name != NULL; i++) {
351 for (int i = 0; PythonQtClassWrapper_methods[i].ml_name != NULL; i++) {
380 352 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj);
381 353 PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func);
382 354 Py_DECREF(func);
383 355 }
356
357 PyDict_Update(dict, objectDict);
384 358 return dict;
385 359 }
386 360
361 // look in Python to support derived Python classes
362 PyObject* superAttr = PyType_Type.tp_getattro(obj, name);
363 if (superAttr) {
364 return superAttr;
365 }
366 PyErr_Clear();
367
387 368 if (wrapper->classInfo()) {
388 369 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
389 370 if (member._type == PythonQtMemberInfo::EnumValue) {
@@ -397,21 +378,17 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
397 378 } else if (member._type == PythonQtMemberInfo::Slot) {
398 379 // we return all slots, even the instance slots, since they are callable as unbound slots with self argument
399 380 return PythonQtSlotFunction_New(member._slot, obj, NULL);
381 } else if (member._type == PythonQtMemberInfo::Signal) {
382 // we return all signals, even the instance signals, since they are callable as unbound signals with self argument
383 return PythonQtSignalFunction_New(member._slot, obj, NULL);
400 384 }
401 385 }
402 386
403 // look for the interal methods (className(), help())
387 // look for the internal methods (className(), help())
404 388 PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName);
405 389 if (internalMethod) {
406 390 return internalMethod;
407 391 }
408 PyErr_Clear();
409
410 // look in super
411 PyObject* superAttr = PyType_Type.tp_getattro(obj, name);
412 if (superAttr) {
413 return superAttr;
414 }
415 392
416 393 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
417 394 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
@@ -70,6 +70,11 public:
70 70 //! indicates that *.py files which are newer than their corresponding *.pyc files
71 71 //! are ignored
72 72 virtual bool ignoreUpdatedPythonSourceFiles() { return false; }
73
74 //! called by PythonQt after successful import to allow
75 //! recording of imports
76 virtual void importedModule(const QString& /*module*/) {};
77
73 78 };
74 79
75 80 #endif
@@ -255,7 +255,13 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
255 255 return NULL;
256 256 }
257 257 }
258
258 259 mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data());
260
261 if (PythonQt::importInterface()) {
262 PythonQt::importInterface()->importedModule(fullname);
263 }
264
259 265 Py_DECREF(code);
260 266 if (Py_VerboseFlag) {
261 267 PySys_WriteStderr("import %s # loaded from %s\n",
@@ -43,6 +43,7
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 #include "PythonQtSignal.h"
46 47 #include "PythonQtClassInfo.h"
47 48 #include "PythonQtConversion.h"
48 49 #include "PythonQtClassWrapper.h"
@@ -413,6 +414,9 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
413 414 case PythonQtMemberInfo::Slot:
414 415 return PythonQtSlotFunction_New(member._slot, obj, NULL);
415 416 break;
417 case PythonQtMemberInfo::Signal:
418 return PythonQtSignalFunction_New(member._slot, obj, NULL);
419 break;
416 420 case PythonQtMemberInfo::EnumValue:
417 421 {
418 422 PyObject* enumValue = member._enumValue;
@@ -529,6 +533,8 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec
529 533 }
530 534 } else if (member._type == PythonQtMemberInfo::Slot) {
531 535 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
536 } else if (member._type == PythonQtMemberInfo::Signal) {
537 error = QString("Signal '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
532 538 } else if (member._type == PythonQtMemberInfo::EnumValue) {
533 539 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
534 540 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
@@ -590,14 +596,16 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
590 596 return result;
591 597 }
592 598 }
593 // next, try to call py_toString
594 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
595 if (info._type == PythonQtMemberInfo::Slot) {
596 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
597 if (resultObj) {
598 // TODO this is one conversion too much, would be nicer to call the slot directly...
599 result = PythonQtConv::PyObjGetString(resultObj);
600 Py_DECREF(resultObj);
599 if (wrapper->_wrappedPtr || wrapper->_obj) {
600 // next, try to call py_toString
601 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
602 if (info._type == PythonQtMemberInfo::Slot) {
603 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
604 if (resultObj) {
605 // TODO this is one conversion too much, would be nicer to call the slot directly...
606 result = PythonQtConv::PyObjGetString(resultObj);
607 Py_DECREF(resultObj);
608 }
601 609 }
602 610 }
603 611 return result;
@@ -99,7 +99,9 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentLis
99 99 if (i>1) {
100 100 fullSig += ",";
101 101 }
102 arguments << QByteArray(args[i]);
102 QByteArray arg(args[i]);
103 fullSig += arg;
104 arguments << arg;
103 105 }
104 106 fullSig += ")";
105 107 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
@@ -66,7 +66,7 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf
66 66 PyObject* o = callable;
67 67 PyFunctionObject* func = (PyFunctionObject*)o;
68 68 PyCodeObject* code = (PyCodeObject*)func->func_code;
69 if (!(code->co_flags & 0x04)) {
69 if (!(code->co_flags & CO_VARARGS)) {
70 70 numPythonArgs = code->co_argcount;
71 71 } else {
72 72 // variable numbers of arguments allowed
@@ -77,7 +77,7 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf
77 77 if (PyFunction_Check(method->im_func)) {
78 78 PyFunctionObject* func = (PyFunctionObject*)method->im_func;
79 79 PyCodeObject* code = (PyCodeObject*)func->func_code;
80 if (!(code->co_flags & 0x04)) {
80 if (!(code->co_flags & CO_VARARGS)) {
81 81 numPythonArgs = code->co_argcount - 1; // we subtract one because the first is "self"
82 82 } else {
83 83 // variable numbers of arguments allowed
@@ -187,11 +187,20 bool PythonQtSignalReceiver::removeSignalHandler(const char* signal, PyObject* c
187 187 int sigId = getSignalIndex(signal);
188 188 if (sigId>=0) {
189 189 QMutableListIterator<PythonQtSignalTarget> i(_targets);
190 while (i.hasNext()) {
191 if (i.next().isSame(sigId, callable)) {
192 i.remove();
193 found = true;
194 break;
190 if (callable) {
191 while (i.hasNext()) {
192 if (i.next().isSame(sigId, callable)) {
193 i.remove();
194 found = true;
195 break;
196 }
197 }
198 } else {
199 while (i.hasNext()) {
200 if (i.next().signalId() == sigId) {
201 i.remove();
202 found = true;
203 }
195 204 }
196 205 }
197 206 }
@@ -118,8 +118,8 public:
118 118 //! add a signal handler
119 119 bool addSignalHandler(const char* signal, PyObject* callable);
120 120
121 //! remove a signal handler
122 bool removeSignalHandler(const char* signal, PyObject* callable);
121 //! remove a signal handler for given callable (or all callables on that signal if callable is NULL)
122 bool removeSignalHandler(const char* signal, PyObject* callable = NULL);
123 123
124 124 //! remove all signal handlers
125 125 void removeSignalHandlers();
@@ -140,3 +140,4 private:
140 140
141 141
142 142 #endif
143
@@ -50,6 +50,8
50 50 #include <exception>
51 51 #include <stdexcept>
52 52
53 #include <QByteArray>
54
53 55 #define PYTHONQT_MAX_ARGS 32
54 56
55 57
@@ -160,28 +162,34 bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj
160 162
161 163 // invoke the slot via metacall
162 164 bool hadException = false;
163 try {
164 (info->decorator()?info->decorator():objectToCall)->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
165 } catch (std::bad_alloc & e) {
166 hadException = true;
167 QByteArray what("std::bad_alloc: ");
168 what += e.what();
169 PyErr_SetString(PyExc_MemoryError, what.constData());
170 } catch (std::runtime_error & e) {
171 hadException = true;
172 QByteArray what("std::runtime_error: ");
173 what += e.what();
174 PyErr_SetString(PyExc_RuntimeError, what.constData());
175 } catch (std::logic_error & e) {
165 QObject* obj = info->decorator()?info->decorator():objectToCall;
166 if (!obj) {
176 167 hadException = true;
177 QByteArray what("std::logic_error: ");
178 what += e.what();
179 PyErr_SetString(PyExc_RuntimeError, what.constData());
180 } catch (std::exception& e) {
181 hadException = true;
182 QByteArray what("std::exception: ");
183 what += e.what();
184 PyErr_SetString(PyExc_StandardError, what.constData());
168 PyErr_SetString(PyExc_RuntimeError, "Trying to call a slot on a deleted QObject!");
169 } else {
170 try {
171 obj->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
172 } catch (std::bad_alloc & e) {
173 hadException = true;
174 QByteArray what("std::bad_alloc: ");
175 what += e.what();
176 PyErr_SetString(PyExc_MemoryError, what.constData());
177 } catch (std::runtime_error & e) {
178 hadException = true;
179 QByteArray what("std::runtime_error: ");
180 what += e.what();
181 PyErr_SetString(PyExc_RuntimeError, what.constData());
182 } catch (std::logic_error & e) {
183 hadException = true;
184 QByteArray what("std::logic_error: ");
185 what += e.what();
186 PyErr_SetString(PyExc_RuntimeError, what.constData());
187 } catch (std::exception& e) {
188 hadException = true;
189 QByteArray what("std::exception: ");
190 what += e.what();
191 PyErr_SetString(PyExc_StandardError, what.constData());
192 }
185 193 }
186 194
187 195 if (profilingCB) {
@@ -227,18 +235,22 static PythonQtSlotFunctionObject *pythonqtslot_free_list = NULL;
227 235 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw)
228 236 {
229 237 PythonQtSlotFunctionObject* f = (PythonQtSlotFunctionObject*)func;
230 PythonQtSlotInfo* info = f->m_ml;
231 if (PyObject_TypeCheck(f->m_self, &PythonQtInstanceWrapper_Type)) {
232 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) f->m_self;
238 return PythonQtMemberFunction_Call(f->m_ml, f->m_self, args, kw);
239 }
240
241 PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, PyObject *args, PyObject *kw)
242 {
243 if (PyObject_TypeCheck(m_self, &PythonQtInstanceWrapper_Type)) {
244 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*) m_self;
233 245 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
234 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
246 QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
235 247 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
236 248 return NULL;
237 249 } else {
238 250 return PythonQtSlotFunction_CallImpl(self->classInfo(), self->_obj, info, args, kw, self->_wrappedPtr);
239 251 }
240 } else if (f->m_self->ob_type == &PythonQtClassWrapper_Type) {
241 PythonQtClassWrapper* type = (PythonQtClassWrapper*) f->m_self;
252 } else if (m_self->ob_type == &PythonQtClassWrapper_Type) {
253 PythonQtClassWrapper* type = (PythonQtClassWrapper*) m_self;
242 254 if (info->isClassDecorator()) {
243 255 return PythonQtSlotFunction_CallImpl(type->classInfo(), NULL, info, args, kw);
244 256 } else {
@@ -250,7 +262,7 PyObject *PythonQtSlotFunction_Call(PyObject *func, PyObject *args, PyObject *kw
250 262 && ((PythonQtInstanceWrapper*)firstArg)->classInfo()->inherits(type->classInfo())) {
251 263 PythonQtInstanceWrapper* self = (PythonQtInstanceWrapper*)firstArg;
252 264 if (!info->isClassDecorator() && (self->_obj==NULL && self->_wrappedPtr==NULL)) {
253 QString error = QString("Trying to call '") + f->m_ml->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
265 QString error = QString("Trying to call '") + info->slotName() + "' on a destroyed " + self->classInfo()->className() + " object";
254 266 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
255 267 return NULL;
256 268 }
@@ -456,6 +468,96 static PyMemberDef meth_members[] = {
456 468 {NULL}
457 469 };
458 470
471 static PyObject *PythonQtSlotFunction_parameterTypes(PythonQtSlotFunctionObject* type)
472 {
473 return PythonQtMemberFunction_parameterTypes(type->m_ml);
474 }
475
476 static PyObject *PythonQtSlotFunction_parameterNames(PythonQtSlotFunctionObject* type)
477 {
478 return PythonQtMemberFunction_parameterNames(type->m_ml);
479 }
480
481 static PyObject *PythonQtSlotFunction_typeName(PythonQtSlotFunctionObject* type)
482 {
483 return PythonQtMemberFunction_typeName(type->m_ml);
484 }
485
486 PyObject *PythonQtMemberFunction_parameterTypes(PythonQtSlotInfo* theInfo)
487 {
488 PythonQtSlotInfo* info = theInfo;
489 int count = 0;
490 while (info) {
491 info = info->nextInfo();
492 count++;
493 }
494 info = theInfo;
495 PyObject* result = PyTuple_New(count);
496 for (int j = 0;j<count;j++) {
497 QList<QByteArray> types = info->metaMethod()->parameterTypes();
498 PyObject* tuple = PyTuple_New(types.count());
499 for (int i = 0; i<types.count();i++) {
500 PyTuple_SET_ITEM(tuple, i, PyString_FromString(types.at(i).constData()));
501 }
502 info = info->nextInfo();
503 PyTuple_SET_ITEM(result, j, tuple);
504 }
505 return result;
506 }
507
508 PyObject *PythonQtMemberFunction_parameterNames(PythonQtSlotInfo* theInfo)
509 {
510 PythonQtSlotInfo* info = theInfo;
511 int count = 0;
512 while (info) {
513 info = info->nextInfo();
514 count++;
515 }
516 info = theInfo;
517 PyObject* result = PyTuple_New(count);
518 for (int j = 0;j<count;j++) {
519 QList<QByteArray> names = info->metaMethod()->parameterNames();
520 PyObject* tuple = PyTuple_New(names.count());
521 for (int i = 0; i<names.count();i++) {
522 PyTuple_SET_ITEM(tuple, i, PyString_FromString(names.at(i).constData()));
523 }
524 info = info->nextInfo();
525 PyTuple_SET_ITEM(result, j, tuple);
526 }
527 return result;
528 }
529
530 PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo)
531 {
532 PythonQtSlotInfo* info = theInfo;
533 int count = 0;
534 while (info) {
535 info = info->nextInfo();
536 count++;
537 }
538 info = theInfo;
539 PyObject* result = PyTuple_New(count);
540 for (int j = 0;j<count;j++) {
541 QByteArray name = info->metaMethod()->typeName();
542 PyTuple_SET_ITEM(result, j, PyString_FromString(name.constData()));
543 info = info->nextInfo();
544 }
545 return result;
546 }
547
548 static PyMethodDef meth_methods[] = {
549 {"parameterTypes", (PyCFunction)PythonQtSlotFunction_parameterTypes, METH_NOARGS,
550 "Returns a tuple of tuples of the C++ parameter types for all overloads of the slot"
551 },
552 {"parameterNames", (PyCFunction)PythonQtSlotFunction_parameterNames, METH_NOARGS,
553 "Returns a tuple of tuples of the C++ parameter type names (if available), for all overloads of the slot"
554 },
555 {"typeName", (PyCFunction)PythonQtSlotFunction_typeName, METH_NOARGS,
556 "Returns a tuple of the C++ return value types of each slot overload"
557 },
558 {NULL, NULL, 0 , NULL} /* Sentinel */
559 };
560
459 561 static PyObject *
460 562 meth_repr(PythonQtSlotFunctionObject *f)
461 563 {
@@ -535,7 +637,7 PyTypeObject PythonQtSlotFunction_Type = {
535 637 0, /* tp_weaklistoffset */
536 638 0, /* tp_iter */
537 639 0, /* tp_iternext */
538 0, /* tp_methods */
640 meth_methods, /* tp_methods */
539 641 meth_members, /* tp_members */
540 642 meth_getsets, /* tp_getset */
541 643 0, /* tp_base */
@@ -65,10 +65,14 PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *);
65 65
66 66 PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL);
67 67
68
69 68 PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *,
70 69 PyObject *);
71 70
71 PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, PyObject *args, PyObject *kw);
72 PyObject *PythonQtMemberFunction_parameterTypes(PythonQtSlotInfo* theInfo);
73 PyObject *PythonQtMemberFunction_parameterNames(PythonQtSlotInfo* theInfo);
74 PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo);
75
72 76 //! defines a python object that stores a Qt slot info
73 77 typedef struct {
74 78 PyObject_HEAD
@@ -102,6 +102,9 bool PythonQtStdDecorators::disconnect(QObject* sender, const QByteArray& signal
102 102 }
103 103 if (sender) {
104 104 result = PythonQt::self()->removeSignalHandler(sender, signalTmp, callable);
105 if (callable == NULL) {
106 result |= QObject::disconnect(sender, signalTmp, NULL, NULL);
107 }
105 108 if (!result) {
106 109 if (sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature(signalTmp.constData()+1)) == -1) {
107 110 qWarning("PythonQt: QObject::disconnect() signal '%s' does not exist on %s", signal.constData(), sender->metaObject()->className());
@@ -61,7 +61,7 class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject
61 61 public slots:
62 62 bool connect(QObject* sender, const QByteArray& signal, PyObject* callable);
63 63 bool connect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
64 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable);
64 bool disconnect(QObject* sender, const QByteArray& signal, PyObject* callable = NULL);
65 65 bool disconnect(QObject* sender, const QByteArray& signal, QObject* receiver, const QByteArray& slot);
66 66
67 67 QObject* parent(QObject* o);
@@ -6,6 +6,7 HEADERS += \
6 6 $$PWD/PythonQtClassInfo.h \
7 7 $$PWD/PythonQtImporter.h \
8 8 $$PWD/PythonQtObjectPtr.h \
9 $$PWD/PythonQtSignal.h \
9 10 $$PWD/PythonQtSlot.h \
10 11 $$PWD/PythonQtStdIn.h \
11 12 $$PWD/PythonQtStdOut.h \
@@ -31,6 +32,7 SOURCES += \
31 32 $$PWD/PythonQtObjectPtr.cpp \
32 33 $$PWD/PythonQtStdIn.cpp \
33 34 $$PWD/PythonQtStdOut.cpp \
35 $$PWD/PythonQtSignal.cpp \
34 36 $$PWD/PythonQtSlot.cpp \
35 37 $$PWD/PythonQtMisc.cpp \
36 38 $$PWD/PythonQtMethodInfo.cpp \
General Comments 0
You need to be logged in to leave comments. Login now