diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a27eae..6368d1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,16 +105,20 @@ endif() #----------------------------------------------------------------------------- # Find Python option(PythonQt_Python3 "Use Python 3.x (3.3+)" OFF) -if(PythonQt_Python3) - set(PythonQt_PythonMin 3.3) -else(PythonQt_Python3) - set(PythonQt_PythonMin 2.6) +option(PythonQt_Python "Use specific Python Version" OFF) +if(PythonQt_Python) + find_package(Python ${PythonQt_Python} REQUIRED EXACT) +elseif(PythonQt_Python3) + find_package(Python 3.3 REQUIRED) +else() + find_package(Python 2.6 REQUIRED) endif() -find_package(Python ${PythonQt_PythonMin} REQUIRED) include_directories(${PYTHON_INCLUDE_DIRS}) add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK) +#----------------------------------------------------------------------------- +# Core add_subdirectory(src) #----------------------------------------------------------------------------- diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 15cb5ee..f4c9422 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -142,7 +142,7 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) Py_INCREF(obj); PyModule_AddObject(pack2, names[i], obj); } else { - std::cerr << "method not found " << names[i]; + std::cerr << "method not found " << names[i] << std::endl; } } } @@ -1492,7 +1492,7 @@ static PyMethodDef PythonQtMethods[] = { }; #ifdef PY3K -static PyModuleDef PythonQtModule = { +static PyModuleDef PythonQtModuleDef = { PyModuleDef_HEAD_INIT, "", NULL, @@ -1512,18 +1512,19 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ name = pythonQtModuleName; } #ifdef PY3K - PythonQtModule.m_name = name.constData(); - _p->_pythonQtModule = PyModule_Create(&PythonQtModule); + PythonQtModuleDef.m_name = name.constData(); + _p->_pythonQtModule = PyModule_Create(&PythonQtModuleDef); #else _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods); #endif _p->_pythonQtModuleName = name; + PythonQtObjectPtr sys; + sys.setNewRef(PyImport_ImportModule("sys")); + if (redirectStdOut) { - PythonQtObjectPtr sys; PythonQtObjectPtr out; PythonQtObjectPtr err; - sys.setNewRef(PyImport_ImportModule("sys")); // create a redirection object for stdout and stderr out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL); ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB; @@ -1535,8 +1536,6 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ } // add PythonQt to the list of builtin module names - PythonQtObjectPtr sys; - sys.setNewRef(PyImport_ImportModule("sys")); PyObject *old_module_names = PyObject_GetAttrString(sys.object(),"builtin_module_names"); Py_ssize_t old_size = PyTuple_Size(old_module_names); PyObject *module_names = PyTuple_New(old_size+1); @@ -1549,6 +1548,10 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ #endif PyModule_AddObject(sys.object(),"builtin_module_names",module_names); Py_DecRef(old_module_names); + +#ifdef PY3K + PyDict_SetItem(PyObject_GetAttrString(sys.object(), "modules"), PyUnicode_FromString(name.constData()), _p->_pythonQtModule.object()); +#endif } QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name) diff --git a/src/PythonQtClassWrapper.cpp b/src/PythonQtClassWrapper.cpp index c6ddd8c..2932697 100644 --- a/src/PythonQtClassWrapper.cpp +++ b/src/PythonQtClassWrapper.cpp @@ -389,9 +389,6 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) } // look in Python to support derived Python classes -#ifdef PY3K - return PyObject_GenericGetAttr(obj, name); -#else PyObject* superAttr = PyType_Type.tp_getattro(obj, name); if (superAttr) { return superAttr; @@ -418,7 +415,11 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) } // look for the internal methods (className(), help()) +#ifdef PY3K + PyObject* internalMethod = PyObject_GenericGetAttr(obj, name); +#else PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName); +#endif if (internalMethod) { return internalMethod; } @@ -426,7 +427,6 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'"; PyErr_SetString(PyExc_AttributeError, error.toLatin1().data()); return NULL; -#endif } static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value) @@ -486,7 +486,7 @@ PyTypeObject PythonQtClassWrapper_Type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + PythonQtClassWrapper_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index 6adbb59..eec6819 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -45,10 +45,6 @@ #include #include -#if PY_MAJOR_VERSION >= 3 -#define PY3K -#endif - PythonQtValueStorage PythonQtConv::global_valueStorage; PythonQtValueStorage PythonQtConv::global_ptrStorage; PythonQtValueStorageWithCleanup PythonQtConv::global_variantStorage; diff --git a/src/PythonQtImporter.cpp b/src/PythonQtImporter.cpp index 61d69f2..19e57e9 100644 --- a/src/PythonQtImporter.cpp +++ b/src/PythonQtImporter.cpp @@ -51,10 +51,6 @@ #include #include -#if PY_MAJOR_VERSION >= 3 -#define PY3K -#endif - #define IS_SOURCE 0x0 #define IS_BYTECODE 0x1 #define IS_PACKAGE 0x2 diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index 45983f1..c1362f4 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -48,10 +48,6 @@ #include "PythonQtConversion.h" #include "PythonQtClassWrapper.h" -#if PY_MAJOR_VERSION >= 3 -#define PY3K -#endif - PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo() { // take the class info from our type object @@ -831,7 +827,7 @@ PyTypeObject PythonQtInstanceWrapper_Type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + PythonQtInstanceWrapper_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ diff --git a/src/PythonQtSlot.cpp b/src/PythonQtSlot.cpp index fc3d82f..8f753ae 100644 --- a/src/PythonQtSlot.cpp +++ b/src/PythonQtSlot.cpp @@ -52,10 +52,6 @@ #include -#if PY_MAJOR_VERSION >= 3 -#define PY3K -#endif - #define PYTHONQT_MAX_ARGS 32 diff --git a/tests/PythonQtTests.cpp b/tests/PythonQtTests.cpp index 70de856..48df0c1 100644 --- a/tests/PythonQtTests.cpp +++ b/tests/PythonQtTests.cpp @@ -243,25 +243,25 @@ void PythonQtTestSlotCalling::testCppFactory() QVERIFY(_helper->runScript("if obj.getPQCppObjectNoWrapAsValue().getH()==47: obj.setPassed();\n")); qRegisterMetaType("PQUnknownButRegisteredValueObject"); - QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsPtr();print a;\nif a!=None: obj.setPassed();\n")); - QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsValue();print a;\nif a!=None: obj.setPassed();\n")); - QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsPtr();print a;\nif a!=None: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsPtr();print (a);\nif a!=None: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = obj.getUnknownButRegisteredValueObjectAsValue();print (a);\nif a!=None: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsPtr();print (a);\nif a!=None: obj.setPassed();\n")); QEXPECT_FAIL("", "Testing by value return without the object being registered as QMetaType or having registered a default constructor decorator", Continue); - QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsValue();print a;\nif a!=None: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = obj.getUnknownValueObjectAsValue();print (a);\nif a!=None: obj.setPassed();\n")); // expect to get strict call to double overload QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(22.2)\nif a.getH()==2: obj.setPassed();\n")); // expect to get un-strict call to double overload QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(22)\nif a.getH()==2: obj.setPassed();\n")); // expect to get strict call to copy constructor overload - QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(PQCppObjectNoWrap())\nprint a.getH()\nif a.getH()==1: obj.setPassed();\n")); + QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObjectNoWrap\na = PQCppObjectNoWrap(PQCppObjectNoWrap())\nprint (a.getH())\nif a.getH()==1: obj.setPassed();\n")); // test decorated enums // already registered by signals test //PythonQt::self()->registerCPPClass("PQCppObject2",NULL,NULL, PythonQtCreateObject); // local enum (decorated) - QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nprint a.testEnumFlag1\nif a.testEnumFlag1(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n")); + QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nprint (a.testEnumFlag1)\nif a.testEnumFlag1(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n")); // enum with namespace (decorated) QVERIFY(_helper->runScript("obj.testNoArg()\nfrom PythonQt.private import PQCppObject2\na = PQCppObject2()\nif a.testEnumFlag2(PQCppObject2.TestEnumValue2)==PQCppObject2.TestEnumValue2: obj.setPassed();\n")); // with int overload to check overloading @@ -565,17 +565,25 @@ void PythonQtTestApi::testRedirect() { connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)), _helper, SLOT(stdOut(const QString&))); connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)), _helper, SLOT(stdErr(const QString&))); - PyRun_SimpleString("print 'test'\n"); + PyRun_SimpleString("print ('test')\n"); } void PythonQtTestApiHelper::stdOut(const QString& s) { - qDebug() << s; + outBuf.append(s); + QStringList x = outBuf.split("\n"); + outBuf = x.takeLast(); + foreach(QString s, x) + qDebug() << s; } void PythonQtTestApiHelper::stdErr(const QString& s) { - qDebug() << s; + errBuf.append(s); + QStringList x = errBuf.split("\n"); + errBuf = x.takeLast(); + foreach(QString s, x) + qDebug() << s; } QObject* PythonQtTestCppFactory::create(const QByteArray& name, void *ptr) diff --git a/tests/PythonQtTests.h b/tests/PythonQtTests.h index 6b14fa9..a9913f6 100644 --- a/tests/PythonQtTests.h +++ b/tests/PythonQtTests.h @@ -170,6 +170,8 @@ public slots: void stdErr(const QString&); private: + QString outBuf; + QString errBuf; bool _passed; };