Skip to content

Commit f3bcda8

Browse files
committed
improved enum generation for decorators
improved sequence conversion callback added support for inheritance chain of Python classes when deriving from a Qt wrapper
1 parent cd4761f commit f3bcda8

File tree

7 files changed

+69
-22
lines changed

7 files changed

+69
-22
lines changed

src/PythonQt.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,15 +1936,31 @@ const QMetaObject* PythonQtPrivate::getDynamicMetaObject(PythonQtInstanceWrapper
19361936
PythonQtDynamicClassInfo* info = wrapper->dynamicClassInfo();
19371937
if (info) {
19381938
if (!info->_dynamicMetaObject) {
1939-
buildDynamicMetaObject(((PythonQtClassWrapper*)Py_TYPE(wrapper)), prototypeMetaObject);
1939+
setupDynamicMetaObjectChain(((PythonQtClassWrapper*)Py_TYPE(wrapper)), prototypeMetaObject);
19401940
}
19411941
return info->_dynamicMetaObject;
19421942
}
19431943
return prototypeMetaObject;
19441944
}
19451945

1946-
void PythonQtPrivate::buildDynamicMetaObject(PythonQtClassWrapper* type, const QMetaObject* prototypeMetaObject)
1946+
const QMetaObject* PythonQtPrivate::setupDynamicMetaObjectChain(PythonQtClassWrapper* type, const QMetaObject* prototypeMetaObject)
19471947
{
1948+
if (!type->_dynamicClassInfo->_dynamicMetaObject) {
1949+
PyTypeObject* superType = ((PyTypeObject *)type)->tp_base;
1950+
const QMetaObject* metaObjectOfParent = prototypeMetaObject;
1951+
if (((PythonQtClassWrapper*)superType)->_dynamicClassInfo) {
1952+
metaObjectOfParent = setupDynamicMetaObjectChain((PythonQtClassWrapper*)superType, prototypeMetaObject);
1953+
}
1954+
return buildDynamicMetaObject(type, metaObjectOfParent);
1955+
} else {
1956+
return type->_dynamicClassInfo->_dynamicMetaObject;
1957+
}
1958+
}
1959+
1960+
const QMetaObject* PythonQtPrivate::buildDynamicMetaObject(PythonQtClassWrapper* type, const QMetaObject* prototypeMetaObject)
1961+
{
1962+
//std::cout << "creating " << ((PyTypeObject*)type)->tp_name << " derived from " << prototypeMetaObject->className() << std::endl;
1963+
19481964
QMetaObjectBuilder builder;
19491965
builder.setSuperClass(prototypeMetaObject);
19501966
builder.setClassName(((PyTypeObject*)type)->tp_name);
@@ -2029,6 +2045,7 @@ void PythonQtPrivate::buildDynamicMetaObject(PythonQtClassWrapper* type, const Q
20292045
// we don't need an own meta object, just use the one from our base class
20302046
type->_dynamicClassInfo->_dynamicMetaObject = prototypeMetaObject;
20312047
}
2048+
return type->_dynamicClassInfo->_dynamicMetaObject;
20322049
}
20332050

20342051

src/PythonQt.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,11 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
742742
//! get the dynamic meta object for the given wrapper. It will contain the signals/slots that have been added in Python
743743
const QMetaObject* getDynamicMetaObject(PythonQtInstanceWrapper* wrapper, const QMetaObject* prototypeMetaObject);
744744

745-
void buildDynamicMetaObject(PythonQtClassWrapper* type, const QMetaObject* prototypeMetaObject);
745+
//! recursively creates the dynamic meta object chain down to the Qt class wrapper.
746+
const QMetaObject* setupDynamicMetaObjectChain(PythonQtClassWrapper* type, const QMetaObject* prototypeMetaObject);
747+
748+
//! builds and returns the dynamic meta object for the given type, derived from prototypeMetaObject.
749+
const QMetaObject* buildDynamicMetaObject(PythonQtClassWrapper* type, const QMetaObject* prototypeMetaObject);
746750

747751
//! redirected from shell classes, tries to call the given meta call on the Python wrapper.
748752
int handleMetaCall(QObject* object, PythonQtInstanceWrapper* wrapper, QMetaObject::Call call, int id, void** args);

src/PythonQtClassInfo.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -738,14 +738,14 @@ QObject* PythonQtClassInfo::decorator()
738738
_decoratorProvider->setParent(PythonQt::priv());
739739
// setup enums early, since they might be needed by the constructor decorators:
740740
if (!_enumsCreated) {
741-
createEnumWrappers();
741+
createEnumWrappers(_decoratorProvider);
742742
}
743743
PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
744744
}
745745
}
746746
// check if enums need to be created and create them if they are not yet created
747747
if (!_enumsCreated) {
748-
createEnumWrappers();
748+
createEnumWrappers(_decoratorProvider);
749749
}
750750
return _decoratorProvider;
751751
}
@@ -857,26 +857,30 @@ void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
857857
}
858858
}
859859

860-
void PythonQtClassInfo::createEnumWrappers()
860+
void PythonQtClassInfo::createEnumWrappers(const QObject* decoratorProvider)
861861
{
862862
if (!_enumsCreated) {
863863
_enumsCreated = true;
864864
if (_meta) {
865865
createEnumWrappers(_meta);
866866
}
867-
if (decorator()) {
868-
createEnumWrappers(decorator()->metaObject());
867+
if (decoratorProvider) {
868+
createEnumWrappers(decoratorProvider->metaObject());
869869
}
870870
Q_FOREACH(const ParentClassInfo& info, _parentClasses) {
871-
info._parent->createEnumWrappers();
871+
// trigger decorator() instead of createEnumWrappers(),
872+
// which will then call createEnumWrappers().
873+
info._parent->decorator();
872874
}
873875
}
874876
}
875877

876878
PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
877879
// force enum creation
878880
if (!_enumsCreated) {
879-
createEnumWrappers();
881+
// trigger decorator() instead of createEnumWrappers(),
882+
// which will then call createEnumWrappers().
883+
decorator();
880884
}
881885
Q_FOREACH(const PythonQtObjectPtr& p, _enumWrappers) {
882886
const char* className = ((PyTypeObject*)p.object())->tp_name;

src/PythonQtClassInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo {
239239
private:
240240
void updateRefCountingCBs();
241241

242-
void createEnumWrappers();
242+
void createEnumWrappers(const QObject* decoratorProvider);
243243
void createEnumWrappers(const QMetaObject* meta);
244244
PyObject* findEnumWrapper(const char* name);
245245

src/PythonQtClassWrapper.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,17 @@ static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args,
366366

367367
// take the class info from the superType
368368
self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
369-
370369
self->_dynamicClassInfo = new PythonQtDynamicClassInfo();
370+
371+
// take the class info from the superType and fill the whole chain
372+
PyTypeObject* typeChain = (PyTypeObject *)self;
373+
while (typeChain && Py_TYPE(typeChain) != &PythonQtClassWrapper_Type) {
374+
375+
((PythonQtClassWrapper*)typeChain)->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
376+
((PythonQtClassWrapper*)typeChain)->_dynamicClassInfo = new PythonQtDynamicClassInfo();
377+
378+
typeChain = typeChain->tp_base;
379+
}
371380
}
372381

373382
return 0;

src/PythonQtConversion.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,8 +1153,11 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
11531153
pythonToMapVariant<QVariantHash>(val, v);
11541154
break;
11551155
case QVariant::List:
1156-
if (PySequence_Check(val)) {
1157-
if (_pythonSequenceToQVariantListCB) {
1156+
{
1157+
bool isListOrTuple = PyList_Check(val) || PyTuple_Check(val);
1158+
if (isListOrTuple || PySequence_Check(val)) {
1159+
if (!isListOrTuple && _pythonSequenceToQVariantListCB) {
1160+
// Only call this if we don't have a tuple or list.
11581161
QVariant result = (*_pythonSequenceToQVariantListCB)(val);
11591162
if (result.isValid()) {
11601163
return result;
@@ -1165,14 +1168,15 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
11651168
// only get items if size is valid (>= 0)
11661169
QVariantList list;
11671170
PyObject* value;
1168-
for (int i = 0;i<count;i++) {
1169-
value = PySequence_GetItem(val,i);
1171+
for (int i = 0; i < count; i++) {
1172+
value = PySequence_GetItem(val, i);
11701173
list.append(PyObjToQVariant(value, -1));
11711174
Py_XDECREF(value);
11721175
}
11731176
v = list;
11741177
}
11751178
}
1179+
}
11761180
break;
11771181
case QVariant::StringList:
11781182
{

src/PythonQtInstanceWrapper.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -452,12 +452,21 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
452452
wrapper->_obj->metaObject();
453453
}
454454
}
455-
if (wrapper->dynamicClassInfo() && wrapper->dynamicClassInfo()->_classInfo) {
456-
PythonQtMemberInfo member = wrapper->dynamicClassInfo()->_classInfo->member(attributeName);
457-
if (member._type == PythonQtMemberInfo::Signal) {
458-
PyObject* boundSignal = PythonQtSignalFunction_New(member._slot, (PyObject*)wrapper, NULL);
459-
Py_DECREF(superAttr);
460-
return boundSignal;
455+
if (wrapper->dynamicClassInfo()) {
456+
// go through the whole inheritance chain to find a signal in the dynamic class info:
457+
PythonQtClassInfo* classInfo = NULL;
458+
PythonQtClassWrapper* classType = (PythonQtClassWrapper*)Py_TYPE(wrapper);
459+
while (classType->_dynamicClassInfo) {
460+
classInfo = classType->_dynamicClassInfo->_classInfo;
461+
if (classInfo) {
462+
PythonQtMemberInfo member = classInfo->member(attributeName);
463+
if (member._type == PythonQtMemberInfo::Signal) {
464+
PyObject* boundSignal = PythonQtSignalFunction_New(member._slot, (PyObject*)wrapper, NULL);
465+
Py_DECREF(superAttr);
466+
return boundSignal;
467+
}
468+
}
469+
classType = (PythonQtClassWrapper*)(((PyTypeObject*)classType)->tp_base);
461470
}
462471
}
463472
}

0 commit comments

Comments
 (0)