##// END OF EJS Templates
added error handling for virtual method overloads, added more global functions (qsrand etc.), added support for exec_ etc (python keyword overlap resolution), change virtual method handling, this will require code regeneration (I will do that tomorrow)...
florianlink -
r67:57d78f859ef3
parent child
Show More
@@ -140,6 +140,22 void PythonQt::init(int flags)
140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
140 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
141 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
142
142
143
144 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
145 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
146 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
147 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
148 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
149 for (unsigned int i = 0;i<16; i++) {
150 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
151 if (obj) {
152 PyModule_AddObject(pack, names[i], obj);
153 Py_INCREF(obj);
154 PyModule_AddObject(pack2, names[i], obj);
155 } else {
156 std::cerr << "method not found " << names[i];
157 }
158 }
143 }
159 }
144
160
145 void PythonQt::cleanup()
161 void PythonQt::cleanup()
@@ -1130,35 +1146,6 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentT
1130 }
1146 }
1131 }
1147 }
1132
1148
1133 static PyObject *PythonQt_SIGNAL(PyObject * /*type*/, PyObject *args)
1134 {
1135 const char* value;
1136 if (!PyArg_ParseTuple(args, "s", &value)) {
1137 return NULL;
1138 }
1139 // we do not prepend 0,1 or 2, why should we?
1140 return PyString_FromString(QByteArray("2") + value);
1141 }
1142
1143 static PyObject *PythonQt_SLOT(PyObject * /*type*/, PyObject *args)
1144 {
1145 const char* value;
1146 if (!PyArg_ParseTuple(args, "s", &value)) {
1147 return NULL;
1148 }
1149 // we do not prepend 0,1 or 2, why should we?
1150 return PyString_FromString(QByteArray("1") + value);
1151 }
1152
1153 static PyMethodDef PythonQt_Qt_methods[] = {
1154 {"SIGNAL", (PyCFunction)PythonQt_SIGNAL, METH_VARARGS,
1155 "Returns a signal string"
1156 },
1157 {"SLOT", (PyCFunction)PythonQt_SLOT, METH_VARARGS,
1158 "Returns a slot string"
1159 }
1160 };
1161
1162 PyObject* PythonQtPrivate::packageByName(const char* name)
1149 PyObject* PythonQtPrivate::packageByName(const char* name)
1163 {
1150 {
1164 if (name==NULL || name[0]==0) {
1151 if (name==NULL || name[0]==0) {
@@ -1167,11 +1154,6 PyObject* PythonQtPrivate::packageByName(const char* name)
1167 PyObject* v = _packages.value(name);
1154 PyObject* v = _packages.value(name);
1168 if (!v) {
1155 if (!v) {
1169 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1156 v = PyImport_AddModule((QByteArray("PythonQt.") + name).constData());
1170 if (strcmp(name,"Qt")==0 || strcmp(name,"QtCore")==0) {
1171 // add SIGNAL and SLOT functions
1172 PyModule_AddObject(v, "SIGNAL", PyCFunction_New(PythonQt_Qt_methods, v));
1173 PyModule_AddObject(v, "SLOT", PyCFunction_New(PythonQt_Qt_methods+1, v));
1174 }
1175 _packages.insert(name, v);
1157 _packages.insert(name, v);
1176 // AddObject steals the reference, so increment it!
1158 // AddObject steals the reference, so increment it!
1177 Py_INCREF(v);
1159 Py_INCREF(v);
@@ -1180,6 +1162,12 PyObject* PythonQtPrivate::packageByName(const char* name)
1180 return v;
1162 return v;
1181 }
1163 }
1182
1164
1165 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1166 {
1167 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1168 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1169 PythonQt::self()->handleError();
1170 }
1183
1171
1184 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1172 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1185 {
1173 {
@@ -470,6 +470,9 public:
470 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
470 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
471 static PyObject* dummyTuple();
471 static PyObject* dummyTuple();
472
472
473 //! called by virtual overloads when a python return value can not be converted to the required Qt type
474 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
475
473 private:
476 private:
474
477
475 //! create a new pythonqt class wrapper and place it in the pythonqt module
478 //! create a new pythonqt class wrapper and place it in the pythonqt module
@@ -308,6 +308,7 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
308 }
308 }
309 }
309 }
310 if (!found) {
310 if (!found) {
311 // maybe it is an enum wrapper?
311 PyObject* p = findEnumWrapper(memberName);
312 PyObject* p = findEnumWrapper(memberName);
312 if (p) {
313 if (p) {
313 info._type = PythonQtMemberInfo::EnumWrapper;
314 info._type = PythonQtMemberInfo::EnumWrapper;
@@ -317,6 +318,20 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
317 }
318 }
318 }
319 }
319 if (!found) {
320 if (!found) {
321 // since python keywords can not be looked up, we check if the name contains a single trailing _
322 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
323 QByteArray mbrName(memberName);
324 if ((mbrName.length()>2) &&
325 (mbrName.at(mbrName.length()-1) == '_') &&
326 (mbrName.at(mbrName.length()-2) != '_')) {
327 mbrName = mbrName.mid(0,mbrName.length()-1);
328 found = lookForMethodAndCache(mbrName.constData());
329 if (found) {
330 return _cachedMembers.value(mbrName);
331 }
332 }
333 }
334 if (!found) {
320 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
335 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
321 info._type = PythonQtMemberInfo::NotFound;
336 info._type = PythonQtMemberInfo::NotFound;
322 _cachedMembers.insert(memberName, info);
337 _cachedMembers.insert(memberName, info);
@@ -144,7 +144,7
144 - PythonQt allows to communicate in both directions, e.g. calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
144 - PythonQt allows to communicate in both directions, e.g. calling a Python object from C++ AND calling a C++ method from Python, while PyQt only handles the Python->C++ direction
145 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
145 - PythonQt offers properties as Python attributes, while PyQt offers them as setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method in PyQt)
146 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
146 - PythonQt does not support instanceof checks for Qt classes, except for the exact match and derived Python classes
147 - QObject.emit to emit Qt signals from Python is not yet implemented
147 - QObject.emit to emit Qt signals from Python is not yet implemented but PythonQt allows to just emit a signal by calling it
148 - PythonQt does not offer to add new signals to Python/C++ objects
148 - PythonQt does not offer to add new signals to Python/C++ objects
149 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually references in PythonQt to not get deleted too early (this will be fixed)
149 - Ownership of objects is a bit different in PythonQt, currently Python classes derived from a C++ class need to be manually references in PythonQt to not get deleted too early (this will be fixed)
150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
150 - Probably there are lots of details that differ, I do not know PyQt that well to list them all.
@@ -58,14 +58,24 PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInf
58 ParameterInfo type;
58 ParameterInfo type;
59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
59 fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
60 _parameters.append(type);
60 _parameters.append(type);
61 QByteArray name;
62 QList<QByteArray> names = meta.parameterTypes();
61 QList<QByteArray> names = meta.parameterTypes();
63 foreach (name, names) {
62 foreach (const QByteArray& name, names) {
64 fillParameterInfo(type, name, classInfo);
63 fillParameterInfo(type, name, classInfo);
65 _parameters.append(type);
64 _parameters.append(type);
66 }
65 }
67 }
66 }
68
67
68 PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
69 {
70 ParameterInfo type;
71 fillParameterInfo(type, typeName, NULL);
72 _parameters.append(type);
73 foreach (const QByteArray& name, args) {
74 fillParameterInfo(type, name, NULL);
75 _parameters.append(type);
76 }
77 }
78
69 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
79 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
70 {
80 {
71 QByteArray sig(signal.signature());
81 QByteArray sig(signal.signature());
@@ -79,12 +89,25 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMet
79 return result;
89 return result;
80 }
90 }
81
91
82 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromMetaObjectAndSignature(const QMetaObject* metaObject, const char* signature)
92 const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
83 {
93 {
84 QByteArray sig = QMetaObject::normalizedSignature(signature);
94 QByteArray typeName = args[0];
85 int idx = metaObject->indexOfMethod(sig);
95 QList<QByteArray> arguments;
86 QMetaMethod meta = metaObject->method(idx);
96 QByteArray fullSig = typeName;
87 return PythonQtMethodInfo::getCachedMethodInfo(meta, NULL);
97 fullSig += "(";
98 for (int i =1;i<numArgs; i++) {
99 if (i>1) {
100 fullSig += ",";
101 }
102 arguments << QByteArray(args[i]);
103 }
104 fullSig += ")";
105 PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
106 if (!result) {
107 result = new PythonQtMethodInfo(typeName, arguments);
108 _cachedSignatures.insert(fullSig, result);
109 }
110 return result;
88 }
111 }
89
112
90 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
113 void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
@@ -74,6 +74,7 public:
74 PythonQtMethodInfo() {};
74 PythonQtMethodInfo() {};
75 ~PythonQtMethodInfo() {};
75 ~PythonQtMethodInfo() {};
76 PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
76 PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
77 PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args);
77 PythonQtMethodInfo(const PythonQtMethodInfo& other) {
78 PythonQtMethodInfo(const PythonQtMethodInfo& other) {
78 _parameters = other._parameters;
79 _parameters = other._parameters;
79 }
80 }
@@ -82,8 +83,8 public:
82 //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
83 //! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
83 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
84 static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
84
85
85 //! get the cached method info by finding the meta method on the meta object via its signature, enums are only supported with leading namespace::
86 //! get the cached method info using the passed in list of return value and arguments, return value needs to be passed as first arg
86 static const PythonQtMethodInfo* getCachedMethodInfoFromMetaObjectAndSignature(const QMetaObject* metaObject, const char* signature);
87 static const PythonQtMethodInfo* getCachedMethodInfoFromArgumentList(int numArgs, const char** args);
87
88
88 //! cleanup the cache
89 //! cleanup the cache
89 static void cleanupCachedMethodInfos();
90 static void cleanupCachedMethodInfos();
@@ -48,7 +48,7
48 #include "funcobject.h"
48 #include "funcobject.h"
49
49
50 void PythonQtSignalTarget::call(void **arguments) const {
50 void PythonQtSignalTarget::call(void **arguments) const {
51 PyObject* result = call(_callable, methodInfo(), arguments, false);
51 PyObject* result = call(_callable, methodInfo(), arguments);
52 if (result) {
52 if (result) {
53 Py_DECREF(result);
53 Py_DECREF(result);
54 }
54 }
@@ -86,9 +86,6 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf
86 const PythonQtMethodInfo* m = methodInfos;
86 const PythonQtMethodInfo* m = methodInfos;
87 // parameterCount includes return value:
87 // parameterCount includes return value:
88 int count = m->parameterCount();
88 int count = m->parameterCount();
89 if (skipFirstArgumentOfMethodInfo) {
90 count--;
91 }
92 if (numPythonArgs!=-1) {
89 if (numPythonArgs!=-1) {
93 if (count>numPythonArgs+1) {
90 if (count>numPythonArgs+1) {
94 // take less arguments
91 // take less arguments
@@ -103,12 +100,8 PyObject* PythonQtSignalTarget::call(PyObject* callable, const PythonQtMethodInf
103 bool err = false;
100 bool err = false;
104 // transform Qt values to Python
101 // transform Qt values to Python
105 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
102 const QList<PythonQtMethodInfo::ParameterInfo>& params = m->parameters();
106 int skipFirstOffset = 0;
107 if (skipFirstArgumentOfMethodInfo) {
108 skipFirstOffset = 1;
109 }
110 for (int i = 1; i < count; i++) {
103 for (int i = 1; i < count; i++) {
111 const PythonQtMethodInfo::ParameterInfo& param = params.at(i + skipFirstOffset);
104 const PythonQtMethodInfo::ParameterInfo& param = params.at(i);
112 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
105 PyObject* arg = PythonQtConv::ConvertQtValueToPython(param, arguments[i]);
113 if (arg) {
106 if (arg) {
114 // steals reference, no unref
107 // steals reference, no unref
@@ -71,6 +71,28 public slots:
71 void setParent(QObject* o, QObject* parent);
71 void setParent(QObject* o, QObject* parent);
72
72
73 QVariantList children(QObject* o);
73 QVariantList children(QObject* o);
74
75 double static_Qt_qAbs(double a) { return qAbs(a); }
76 double static_Qt_qBound(double a,double b,double c) { return qBound(a,b,c); }
77 void static_Qt_qDebug(const QByteArray& msg) { qDebug(msg.constData()); }
78 // TODO: multi arg qDebug...
79 void static_Qt_qWarning(const QByteArray& msg) { qWarning(msg.constData()); }
80 // TODO: multi arg qWarning...
81 void static_Qt_qCritical(const QByteArray& msg) { qCritical(msg.constData()); }
82 // TODO: multi arg qCritical...
83 void static_Qt_qFatal(const QByteArray& msg) { qFatal(msg.constData()); }
84 // TODO: multi arg qFatal...
85 bool static_Qt_qFuzzyCompare(double a, double b) { return qFuzzyCompare(a, b); }
86 double static_Qt_qMax(double a, double b) { return qMax(a, b); }
87 double static_Qt_qMin(double a, double b) { return qMin(a, b); }
88 int static_Qt_qRound(double a) { return qRound(a); }
89 qint64 static_Qt_qRound64(double a) { return qRound64(a); }
90 const char* static_Qt_qVersion() { return qVersion(); }
91 int static_Qt_qrand() { return qrand(); }
92 void static_Qt_qsrand(uint a) { qsrand(a); }
93
94 QByteArray static_Qt_SIGNAL(const QByteArray& s) { return QByteArray("2") + s; }
95 QByteArray static_Qt_SLOT(const QByteArray& s) { return QByteArray("1") + s; }
74
96
75 //TODO: add findChild/findChildren/children/...
97 //TODO: add findChild/findChildren/children/...
76 };
98 };
General Comments 0
You need to be logged in to leave comments. Login now