Skip to content

Commit 5d6675b

Browse files
committed
updated to upstream state in MeVisLab repository
1 parent 13fad06 commit 5d6675b

20 files changed

+339
-126
lines changed

src/PythonQt.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
8080

8181
PythonQt_init_QtCoreBuiltin(NULL);
8282
PythonQt_init_QtGuiBuiltin(NULL);
83-
83+
8484
PythonQtRegisterToolClassesTemplateConverter(QByteArray);
8585
PythonQtRegisterToolClassesTemplateConverter(QDate);
8686
PythonQtRegisterToolClassesTemplateConverter(QTime);
@@ -157,7 +157,7 @@ PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
157157
}
158158
Py_Initialize();
159159
}
160-
160+
161161
// add our own python object types for qt object slots
162162
if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
163163
std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
@@ -245,6 +245,14 @@ void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* p
245245
PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
246246
info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
247247
}
248+
} else if (first && module) {
249+
// There is a wrapper already, but if we got a module, we want to place the wrapper into that module as well,
250+
// since it might have been placed into "private" earlier on.
251+
// If the wrapper was already added to module before, it is just readded, which does no harm.
252+
PyObject* classWrapper = info->pythonQtClassWrapper();
253+
// AddObject steals a reference, so we need to INCREF
254+
Py_INCREF(classWrapper);
255+
PyModule_AddObject(module, info->className(), classWrapper);
248256
}
249257
if (first) {
250258
first = false;
@@ -913,6 +921,7 @@ PythonQtPrivate::PythonQtPrivate()
913921
_noLongerWrappedCB = NULL;
914922
_wrappedCB = NULL;
915923
_currentClassInfoForClassWrapperCreation = NULL;
924+
_profilingCB = NULL;
916925
}
917926

918927
void PythonQtPrivate::setupSharedLibrarySuffixes()
@@ -922,6 +931,14 @@ void PythonQtPrivate::setupSharedLibrarySuffixes()
922931
imp.setNewRef(PyImport_ImportModule("imp"));
923932
int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
924933
QVariant result = imp.call("get_suffixes");
934+
#ifdef __linux
935+
#ifdef _DEBUG
936+
// First look for shared libraries with the '_d' suffix in debug mode on Linux.
937+
// This is a workaround, because python does not append the '_d' suffix on Linux
938+
// and would always load the release library otherwise.
939+
_sharedLibrarySuffixes << "_d.so";
940+
#endif
941+
#endif
925942
foreach (QVariant entry, result.toList()) {
926943
QVariantList suffixEntry = entry.toList();
927944
if (suffixEntry.count()==3) {
@@ -1066,6 +1083,10 @@ void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedC
10661083
_p->_noLongerWrappedCB = cb;
10671084
}
10681085

1086+
void PythonQt::setProfilingCallback(ProfilingCB* cb)
1087+
{
1088+
_p->_profilingCB = cb;
1089+
}
10691090

10701091

10711092
static PyMethodDef PythonQtMethods[] = {
@@ -1080,7 +1101,7 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ
10801101
}
10811102
_p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
10821103
_p->_pythonQtModuleName = name;
1083-
1104+
10841105
if (redirectStdOut) {
10851106
PythonQtObjectPtr sys;
10861107
PythonQtObjectPtr out;
@@ -1194,6 +1215,13 @@ PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
11941215
}
11951216
}
11961217

1218+
void PythonQt::clearNotFoundCachedMembers()
1219+
{
1220+
foreach(PythonQtClassInfo* info, _p->_knownClassInfos) {
1221+
info->clearNotFoundCachedMembers();
1222+
}
1223+
}
1224+
11971225
void PythonQtPrivate::removeWrapperPointer(void* obj)
11981226
{
11991227
_wrappedObjects.remove(obj);

src/PythonQt.h

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtI
7575

7676
//! returns the offset that needs to be added to upcast an object of type T1 to T2
7777
template<class T1, class T2> int PythonQtUpcastingOffset() {
78-
return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
78+
return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
7979
}
8080

8181
//! callback to create a QObject lazily
@@ -143,10 +143,20 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
143143

144144
};
145145

146+
//! enum for profiling callback
147+
enum ProfilingCallbackState {
148+
Enter = 1,
149+
Leave = 2
150+
};
151+
152+
//! callback for profiling. className and methodName are only passed when state == Enter, otherwise
153+
//! they are NULL.
154+
typedef void ProfilingCB(ProfilingCallbackState state, const char* className, const char* methodName);
155+
146156
//---------------------------------------------------------------------------
147157
//! \name Singleton Initialization
148158
//@{
149-
159+
150160
//! initialize the python qt binding (flags are a or combination of PythonQt::InitFlags), if \c pythonQtModuleName is given
151161
//! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
152162
//! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
@@ -159,7 +169,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
159169
static PythonQt* self() { return _self; }
160170

161171
//@}
162-
172+
163173
//! defines the object types for introspection
164174
enum ObjectType {
165175
Class,
@@ -186,13 +196,13 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
186196
//! to a module later on.
187197
//! The user needs to make sure that the \c name is unique in the python module dictionary.
188198
PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
189-
199+
190200
//! creates the new module \c name and evaluates the given script in the context of that module.
191201
//! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
192202
//! to a module later on.
193203
//! The user needs to make sure that the \c name is unique in the python module dictionary.
194204
PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
195-
205+
196206
//! create a uniquely named module, you can use evalFile or evalScript to populate the module with
197207
//! script code
198208
PythonQtObjectPtr createUniqueModule();
@@ -213,20 +223,20 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
213223
void setModuleImportPath(PyObject* module, const QStringList& paths);
214224

215225
//@}
216-
226+
217227
//---------------------------------------------------------------------------
218228
//! \name Registering Classes
219229
//@{
220-
230+
221231
//! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
222232
/* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
223233
you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
224234
void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
225-
235+
226236
//! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
227237
//! (ownership of wrapper is passed to PythonQt)
228238
/*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
229-
239+
230240
This will add a wrapper object that is used to make calls to the given classname \c typeName.
231241
All slots that take a pointer to typeName as the first argument will be callable from Python on
232242
a variant object that contains such a type.
@@ -251,7 +261,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
251261
//---------------------------------------------------------------------------
252262
//! \name Script Parsing and Evaluation
253263
//@{
254-
264+
255265
//! parses the given file and returns the python code object, this can then be used to call evalCode()
256266
PythonQtObjectPtr parseFile(const QString& filename);
257267

@@ -287,7 +297,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
287297

288298
//---------------------------------------------------------------------------
289299
//! \name Variable access
290-
//@{
300+
//@{
291301

292302
//! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
293303
void addObject(PyObject* object, const QString& name, QObject* qObject);
@@ -312,7 +322,7 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
312322

313323
//---------------------------------------------------------------------------
314324
//! \name Calling Python Objects
315-
//@{
325+
//@{
316326

317327
//! call the given python \c callable in the scope of object, returns the result converted to a QVariant
318328
QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
@@ -385,10 +395,10 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
385395
//---------------------------------------------------------------------------
386396
//! \name Custom Importer
387397
//@{
388-
398+
389399
//! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
390400
//! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
391-
//! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
401+
//! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
392402
//! This is not reversible, so even setting setImporter(NULL) afterwards will
393403
//! keep the custom PythonQt importer with a QFile default import interface.
394404
//! Subsequent python import calls will make use of the passed importInterface
@@ -427,6 +437,10 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
427437
//! The error is currently just output to the python stderr, future version might implement better trace printing
428438
bool handleError();
429439

440+
//! clear all NotFound entries on all class infos, to ensure that
441+
//! newly loaded wrappers can add methods even when the object was wrapped by PythonQt before the wrapper was loaded
442+
void clearNotFoundCachedMembers();
443+
430444
//! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
431445
void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
432446
//! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
@@ -437,11 +451,14 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
437451

438452
//! called by internal help methods
439453
PyObject* helpCalled(PythonQtClassInfo* info);
440-
454+
441455
//! returns the found object or NULL
442456
//! @return new reference
443457
PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
444458

459+
//! sets a callback that is called before and after function calls for profiling
460+
void setProfilingCallback(ProfilingCB* cb);
461+
445462
//@}
446463

447464
signals:
@@ -507,7 +524,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
507524

508525
//! add a handler for polymorphic downcasting
509526
void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
510-
527+
511528
//! lookup existing classinfo and return new if not yet present
512529
PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
513530

@@ -528,13 +545,13 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
528545
//! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
529546
//! (ownership of wrapper is passed to PythonQt)
530547
/*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
531-
548+
532549
This will add a wrapper object that is used to make calls to the given classname \c typeName.
533550
All slots that take a pointer to typeName as the first argument will be callable from Python on
534551
a variant object that contains such a type.
535552
*/
536553
void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
537-
554+
538555
//! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
539556
//! and it will register the classes when it first sees a pointer to such a derived class
540557
void registerQObjectClassNames(const QStringList& names);
@@ -571,10 +588,13 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
571588

572589
//! called by virtual overloads when a python return value can not be converted to the required Qt type
573590
void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
574-
591+
575592
//! get access to the PythonQt module
576593
PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
577594

595+
//! returns the profiling callback, which may be NULL
596+
PythonQt::ProfilingCB* profilingCB() const { return _profilingCB; }
597+
578598
private:
579599
//! Setup the shared library suffixes by getting them from the "imp" module.
580600
void setupSharedLibrarySuffixes();
@@ -605,13 +625,13 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
605625

606626
//! the name of the PythonQt python module
607627
QByteArray _pythonQtModuleName;
608-
628+
609629
//! the importer interface (if set)
610630
PythonQtImportFileInterface* _importInterface;
611631

612632
//! the default importer
613633
PythonQtQFileImporter* _defaultImporter;
614-
634+
615635
PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
616636
PythonQtQObjectWrappedCB* _wrappedCB;
617637

@@ -625,6 +645,8 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
625645

626646
PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
627647

648+
PythonQt::ProfilingCB* _profilingCB;
649+
628650
int _initFlags;
629651
int _PythonQtObjectPtr_metaId;
630652

src/PythonQtClassInfo.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,3 +847,22 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
847847
return NULL;
848848
}
849849

850+
void PythonQtClassInfo::setDecoratorProvider( PythonQtQObjectCreatorFunctionCB* cb )
851+
{
852+
_decoratorProviderCB = cb;
853+
_decoratorProvider = NULL;
854+
_enumsCreated = false;
855+
}
856+
857+
void PythonQtClassInfo::clearNotFoundCachedMembers()
858+
{
859+
// remove all not found entries, since a new decorator means new slots,
860+
// which might have been cached as "NotFound" already.
861+
QMutableHashIterator<QByteArray, PythonQtMemberInfo> it(_cachedMembers);
862+
while (it.hasNext()) {
863+
it.next();
864+
if (it.value()._type == PythonQtMemberInfo::NotFound) {
865+
it.remove();
866+
}
867+
}
868+
}

src/PythonQtClassInfo.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo {
166166
int metaTypeId() { return _metaTypeId; }
167167

168168
//! set an additional decorator provider that offers additional decorator slots for this class
169-
void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) { _decoratorProviderCB = cb; _decoratorProvider = NULL; }
169+
void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb);
170170

171171
//! get the decorator qobject instance
172172
QObject* decorator();
@@ -201,7 +201,10 @@ class PYTHONQT_EXPORT PythonQtClassInfo {
201201

202202
//! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
203203
static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
204-
204+
205+
//! clear all members that where cached as "NotFound"
206+
void clearNotFoundCachedMembers();
207+
205208
private:
206209
void createEnumWrappers();
207210
void createEnumWrappers(const QMetaObject* meta);
@@ -225,7 +228,7 @@ class PYTHONQT_EXPORT PythonQtClassInfo {
225228

226229
PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
227230
int findCharOffset(const char* sigStart, char someChar);
228-
231+
229232
QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
230233

231234
PythonQtSlotInfo* _constructors;

0 commit comments

Comments
 (0)