Skip to content

Commit 4d37db6

Browse files
committed
added changes from MeVisLab code base
1 parent cc2122e commit 4d37db6

File tree

7 files changed

+206
-32
lines changed

7 files changed

+206
-32
lines changed

src/PythonQt.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,27 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
101101
PythonQtRegisterToolClassesTemplateConverter(qint64);
102102
PythonQtRegisterToolClassesTemplateConverter(quint64);
103103

104+
#ifdef PYTHONQT_SUPPORT_ML_TYPES
105+
PythonQtMethodInfo::addParameterTypeAlias("QList<MLfloat>", "QList<float>");
106+
PythonQtMethodInfo::addParameterTypeAlias("QVector<MLfloat>", "QVector<float>");
107+
PythonQtMethodInfo::addParameterTypeAlias("QList<MLdouble>", "QList<double>");
108+
PythonQtMethodInfo::addParameterTypeAlias("QVector<MLdouble>", "QVector<double>");
109+
110+
PythonQtMethodInfo::addParameterTypeAlias("QList<MLuint32>", "QList<quint32>");
111+
PythonQtMethodInfo::addParameterTypeAlias("QVector<MLuint32>", "QVector<quint32>");
112+
PythonQtMethodInfo::addParameterTypeAlias("QList<MLint32>", "QList<qint32>");
113+
PythonQtMethodInfo::addParameterTypeAlias("QVector<MLint32>", "QVector<qint32>");
114+
115+
PythonQtMethodInfo::addParameterTypeAlias("QList<MLuint64>", "QList<quint64>");
116+
PythonQtMethodInfo::addParameterTypeAlias("QVector<MLuint64>", "QVector<quint64>");
117+
PythonQtMethodInfo::addParameterTypeAlias("QList<MLint64>", "QList<qint64>");
118+
PythonQtMethodInfo::addParameterTypeAlias("QVector<MLint64>", "QVector<qint64>");
119+
PythonQtMethodInfo::addParameterTypeAlias("QList<MLuint>", "QList<quint64>");
120+
PythonQtMethodInfo::addParameterTypeAlias("QVector<MLuint>", "QVector<quint64>");
121+
PythonQtMethodInfo::addParameterTypeAlias("QList<MLint>", "QList<qint64>");
122+
PythonQtMethodInfo::addParameterTypeAlias("QVector<MLint>", "QVector<qint64>");
123+
#endif
124+
104125
PythonQtMethodInfo::addParameterTypeAlias("QList<qreal>", "QList<double>");
105126
PythonQtMethodInfo::addParameterTypeAlias("QVector<qreal>", "QVector<double>");
106127
PythonQtMethodInfo::addParameterTypeAlias("QList<unsigned int>", "QList<quint32>");
@@ -891,6 +912,7 @@ PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
891912
clearError();
892913
if (!p) {
893914
handleError();
915+
_p->_hadError = true;
894916
}
895917
return p;
896918
}

src/PythonQtConversion.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include <QTime>
4747
#include <QDate>
4848
#include <climits>
49+
#include <limits>
4950

5051
PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
5152
PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
@@ -383,7 +384,9 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i
383384
return ptr;
384385
}
385386

386-
if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) && info.typeId != PythonQtMethodInfo::Variant) {
387+
if (PyObject_TypeCheck(obj, &PythonQtInstanceWrapper_Type) &&
388+
info.typeId != PythonQtMethodInfo::Variant &&
389+
!PythonQt::priv()->isPythonQtObjectPtrMetaId(info.typeId)) {
387390
// if we have a Qt wrapper object and if we do not need a QVariant, we do the following:
388391
// (the Variant case is handled below in a switch)
389392

@@ -984,7 +987,15 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
984987
type = QVariant::Int;
985988
#endif
986989
} else if (PyLong_Check(val)) {
987-
type = QVariant::LongLong;
990+
// return int if the value fits into that range,
991+
// otherwise it would not be possible to get an int from Python 3
992+
qint64 d = PyLong_AsLongLong(val);
993+
if (d > std::numeric_limits<int>::max() ||
994+
d < std::numeric_limits<int>::min()) {
995+
type = QVariant::LongLong;
996+
} else {
997+
type = QVariant::Int;
998+
}
988999
} else if (PyFloat_Check(val)) {
9891000
type = QVariant::Double;
9901001
} else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) {

src/PythonQtConversion.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
#include "PythonQtClassInfo.h"
4848
#include "PythonQtMethodInfo.h"
4949

50-
#include <QWidget>
5150
#include <QList>
5251
#include <vector>
5352

@@ -261,7 +260,7 @@ template<class ListType, class T>
261260
PyObject* PythonQtConvertListOfKnownClassToPythonList(const void* /*QList<T>* */ inList, int metaTypeId)
262261
{
263262
ListType* list = (ListType*)inList;
264-
static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerTemplateTypeName(QByteArray(QMetaType::typeName(metaTypeId))));
263+
static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId))));
265264
if (innerType == NULL) {
266265
std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type " << innerType->className().constData() << std::endl;
267266
}
@@ -281,7 +280,7 @@ template<class ListType, class T>
281280
bool PythonQtConvertPythonListToListOfKnownClass(PyObject* obj, void* /*QList<T>* */ outList, int metaTypeId, bool /*strict*/)
282281
{
283282
ListType* list = (ListType*)outList;
284-
static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerTemplateTypeName(QByteArray(QMetaType::typeName(metaTypeId))));
283+
static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId))));
285284
if (innerType == NULL) {
286285
std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type " << innerType->className().constData() << std::endl;
287286
}

src/PythonQtImporter.cpp

Lines changed: 127 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "PythonQtImportFileInterface.h"
4949
#include "PythonQt.h"
5050
#include "PythonQtConversion.h"
51+
#include <QDir>
5152
#include <QFile>
5253
#include <QFileInfo>
5354

@@ -100,6 +101,13 @@ PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self,
100101
QString test;
101102
for (zso = mlab_searchorder; *zso->suffix; zso++) {
102103
test = path + zso->suffix;
104+
#ifdef PY3K
105+
if (!PythonQt::importInterface()->exists(test) && (zso->type & IS_BYTECODE)) {
106+
// try __pycache__/*.pyc file
107+
static QString cacheTag(PyImport_GetMagicTag());
108+
test = *self->_path + "/__pycache__/" + subname + "." + cacheTag + zso->suffix;
109+
}
110+
#endif
103111
if (PythonQt::importInterface()->exists(test)) {
104112
info.fullPath = test;
105113
info.moduleName = subname;
@@ -227,7 +235,8 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args)
227235

228236
if (info.type == PythonQtImport::MI_PACKAGE || info.type == PythonQtImport::MI_MODULE) {
229237
QString fullPath;
230-
code = PythonQtImport::getModuleCode(self, fullname, fullPath);
238+
QString fullCachePath;
239+
code = PythonQtImport::getModuleCode(self, fullname, fullPath, fullCachePath);
231240
if (code == NULL) {
232241
return NULL;
233242
}
@@ -274,9 +283,26 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args)
274283
Py_DECREF(mod);
275284
return NULL;
276285
}
286+
287+
// set __package__ only for Python 3, because in Python 2 it causes the exception "__package__ set to non-string"
288+
#ifdef PY3K
289+
// The package attribute is needed to resolve the package name if it is referenced as '.'. For example,
290+
// when importing the encodings package, there is an import statement 'from . import aliases'. This import
291+
// would fail when reloading the encodings package with importlib.
292+
err = PyDict_SetItemString(dict, "__package__", PyUnicode_FromString(fullname));
293+
if (err != 0) {
294+
Py_DECREF(code);
295+
Py_DECREF(mod);
296+
return NULL;
297+
}
298+
#endif
277299
}
278300

301+
#ifdef PY3K
302+
mod = PyImport_ExecCodeModuleWithPathnames(fullname, code, fullPath.toUtf8().data(), fullCachePath.isEmpty() ? NULL : fullCachePath.toUtf8().data());
303+
#else
279304
mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data());
305+
#endif
280306

281307
if (PythonQt::importInterface()) {
282308
PythonQt::importInterface()->importedModule(fullname);
@@ -351,7 +377,8 @@ PythonQtImporter_get_code(PyObject *obj, PyObject *args)
351377
return NULL;
352378

353379
QString notused;
354-
return PythonQtImport::getModuleCode(self, fullname, notused);
380+
QString notused2;
381+
return PythonQtImport::getModuleCode(self, fullname, notused, notused2);
355382
}
356383

357384
PyObject *
@@ -517,13 +544,20 @@ open_exclusive(const QString& filename)
517544
}
518545

519546

520-
void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime)
547+
void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime, long sourceSize)
521548
{
522549
FILE *fp;
523550
// we do not want to write Qt resources to disk, do we?
524551
if (filename.startsWith(":")) {
525552
return;
526553
}
554+
#ifdef PY3K
555+
// create __pycache__ directory, if it does not exist
556+
QDir dir = QFileInfo(filename).absoluteDir();
557+
if (!dir.exists()) {
558+
dir.mkpath(".");
559+
}
560+
#endif
527561
fp = open_exclusive(filename);
528562
if (fp == NULL) {
529563
if (Py_VerboseFlag)
@@ -542,6 +576,9 @@ void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filena
542576
#else
543577
PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
544578
#endif
579+
#ifdef PY3K
580+
PyMarshal_WriteLongToFile(sourceSize, fp, Py_MARSHAL_VERSION);
581+
#endif
545582
#if PY_VERSION_HEX < 0x02040000
546583
PyMarshal_WriteObjectToFile((PyObject *)co, fp);
547584
#else
@@ -611,7 +648,15 @@ PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_
611648
}
612649
}
613650

651+
#ifdef PY3K
652+
// Python 3 also stores the size of the *.py file, but we ignore it for now
653+
int sourceSize = getLong((unsigned char *)buf + 8);
654+
Q_UNUSED(sourceSize);
655+
// read the module
656+
code = PyMarshal_ReadObjectFromString(buf + 12, size - 12);
657+
#else
614658
code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
659+
#endif
615660
if (code == NULL)
616661
return NULL;
617662
if (!PyCode_Check(code)) {
@@ -640,6 +685,38 @@ PythonQtImport::compileSource(const QString& path, const QByteArray& data)
640685
return code;
641686
}
642687

688+
QString PythonQtImport::getCacheFilename(const QString& sourceFilename, bool isOptimizedFilename)
689+
{
690+
#ifdef PY3K
691+
QFileInfo fi(sourceFilename);
692+
static QString cacheTag(PyImport_GetMagicTag());
693+
QString pycFilename = fi.absolutePath() + "/__pycache__/" + fi.baseName() + "." + cacheTag + ".py";
694+
#else
695+
QString pycFilename = sourceFilename;
696+
#endif
697+
return pycFilename + (isOptimizedFilename ? "o" : "c");
698+
}
699+
700+
QString PythonQtImport::getSourceFilename(const QString& cacheFile)
701+
{
702+
#ifdef PY3K
703+
static QString cacheTagPart = "." + QString(PyImport_GetMagicTag());
704+
QFileInfo fi(cacheFile);
705+
// get the parent directory of the __pycache__ directory
706+
QDir dir = fi.absoluteDir();
707+
dir.cdUp();
708+
QString baseName = fi.completeBaseName();
709+
baseName.truncate(baseName.length()-cacheTagPart.length());
710+
QString pyFilename = dir.absolutePath() + "/" + baseName + ".py";
711+
#else
712+
QString pyFilename;
713+
if (cacheFile.length() > 0) {
714+
pyFilename = cacheFile;
715+
pyFilename.truncate(pyFilename.length()-1);
716+
}
717+
#endif
718+
return pyFilename;
719+
}
643720

644721
/* Return the code object for the module named by 'fullname' from the
645722
Zip archive as a new reference. */
@@ -665,7 +742,7 @@ PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispack
665742
}
666743

667744
if (isbytecode) {
668-
// mlabDebugConst("MLABPython", "reading bytecode " << path);
745+
// mlabDebugConst("MLABPython", "reading bytecode " << path);
669746
code = unmarshalCode(path, qdata, mtime);
670747
}
671748
else {
@@ -675,7 +752,8 @@ PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int /*ispack
675752
// save a pyc file if possible
676753
QDateTime time;
677754
time = PythonQt::importInterface()->lastModifiedDate(path);
678-
writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
755+
QString cacheFilename = getCacheFilename(path, /*isOptimizedFilename=*/false);
756+
writeCompiledModule((PyCodeObject*)code, cacheFilename, time.toTime_t(), /*sourceSize=*/qdata.length());
679757
}
680758
}
681759
return code;
@@ -685,9 +763,7 @@ time_t
685763
PythonQtImport::getMTimeOfSource(const QString& path)
686764
{
687765
time_t mtime = 0;
688-
QString path2 = path;
689-
path2.truncate(path.length()-1);
690-
766+
QString path2 = getSourceFilename(path);
691767
if (PythonQt::importInterface()->exists(path2)) {
692768
QDateTime t = PythonQt::importInterface()->lastModifiedDate(path2);
693769
if (t.isValid()) {
@@ -701,7 +777,7 @@ PythonQtImport::getMTimeOfSource(const QString& path)
701777
/* Get the code object associated with the module specified by
702778
'fullname'. */
703779
PyObject *
704-
PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QString& modpath)
780+
PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QString& modpath, QString& cachemodpath)
705781
{
706782
QString subname;
707783
struct st_mlab_searchorder *zso;
@@ -710,13 +786,23 @@ PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QStr
710786
QString path = *self->_path + "/" + subname;
711787

712788
QString test;
713-
for (zso = mlab_searchorder; *zso->suffix; zso++) {
789+
for (zso = mlab_searchorder; *zso->suffix;zso++) {
714790
PyObject *code = NULL;
715791
test = path + zso->suffix;
716792

717793
if (Py_VerboseFlag > 1)
718794
PySys_WriteStderr("# trying %s\n",
719795
test.toLatin1().constData());
796+
#ifdef PY3K
797+
if (!PythonQt::importInterface()->exists(test) && zso->type & IS_BYTECODE) {
798+
// try __pycache__/*.pyc file
799+
static QString cacheTag(PyImport_GetMagicTag());
800+
test = *self->_path + "/__pycache__/" + subname + "." + cacheTag + zso->suffix;
801+
if (Py_VerboseFlag > 1)
802+
PySys_WriteStderr("# trying %s\n",
803+
test.toLatin1().constData());
804+
}
805+
#endif
720806
if (PythonQt::importInterface()->exists(test)) {
721807
time_t mtime = 0;
722808
int ispackage = zso->type & IS_PACKAGE;
@@ -737,6 +823,12 @@ PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QStr
737823
}
738824
if (code != NULL) {
739825
modpath = test;
826+
#ifdef PY3K
827+
if (isbytecode) {
828+
cachemodpath = modpath;
829+
modpath = getSourceFilename(modpath);
830+
}
831+
#endif
740832
}
741833
return code;
742834
}
@@ -762,7 +854,17 @@ PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
762854
{
763855
PyObject* code;
764856
const static QString pycStr("pyc");
765-
QString pyc = replaceExtension(file, pycStr);
857+
QString pyc;
858+
#ifdef PY3K
859+
// if the cache file in __pycache__ does not exist, look for cache file next to
860+
// source file
861+
pyc = getCacheFilename(file, /*isOptimizedFilename=*/false);
862+
if (!PythonQt::importInterface()->exists(pyc)) {
863+
pyc = replaceExtension(file, pycStr);
864+
}
865+
#else
866+
pyc = replaceExtension(file, pycStr);
867+
#endif
766868
if (PythonQt::importInterface()->exists(pyc)) {
767869
time_t mtime = 0;
768870
// if ignoreUpdatedPythonSourceFiles() returns true, then mtime stays 0
@@ -857,17 +959,18 @@ void PythonQtImport::init()
857959
// set our importer into the path_hooks to handle all path on sys.path
858960
PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter");
859961
PyObject* path_hooks = PySys_GetObject(const_cast<char*>("path_hooks"));
860-
PyList_Append(path_hooks, classobj);
861-
862-
#ifndef WIN32
863-
// reload the encodings module, because it might fail to custom import requirements (e.g. encryption).
864-
PyObject* modules = PyImport_GetModuleDict();
865-
PyObject* encodingsModule = PyDict_GetItemString(modules, "encodings");
866-
if (encodingsModule != NULL) {
867-
PyImport_ReloadModule(encodingsModule);
868-
} else {
869-
// import it now, so that the search function is registered (a previous import from the codecs module may have failed and it does not retry to import it)
870-
PyImport_ImportModule("encodings");
871-
}
872-
#endif
962+
// insert our importer before all other loaders
963+
PyList_Insert(path_hooks, 0, classobj);
964+
965+
#ifndef WIN32
966+
// reload the encodings module, because it might fail to custom import requirements (e.g. encryption).
967+
PyObject* modules = PyImport_GetModuleDict();
968+
PyObject* encodingsModule = PyDict_GetItemString(modules, "encodings");
969+
if (encodingsModule != NULL) {
970+
PyImport_ReloadModule(encodingsModule);
971+
} else {
972+
// import it now, so that the search function is registered (a previous import from the codecs module may have failed and it does not retry to import it)
973+
PyImport_ImportModule("encodings");
974+
}
975+
#endif
873976
}

0 commit comments

Comments
 (0)