Skip to content

Commit 6f219bf

Browse files
author
florianlink
committed
merged various improvements from MeVisLab repository
- support for properties on class wrappers - support for return type completion on jedi library (using __doc__ of methods) - auto importing known packages when classname appears on interface - support of intrusive ref-counting for OpenInventor (and other ref counted libraries) - and other small details git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@372 ea8d5007-eb21-0410-b261-ccb3ea6e24a9
1 parent 42e1dfa commit 6f219bf

13 files changed

+697
-192
lines changed

src/PythonQt.cpp

Lines changed: 105 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@
5353
#include "PythonQtStdDecorators.h"
5454
#include "PythonQtQFileImporter.h"
5555
#include "PythonQtBoolResult.h"
56+
57+
#include <QDir>
58+
5659
#include <pydebug.h>
5760
#include <vector>
5861

@@ -63,18 +66,17 @@ void PythonQt_init_QtGuiBuiltin(PyObject*);
6366
void PythonQt_init_QtCoreBuiltin(PyObject*);
6467

6568

66-
PyObject* PythonQtConvertFromStringRef(const void* inObject, int /*metaTypeId*/)
67-
{
68-
return PythonQtConv::QStringToPyObject(((QStringRef*)inObject)->toString());
69-
}
70-
7169
void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
7270
{
7371
if (!_self) {
7472
_self = new PythonQt(flags, pythonQtModuleName);
7573

7674
PythonQt::priv()->setupSharedLibrarySuffixes();
7775

76+
_self->_p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
77+
PythonQtConv::registerMetaTypeToPythonConverter(_self->_p->_PythonQtObjectPtr_metaId, PythonQtConv::convertFromPythonQtObjectPtr);
78+
PythonQtConv::registerPythonToMetaTypeConverter(_self->_p->_PythonQtObjectPtr_metaId, PythonQtConv::convertToPythonQtObjectPtr);
79+
7880
PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
7981
qRegisterMetaType<QList<QObject*> >("QList<void*>");
8082
qRegisterMetaType<QObjectList>("QObjectList");
@@ -85,7 +87,11 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
8587
qRegisterMetaType<quint32>("size_t");
8688
}
8789
int stringRefId = qRegisterMetaType<QStringRef>("QStringRef");
88-
PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConvertFromStringRef);
90+
PythonQtConv::registerMetaTypeToPythonConverter(stringRefId, PythonQtConv::convertFromStringRef);
91+
92+
int objectPtrListId = qRegisterMetaType<QList<PythonQtObjectPtr> >("QList<PythonQtObjectPtr>");
93+
PythonQtConv::registerMetaTypeToPythonConverter(objectPtrListId, PythonQtConv::convertFromQListOfPythonQtObjectPtr);
94+
PythonQtConv::registerPythonToMetaTypeConverter(objectPtrListId, PythonQtConv::convertToQListOfPythonQtObjectPtr);
8995

9096
PythonQtRegisterToolClassesTemplateConverter(int);
9197
PythonQtRegisterToolClassesTemplateConverter(float);
@@ -250,8 +256,6 @@ PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
250256
_p = new PythonQtPrivate;
251257
_p->_initFlags = flags;
252258

253-
_p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
254-
255259
if ((flags & PythonAlreadyInitialized) == 0) {
256260
#ifdef PY3K
257261
Py_SetProgramName(const_cast<wchar_t*>(L"PythonQt"));
@@ -491,7 +495,7 @@ PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
491495
return (PyObject*)wrap;
492496
}
493497

494-
PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
498+
PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name, bool passOwnership)
495499
{
496500
if (!ptr) {
497501
Py_INCREF(Py_None);
@@ -510,7 +514,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
510514
wrap = NULL;
511515
}
512516
if (!wrap) {
513-
PythonQtClassInfo* info = _knownClassInfos.value(name);
517+
PythonQtClassInfo* info = getClassInfo(name);
514518
if (!info) {
515519
// maybe it is a PyObject, which we can return directly
516520
if (name == "PyObject") {
@@ -538,6 +542,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
538542
}
539543
}
540544
wrap = createNewPythonQtInstanceWrapper(qptr, info);
545+
wrap->_ownedByPythonQt = passOwnership;
541546
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
542547
return (PyObject*)wrap;
543548
}
@@ -574,6 +579,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
574579
info = _knownClassInfos.value(qptr->metaObject()->className());
575580
}
576581
wrap = createNewPythonQtInstanceWrapper(qptr, info);
582+
wrap->_ownedByPythonQt = passOwnership;
577583
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
578584
return (PyObject*)wrap;
579585
}
@@ -594,6 +600,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
594600
Py_INCREF(wrap);
595601
} else {
596602
wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
603+
wrap->_ownedByPythonQt = passOwnership;
597604
}
598605
// mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
599606
} else {
@@ -622,13 +629,22 @@ PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObje
622629
result->_ownedByPythonQt = false;
623630
result->_useQMetaTypeDestroy = false;
624631

625-
if (wrappedPtr) {
626-
_wrappedObjects.insert(wrappedPtr, result);
627-
} else {
628-
_wrappedObjects.insert(obj, result);
629-
if (obj->parent()== NULL && _wrappedCB) {
630-
// tell someone who is interested that the qobject is wrapped the first time, if it has no parent
631-
(*_wrappedCB)(obj);
632+
if (wrappedPtr || obj) {
633+
634+
// if this object is reference counted, we ref it:
635+
PythonQtVoidPtrCB* refCB = info->referenceCountingRefCB();
636+
if (refCB) {
637+
(*refCB)(wrappedPtr);
638+
}
639+
640+
if (wrappedPtr) {
641+
_wrappedObjects.insert(wrappedPtr, result);
642+
} else {
643+
_wrappedObjects.insert(obj, result);
644+
if (obj->parent()== NULL && _wrappedCB) {
645+
// tell someone who is interested that the qobject is wrapped the first time, if it has no parent
646+
(*_wrappedCB)(obj);
647+
}
632648
}
633649
}
634650
return result;
@@ -980,27 +996,15 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
980996
if (type == CallOverloads) {
981997
if (PythonQtSlotFunction_Check(object)) {
982998
PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object;
983-
PythonQtSlotInfo* info = o->m_ml;
984-
985-
while (info) {
986-
results << info->fullSignature();
987-
info = info->nextInfo();
988-
}
999+
results = o->m_ml->overloads();
9891000
} else if (PythonQtSignalFunction_Check(object)) {
9901001
PythonQtSignalFunctionObject* o = (PythonQtSignalFunctionObject*)object;
991-
PythonQtSlotInfo* info = o->m_ml;
992-
993-
while (info) {
994-
results << info->fullSignature();
995-
info = info->nextInfo();
996-
}
1002+
results = o->m_ml->overloads();
9971003
} else if (object->ob_type == &PythonQtClassWrapper_Type) {
9981004
PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
9991005
PythonQtSlotInfo* info = o->classInfo()->constructors();
1000-
1001-
while (info) {
1002-
results << info->fullSignature();
1003-
info = info->nextInfo();
1006+
if (info) {
1007+
results = info->overloads(/*skipReturnValue = */ true);
10041008
}
10051009
} else {
10061010
QString signature = _p->getSignature(object);
@@ -1009,8 +1013,16 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
10091013
} else {
10101014
PyObject* doc = PyObject_GetAttrString(object, "__doc__");
10111015
if (doc) {
1012-
results << PyString_AsString(doc);
1016+
QString docString = QString::fromUtf8(PyString_AsString(doc));
10131017
Py_DECREF(doc);
1018+
int idx = docString.indexOf("\n");
1019+
if (idx != -1) {
1020+
docString = docString.mid(0, idx);
1021+
}
1022+
// if the first line contains a "(", take it as a signature
1023+
if (docString.contains("(")) {
1024+
results << docString;
1025+
}
10141026
}
10151027
}
10161028
}
@@ -1086,13 +1098,6 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
10861098
}
10871099
Py_DECREF(keys);
10881100
}
1089-
if ((type == Anything) || (type == Variable)) {
1090-
if (object->ob_type == &PythonQtClassWrapper_Type) {
1091-
PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
1092-
PythonQtClassInfo* info = o->classInfo();
1093-
results += info->propertyList();
1094-
}
1095-
}
10961101
}
10971102
return results;
10981103
}
@@ -1511,7 +1516,13 @@ void PythonQt::overwriteSysPath(const QStringList& paths)
15111516
{
15121517
PythonQtObjectPtr sys;
15131518
sys.setNewRef(PyImport_ImportModule("sys"));
1514-
PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1519+
// Since Python uses os.path.sep at various places,
1520+
// makse sure that we use the native path separators.
1521+
QStringList nativePaths;
1522+
foreach(QString path, paths) {
1523+
nativePaths << QDir::toNativeSeparators(path);
1524+
}
1525+
PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(nativePaths));
15151526
}
15161527

15171528
void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
@@ -1592,7 +1603,6 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ
15921603
if (redirectStdOut) {
15931604
PythonQtObjectPtr out;
15941605
PythonQtObjectPtr err;
1595-
sys.setNewRef(PyImport_ImportModule("sys"));
15961606
// create a redirection object for stdout and stderr
15971607
out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
15981608
((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
@@ -1626,13 +1636,12 @@ QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString&
16261636
QStringList tmp = name.split(".");
16271637
QString methodName = tmp.takeLast();
16281638
QString variableName = tmp.join(".");
1629-
// TODO: the variableName may be a type name, this needs to be handled differently,
1630-
// because it is not necessarily known in the module context
16311639
PythonQtObjectPtr variableObject = lookupObject(module, variableName);
16321640
if (variableObject.isNull()) {
1633-
return "";
1641+
// try lookup by interpreting the variableName as a type
1642+
QString type = getReturnTypeOfWrappedMethod(variableName, methodName);
1643+
return type;
16341644
}
1635-
16361645
return getReturnTypeOfWrappedMethodHelper(variableObject, methodName, name);
16371646
}
16381647

@@ -1664,53 +1673,24 @@ QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& va
16641673
// a constructor is called. Return the context.
16651674
type = context;
16661675
} else if (methodObject->ob_type == &PythonQtSlotFunction_Type) {
1667-
QString className;
1668-
1669-
if (PyObject_TypeCheck(variableObject, &PythonQtInstanceWrapper_Type)) {
1670-
// the type name of wrapped instance is the class name
1671-
className = variableObject->ob_type->tp_name;
1672-
} else {
1673-
PyObject* classNameObject = PyObject_GetAttrString(variableObject, "__name__");
1674-
if (classNameObject) {
1675-
Q_ASSERT(PyString_Check(classNameObject));
1676-
className = PyString_AsString(classNameObject);
1677-
Py_DECREF(classNameObject);
1678-
}
1679-
}
1680-
1681-
if (!className.isEmpty()) {
1682-
PythonQtClassInfo* info = _p->_knownClassInfos.value(className.toLatin1().constData());
1683-
if (info) {
1684-
PythonQtSlotInfo* slotInfo = info->member(methodName.toLatin1().constData())._slot;
1685-
if (slotInfo) {
1686-
if (slotInfo->metaMethod()) {
1687-
type = PythonQtUtils::typeName(*slotInfo->metaMethod());
1688-
if (!type.isEmpty()) {
1689-
QChar c = type.at(type.length()-1);
1690-
while (c == '*' || c == '&') {
1691-
type.truncate(type.length()-1);
1692-
if (!type.isEmpty()) {
1693-
c = type.at(type.length()-1);
1694-
} else {
1695-
break;
1696-
}
1697-
}
1698-
// split away template arguments
1699-
type = type.split("<").first();
1700-
// split away const
1701-
type = type.split(" ").last().trimmed();
1702-
1703-
// if the type is a known class info, then create the full type name, i.e. include the
1704-
// module name. For example, the slot may return a QDate, then this looks up the
1705-
// name _PythonQt.QtCore.QDate.
1706-
PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1707-
if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1708-
PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1709-
Q_ASSERT(PyString_Check(s));
1710-
type = QString(PyString_AsString(s)) + "." + type;
1711-
Py_DECREF(s);
1712-
}
1713-
}
1676+
PythonQtSlotInfo* slotInfo = ((PythonQtSlotFunctionObject*)methodObject.object())->m_ml;
1677+
if (slotInfo) {
1678+
if (slotInfo->parameterCount()>0) {
1679+
type = slotInfo->parameters().at(0).name;
1680+
if (type.contains("<")) {
1681+
// can't handle templates
1682+
type = "";
1683+
}
1684+
if (!type.isEmpty()) {
1685+
// if the type is a known class info, then create the full type name, i.e. include the
1686+
// module name. For example, the slot may return a QDate, then this looks up the
1687+
// name _PythonQt.QtCore.QDate.
1688+
PythonQtClassInfo* typeInfo = _p->_knownClassInfos.value(type.toLatin1().constData());
1689+
if (typeInfo && typeInfo->pythonQtClassWrapper()) {
1690+
PyObject* s = PyObject_GetAttrString(typeInfo->pythonQtClassWrapper(), "__module__");
1691+
Q_ASSERT(PyString_Check(s));
1692+
type = QString(PyString_AsString(s)) + "." + type;
1693+
Py_DECREF(s);
17141694
}
17151695
}
17161696
}
@@ -2062,3 +2042,34 @@ PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
20622042
return PyBuffer_FromReadWriteMemory((char*)data, size);
20632043
#endif
20642044
}
2045+
2046+
PythonQtClassInfo* PythonQtPrivate::getClassInfo( const QMetaObject* meta )
2047+
{
2048+
return getClassInfo(QByteArray(meta->className()));
2049+
}
2050+
2051+
PythonQtClassInfo* PythonQtPrivate::getClassInfo( const QByteArray& className )
2052+
{
2053+
PythonQtClassInfo* result = _knownClassInfos.value(className);
2054+
if (!result) {
2055+
static bool recursion = false;
2056+
if (!recursion) {
2057+
if (_knownLazyClasses.contains(className)) {
2058+
QByteArray module = _knownLazyClasses.value(className);
2059+
recursion = true;
2060+
PyImport_ImportModule(module);
2061+
recursion = false;
2062+
result = _knownClassInfos.value(className);
2063+
if (!result) {
2064+
std::cerr << "PythonQt lazy import " << module.constData() << " did not resolve " << className.constData() <<std::endl;
2065+
}
2066+
}
2067+
}
2068+
}
2069+
return result;
2070+
}
2071+
2072+
void PythonQtPrivate::registerLazyClass( const QByteArray& name, const QByteArray& moduleToImport )
2073+
{
2074+
_knownLazyClasses.insert(name, moduleToImport);
2075+
}

0 commit comments

Comments
 (0)