53
53
#include " PythonQtStdDecorators.h"
54
54
#include " PythonQtQFileImporter.h"
55
55
#include " PythonQtBoolResult.h"
56
+
57
+ #include < QDir>
58
+
56
59
#include < pydebug.h>
57
60
#include < vector>
58
61
@@ -63,18 +66,17 @@ void PythonQt_init_QtGuiBuiltin(PyObject*);
63
66
void PythonQt_init_QtCoreBuiltin (PyObject*);
64
67
65
68
66
- PyObject* PythonQtConvertFromStringRef (const void * inObject, int /* metaTypeId*/ )
67
- {
68
- return PythonQtConv::QStringToPyObject (((QStringRef*)inObject)->toString ());
69
- }
70
-
71
69
void PythonQt::init (int flags, const QByteArray& pythonQtModuleName)
72
70
{
73
71
if (!_self) {
74
72
_self = new PythonQt (flags, pythonQtModuleName);
75
73
76
74
PythonQt::priv ()->setupSharedLibrarySuffixes ();
77
75
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
+
78
80
PythonQtMethodInfo::addParameterTypeAlias (" QObjectList" , " QList<QObject*>" );
79
81
qRegisterMetaType<QList<QObject*> >(" QList<void*>" );
80
82
qRegisterMetaType<QObjectList>(" QObjectList" );
@@ -85,7 +87,11 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
85
87
qRegisterMetaType<quint32>(" size_t" );
86
88
}
87
89
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);
89
95
90
96
PythonQtRegisterToolClassesTemplateConverter (int );
91
97
PythonQtRegisterToolClassesTemplateConverter (float );
@@ -250,8 +256,6 @@ PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
250
256
_p = new PythonQtPrivate;
251
257
_p->_initFlags = flags;
252
258
253
- _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>(" PythonQtObjectPtr" );
254
-
255
259
if ((flags & PythonAlreadyInitialized) == 0 ) {
256
260
#ifdef PY3K
257
261
Py_SetProgramName (const_cast <wchar_t *>(L" PythonQt" ));
@@ -491,7 +495,7 @@ PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
491
495
return (PyObject*)wrap;
492
496
}
493
497
494
- PyObject* PythonQtPrivate::wrapPtr (void * ptr, const QByteArray& name)
498
+ PyObject* PythonQtPrivate::wrapPtr (void * ptr, const QByteArray& name, bool passOwnership )
495
499
{
496
500
if (!ptr) {
497
501
Py_INCREF (Py_None);
@@ -510,7 +514,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
510
514
wrap = NULL ;
511
515
}
512
516
if (!wrap) {
513
- PythonQtClassInfo* info = _knownClassInfos. value (name);
517
+ PythonQtClassInfo* info = getClassInfo (name);
514
518
if (!info) {
515
519
// maybe it is a PyObject, which we can return directly
516
520
if (name == " PyObject" ) {
@@ -538,6 +542,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
538
542
}
539
543
}
540
544
wrap = createNewPythonQtInstanceWrapper (qptr, info);
545
+ wrap->_ownedByPythonQt = passOwnership;
541
546
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
542
547
return (PyObject*)wrap;
543
548
}
@@ -574,6 +579,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
574
579
info = _knownClassInfos.value (qptr->metaObject ()->className ());
575
580
}
576
581
wrap = createNewPythonQtInstanceWrapper (qptr, info);
582
+ wrap->_ownedByPythonQt = passOwnership;
577
583
// mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
578
584
return (PyObject*)wrap;
579
585
}
@@ -594,6 +600,7 @@ PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
594
600
Py_INCREF (wrap);
595
601
} else {
596
602
wrap = createNewPythonQtInstanceWrapper (wrapper, info, ptr);
603
+ wrap->_ownedByPythonQt = passOwnership;
597
604
}
598
605
// mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
599
606
} else {
@@ -622,13 +629,22 @@ PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObje
622
629
result->_ownedByPythonQt = false ;
623
630
result->_useQMetaTypeDestroy = false ;
624
631
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
+ }
632
648
}
633
649
}
634
650
return result;
@@ -980,27 +996,15 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
980
996
if (type == CallOverloads) {
981
997
if (PythonQtSlotFunction_Check (object)) {
982
998
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 ();
989
1000
} else if (PythonQtSignalFunction_Check (object)) {
990
1001
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 ();
997
1003
} else if (object->ob_type == &PythonQtClassWrapper_Type) {
998
1004
PythonQtClassWrapper* o = (PythonQtClassWrapper*)object;
999
1005
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 );
1004
1008
}
1005
1009
} else {
1006
1010
QString signature = _p->getSignature (object);
@@ -1009,8 +1013,16 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
1009
1013
} else {
1010
1014
PyObject* doc = PyObject_GetAttrString (object, " __doc__" );
1011
1015
if (doc) {
1012
- results << PyString_AsString (doc);
1016
+ QString docString = QString::fromUtf8 ( PyString_AsString (doc) );
1013
1017
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
+ }
1014
1026
}
1015
1027
}
1016
1028
}
@@ -1086,13 +1098,6 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type)
1086
1098
}
1087
1099
Py_DECREF (keys);
1088
1100
}
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
- }
1096
1101
}
1097
1102
return results;
1098
1103
}
@@ -1511,7 +1516,13 @@ void PythonQt::overwriteSysPath(const QStringList& paths)
1511
1516
{
1512
1517
PythonQtObjectPtr sys;
1513
1518
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));
1515
1526
}
1516
1527
1517
1528
void PythonQt::setModuleImportPath (PyObject* module , const QStringList& paths)
@@ -1592,7 +1603,6 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ
1592
1603
if (redirectStdOut) {
1593
1604
PythonQtObjectPtr out;
1594
1605
PythonQtObjectPtr err;
1595
- sys.setNewRef (PyImport_ImportModule (" sys" ));
1596
1606
// create a redirection object for stdout and stderr
1597
1607
out = PythonQtStdOutRedirectType.tp_new (&PythonQtStdOutRedirectType,NULL , NULL );
1598
1608
((PythonQtStdOutRedirect*)out.object ())->_cb = stdOutRedirectCB;
@@ -1626,13 +1636,12 @@ QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString&
1626
1636
QStringList tmp = name.split (" ." );
1627
1637
QString methodName = tmp.takeLast ();
1628
1638
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
1631
1639
PythonQtObjectPtr variableObject = lookupObject (module , variableName);
1632
1640
if (variableObject.isNull ()) {
1633
- return " " ;
1641
+ // try lookup by interpreting the variableName as a type
1642
+ QString type = getReturnTypeOfWrappedMethod (variableName, methodName);
1643
+ return type;
1634
1644
}
1635
-
1636
1645
return getReturnTypeOfWrappedMethodHelper (variableObject, methodName, name);
1637
1646
}
1638
1647
@@ -1664,53 +1673,24 @@ QString PythonQt::getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr& va
1664
1673
// a constructor is called. Return the context.
1665
1674
type = context;
1666
1675
} 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);
1714
1694
}
1715
1695
}
1716
1696
}
@@ -2062,3 +2042,34 @@ PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size )
2062
2042
return PyBuffer_FromReadWriteMemory ((char *)data, size);
2063
2043
#endif
2064
2044
}
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