From 47217affdb35850d2b8ca67b3f0a9b04fbd02fc7 Mon Sep 17 00:00:00 2001 From: Cristian Maureira-Fredes Date: Sun, 29 Mar 2020 20:27:25 +0200 Subject: doc: add clarification to examples page New users are getting confused by the phrasing of the page, and believe we only have two examples in our codebase. Adding a paragraph to clarify this situation will solve the misconception. Change-Id: I2a18d99771eee82af3181a997c137109840edbec Reviewed-by: Friedemann Kleint --- sources/pyside2/doc/pyside-examples/examples.qdoc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sources/pyside2/doc/pyside-examples/examples.qdoc b/sources/pyside2/doc/pyside-examples/examples.qdoc index d82b33cf7..748c4f8fd 100644 --- a/sources/pyside2/doc/pyside-examples/examples.qdoc +++ b/sources/pyside2/doc/pyside-examples/examples.qdoc @@ -28,5 +28,10 @@ /*! \group all-pyside-examples \title All Qt for Python Examples - \brief A list of all the examples that are available with the Qt for Python package. + \brief A varied selection of examples can be found in the 'examples' directory of the + pyside-setup repository. This can be accessed after installing + PySide2 via pip, checking the 'site-packages/PySide2/examples' directory. + + This page aims to document the most important use cases of the module + and it will be extended with each release. */ -- cgit v1.2.3 From cf8e0d98821cc7e6f0fc48b56a0a16ad88cd881b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 30 Mar 2020 08:33:15 +0200 Subject: Add an example for QUiLoader Task-number: PYSIDE-841 Change-Id: I3aae15ae88f94f62eb7e11dd9942834ef92c55ad Reviewed-by: Christian Tismer --- examples/uiloader/uiloader.py | 71 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 examples/uiloader/uiloader.py diff --git a/examples/uiloader/uiloader.py b/examples/uiloader/uiloader.py new file mode 100644 index 000000000..1e6e72d78 --- /dev/null +++ b/examples/uiloader/uiloader.py @@ -0,0 +1,71 @@ +############################################################################# +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +"""QUiLoader example, showing how to dynamically load a Qt Designer form + from a UI file.""" + +from argparse import ArgumentParser, RawTextHelpFormatter +import sys + +from PySide2.QtCore import Qt, QFile, QIODevice +from PySide2.QtWidgets import QApplication, QWidget +from PySide2.QtUiTools import QUiLoader + + +if __name__ == '__main__': + arg_parser = ArgumentParser(description="QUiLoader example", + formatter_class=RawTextHelpFormatter) + arg_parser.add_argument('file', type=str, help='UI file') + args = arg_parser.parse_args() + ui_file_name = args.file + + app = QApplication(sys.argv) + ui_file = QFile(ui_file_name) + if not ui_file.open(QIODevice.ReadOnly): + print("Cannot open {}: {}".format(ui_file_name, ui_file.errorString())) + sys.exit(-1) + loader = QUiLoader() + widget = loader.load(ui_file, None) + ui_file.close() + if not widget: + print(loader.errorString()) + sys.exit(-1) + widget.show() + sys.exit(app.exec_()) -- cgit v1.2.3 From b28ce21f046ba3e87b12208621c3d9ae6a295944 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Thu, 26 Mar 2020 15:01:54 +0100 Subject: Refine pep384impl.cpp a bit This patch replaces NULL with nullptr, replaces type casts and simplifies a helper function further to avoid string creation. Change-Id: If06cf739eef5836e615e4ff9beb1bca40c791f9e Reviewed-by: Friedemann Kleint --- sources/shiboken2/libshiboken/pep384impl.cpp | 74 +++++++++++----------- sources/shiboken2/libshiboken/sbkstaticstrings.cpp | 1 + sources/shiboken2/libshiboken/sbkstaticstrings.h | 1 + 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index c7ca98c46..622efd201 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -67,7 +67,7 @@ extern "C" #define make_dummy(x) (reinterpret_cast(make_dummy_int(x))) #ifdef Py_LIMITED_API -datetime_struc *PyDateTimeAPI = NULL; +datetime_struc *PyDateTimeAPI = nullptr; #endif static PyObject * @@ -207,15 +207,15 @@ _PepUnicode_AsString(PyObject *str) #define TOSTRING(x) STRINGIFY(x) #define AT __FILE__ ":" TOSTRING(__LINE__) - static PyObject *cstring_dict = NULL; - if (cstring_dict == NULL) { + static PyObject *cstring_dict = nullptr; + if (cstring_dict == nullptr) { cstring_dict = PyDict_New(); - if (cstring_dict == NULL) + if (cstring_dict == nullptr) Py_FatalError("Error in " AT); } - PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", NULL); + PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", nullptr); PyObject *entry = PyDict_GetItem(cstring_dict, bytesStr); - if (entry == NULL) { + if (entry == nullptr) { int e = PyDict_SetItem(cstring_dict, bytesStr, bytesStr); if (e != 0) Py_FatalError("Error in " AT); @@ -253,7 +253,7 @@ _PepLong_AsInt(PyObject *obj) "Python int too large to convert to C int"); return -1; } - return (int)result; + return int(result); } /***************************************************************************** @@ -261,7 +261,7 @@ _PepLong_AsInt(PyObject *obj) * Support for pydebug.h * */ -static PyObject *sys_flags = NULL; +static PyObject *sys_flags = nullptr; int Pep_GetFlag(const char *name) @@ -271,13 +271,13 @@ Pep_GetFlag(const char *name) if (!initialized) { sys_flags = PySys_GetObject("flags"); - // func gives no error if NULL is returned and does not incref. + // func gives no error if nullptr is returned and does not incref. Py_XINCREF(sys_flags); initialized = 1; } - if (sys_flags != NULL) { + if (sys_flags != nullptr) { PyObject *ob_ret = PyObject_GetAttrString(sys_flags, name); - if (ob_ret != NULL) { + if (ob_ret != nullptr) { long long_ret = PyLong_AsLong(ob_ret); Py_DECREF(ob_ret); ret = (int) long_ret; @@ -314,7 +314,7 @@ PepCode_Get(PyCodeObject *co, const char *name) int ret = -1; ob_ret = PyObject_GetAttrString(ob, name); - if (ob_ret != NULL) { + if (ob_ret != nullptr) { long long_ret = PyLong_AsLong(ob_ret); Py_DECREF(ob_ret); ret = (int) long_ret; @@ -331,11 +331,11 @@ PepCode_Get(PyCodeObject *co, const char *name) static PyTypeObject *dt_getCheck(const char *name) { PyObject *op = PyObject_GetAttrString(PyDateTimeAPI->module, name); - if (op == NULL) { + if (op == nullptr) { fprintf(stderr, "datetime.%s not found\n", name); Py_FatalError("aborting"); } - return (PyTypeObject *)op; + return reinterpret_cast(op); } // init_DateTime is called earlier than our module init. @@ -346,10 +346,10 @@ init_DateTime(void) static int initialized = 0; if (!initialized) { PyDateTimeAPI = (datetime_struc *)malloc(sizeof(datetime_struc)); - if (PyDateTimeAPI == NULL) + if (PyDateTimeAPI == nullptr) Py_FatalError("PyDateTimeAPI malloc error, aborting"); PyDateTimeAPI->module = PyImport_ImportModule("datetime"); - if (PyDateTimeAPI->module == NULL) + if (PyDateTimeAPI->module == nullptr) Py_FatalError("datetime module not found, aborting"); PyDateTimeAPI->DateType = dt_getCheck("date"); PyDateTimeAPI->DateTimeType = dt_getCheck("datetime"); @@ -368,7 +368,7 @@ PyDateTime_Get(PyObject *ob, const char *name) int ret = -1; ob_ret = PyObject_GetAttrString(ob, name); - if (ob_ret != NULL) { + if (ob_ret != nullptr) { long long_ret = PyLong_AsLong(ob_ret); Py_DECREF(ob_ret); ret = (int) long_ret; @@ -410,9 +410,9 @@ PyObject * PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) { PyObject *code = Py_CompileString(str, "pyscript", start); - PyObject *ret = NULL; + PyObject *ret = nullptr; - if (code != NULL) { + if (code != nullptr) { ret = PyEval_EvalCode(code, globals, locals); } Py_XDECREF(code); @@ -425,7 +425,7 @@ PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) // Used also in Python 2. #if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x03000000 static PyObject * -PepRun_GetResult(const char *command, const char *resvar) +PepRun_GetResult(const char *command) { PyObject *d, *v, *res; @@ -435,7 +435,7 @@ PepRun_GetResult(const char *command, const char *resvar) return nullptr; } v = PyRun_String(command, Py_file_input, d, d); - res = v ? PyDict_GetItemString(d, resvar) : NULL; + res = v ? PyDict_GetItem(d, Shiboken::PyName::result()) : nullptr; Py_XDECREF(v); Py_DECREF(d); return res; @@ -450,15 +450,15 @@ PepRun_GetResult(const char *command, const char *resvar) * */ -PyTypeObject *PepMethod_TypePtr = NULL; +PyTypeObject *PepMethod_TypePtr = nullptr; static PyTypeObject *getMethodType(void) { static const char prog[] = "class _C:\n" " def _m(self): pass\n" - "MethodType = type(_C()._m)\n"; - return (PyTypeObject *) PepRun_GetResult(prog, "MethodType"); + "result = type(_C()._m)\n"; + return reinterpret_cast(PepRun_GetResult(prog)); } // We have no access to PyMethod_New and must call types.MethodType, instead. @@ -509,13 +509,13 @@ PepFunction_Get(PyObject *ob, const char *name) // This became necessary after Windows was activated. -PyTypeObject *PepFunction_TypePtr = NULL; +PyTypeObject *PepFunction_TypePtr = nullptr; static PyTypeObject *getFunctionType(void) { static const char prog[] = - "from types import FunctionType\n"; - return (PyTypeObject *) PepRun_GetResult(prog, "FunctionType"); + "from types import FunctionType as result\n"; + return reinterpret_cast(PepRun_GetResult(prog)); } /***************************************************************************** @@ -524,7 +524,7 @@ static PyTypeObject *getFunctionType(void) * */ -PyTypeObject *PepStaticMethod_TypePtr = NULL; +PyTypeObject *PepStaticMethod_TypePtr = nullptr; static PyTypeObject * getStaticMethodType(void) @@ -533,8 +533,8 @@ getStaticMethodType(void) // "StaticMethodType = type(str.__dict__['maketrans'])\n"; static const char prog[] = "from xxsubtype import spamlist\n" - "StaticMethod_Type = type(spamlist.__dict__['staticmeth'])\n"; - return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethod_Type"); + "result = type(spamlist.__dict__['staticmeth'])\n"; + return reinterpret_cast(PepRun_GetResult(prog)); } typedef struct { @@ -548,23 +548,23 @@ PyStaticMethod_New(PyObject *callable) { staticmethod *sm = (staticmethod *) PyType_GenericAlloc(PepStaticMethod_TypePtr, 0); - if (sm != NULL) { + if (sm != nullptr) { Py_INCREF(callable); sm->sm_callable = callable; } - return (PyObject *)sm; + return reinterpret_cast(sm); } #endif // Py_LIMITED_API #if PY_VERSION_HEX < 0x03000000 -PyTypeObject *PepMethodDescr_TypePtr = NULL; +PyTypeObject *PepMethodDescr_TypePtr = nullptr; static PyTypeObject * getMethodDescrType(void) { static const char prog[] = - "MethodDescr_Type = type(str.split)\n"; - return (PyTypeObject *) PepRun_GetResult(prog, "MethodDescr_Type"); + "result = type(str.split)\n"; + return reinterpret_cast(PepRun_GetResult(prog)); } #endif @@ -609,7 +609,7 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name) */ #if PY_VERSION_HEX < 0X03000000 const char *namestr = PyString_AsString(name); - if (namestr == NULL || namestr[0] != '_' || namestr[1] != '_') { + if (namestr == nullptr || namestr[0] != '_' || namestr[1] != '_') { Py_INCREF(name); return name; } @@ -655,7 +655,7 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name) if (plen + nlen >= PY_SSIZE_T_MAX - 1) { PyErr_SetString(PyExc_OverflowError, "private identifier too large to be mangled"); - return NULL; + return nullptr; } size_t const amount = ipriv + 1 + plen + nlen; size_t const big_stack = 1000; diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp index 42d20d133..04069a4d1 100644 --- a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp +++ b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp @@ -54,6 +54,7 @@ namespace PyName { // exported: STATIC_STRING_IMPL(dumps, "dumps") STATIC_STRING_IMPL(loads, "loads") +STATIC_STRING_IMPL(result, "result") // Internal: STATIC_STRING_IMPL(classmethod, "classmethod") diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.h b/sources/shiboken2/libshiboken/sbkstaticstrings.h index fa21a8e2c..6016fe106 100644 --- a/sources/shiboken2/libshiboken/sbkstaticstrings.h +++ b/sources/shiboken2/libshiboken/sbkstaticstrings.h @@ -50,6 +50,7 @@ namespace PyName { LIBSHIBOKEN_API PyObject *dumps(); LIBSHIBOKEN_API PyObject *loads(); +LIBSHIBOKEN_API PyObject *result(); } // namespace PyName namespace PyMagicName -- cgit v1.2.3 From d77a90d4ef30d311dea39a7f4c3399e4363cc1b7 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Sat, 28 Mar 2020 18:59:00 +0100 Subject: shiboken: Update sbkstring to use PyUnicode_GetLength The unicode implementation has changed very much. PyUnicode_GET_SIZE has been used all the time, although this macro is already a quite expensive real function since Python 3.3 . The function is deprecated, and the macro PyUnicode_GET_LENGTH should be used, instead. This is relevant for cleaning things up, because in the course of fixing PYSIDE-813 we work with debug Python, which then complains that Python memory is used without holding the GIL. The usage of the right implementation was ensured by a function PepUnicode_GetLength and removing all traces of the former version. Task-number: PYSIDE-813 Change-Id: I62e94e10e14975dac3dad0ed1fffec8a1b54a0d5 Reviewed-by: Cristian Maureira-Fredes --- sources/pyside2/PySide2/glue/qtcore.cpp | 2 +- sources/shiboken2/libshiboken/bufferprocs_py37.cpp | 2 +- sources/shiboken2/libshiboken/pep384impl.cpp | 2 +- sources/shiboken2/libshiboken/pep384impl.h | 37 +++++++++++++++++----- sources/shiboken2/libshiboken/pep384impl_doc.rst | 6 ++-- sources/shiboken2/libshiboken/sbkpython.h | 2 ++ sources/shiboken2/libshiboken/sbkstring.cpp | 2 +- 7 files changed, 39 insertions(+), 14 deletions(-) diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index 60ddf675c..169b89cae 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -1685,7 +1685,7 @@ Py_UNICODE *unicode = PyUnicode_AS_UNICODE(%in); // cast as Py_UNICODE can be a different type %out = QString::fromUcs4((const uint *)unicode); # else -%out = QString::fromUtf16((const ushort *)unicode, PyUnicode_GET_SIZE(%in)); +%out = QString::fromUtf16((const ushort *)unicode, PepUnicode_GetLength(%in)); # endif #else wchar_t *temp = PyUnicode_AsWideCharString(%in, NULL); diff --git a/sources/shiboken2/libshiboken/bufferprocs_py37.cpp b/sources/shiboken2/libshiboken/bufferprocs_py37.cpp index ddb07390e..da6bb00a3 100644 --- a/sources/shiboken2/libshiboken/bufferprocs_py37.cpp +++ b/sources/shiboken2/libshiboken/bufferprocs_py37.cpp @@ -47,7 +47,7 @@ #ifdef Py_LIMITED_API -#include "pep384impl.h" +#include "sbkpython.h" /* Buffer C-API for Python 3.0 */ int diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 622efd201..9939bb410 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "pep384impl.h" +#include "sbkpython.h" #include "autodecref.h" #include "sbkstaticstrings.h" #include "sbkstaticstrings_p.h" diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index 6d0fa2450..c18f00804 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -40,8 +40,6 @@ #ifndef PEP384IMPL_H #define PEP384IMPL_H -#include "sbkpython.h" - extern "C" { @@ -204,17 +202,40 @@ LIBSHIBOKEN_API int Pep_GetVerboseFlag(void); * RESOLVED: unicodeobject.h * */ -#ifdef Py_LIMITED_API - -LIBSHIBOKEN_API char *_PepUnicode_AsString(PyObject *); +/////////////////////////////////////////////////////////////////////// +// +// PYSIDE-813: About The Length Of Unicode Objects +// ----------------------------------------------- +// +// In Python 2 and before Python 3.3, the macro PyUnicode_GET_SIZE +// worked fine and really like a macro. +// +// Meanwhile, the unicode objects have changed their layout very much, +// and the former cheap macro call has become a real function call +// that converts objects and needs PyMemory. +// PyUnicode_GET_SIZE was retained for compatibility reasons. +// +// That is not only inefficient, but also requires the GIL! +// This problem was visible by debug Python and qdatastream_test.py . +// It was found while fixing the refcount problem of PYSIDE-813 which +// needed a debug Python. +// + +// PyUnicode_GetSize is deprecated in favor of PyUnicode_GetLength. +// We undefine the PyUnicode_GET_SIZE macro, to be sure that it is not used +// by accident. Only PepUnicode_GetLength should be used. +#undef PyUnicode_GET_SIZE #if PY_VERSION_HEX < 0x03000000 -#define PyUnicode_GET_SIZE(op) PyUnicode_GetSize((PyObject *)(op)) +#define PepUnicode_GetLength(op) PyUnicode_GetSize((PyObject *)(op)) #else -// PyUnicode_GetSize is deprecated in favor of PyUnicode_GetLength -#define PyUnicode_GET_SIZE(op) PyUnicode_GetLength((PyObject *)(op)) +#define PepUnicode_GetLength(op) PyUnicode_GetLength((PyObject *)(op)) #endif +#ifdef Py_LIMITED_API + +LIBSHIBOKEN_API char *_PepUnicode_AsString(PyObject *); + #else #define _PepUnicode_AsString PyUnicode_AsUTF8 #endif diff --git a/sources/shiboken2/libshiboken/pep384impl_doc.rst b/sources/shiboken2/libshiboken/pep384impl_doc.rst index 2f3b7ea97..ac4b053a7 100644 --- a/sources/shiboken2/libshiboken/pep384impl_doc.rst +++ b/sources/shiboken2/libshiboken/pep384impl_doc.rst @@ -70,8 +70,10 @@ supported. We redefined it as macro ``Py_VerboseFlag`` which calls ``Pep_Verbose unicodeobject.h --------------- -The macro ``PyUnicode_GET_SIZE`` was redefined to call into ``PyUnicode_GetSize`` -for Python 2, and ``PyUnicode_GetLength`` for Python 3. +The macro ``PyUnicode_GET_SIZE`` was removed and replaced by ``PepUnicode_GetLength`` +which evaluates to ``PyUnicode_GetSize`` for Python 2 and ``PyUnicode_GetLength`` for Python 3. +Since Python 3.3, ``PyUnicode_GetSize`` would have the bad side effect of requiring the GIL! + Function ``_PyUnicode_AsString`` is unavailable and was replaced by a macro that calls ``_PepUnicode_AsString``. The implementation was a bit involved, and it would be better to change the code and replace this function. diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h index f06b0b19e..9dd1e712e 100644 --- a/sources/shiboken2/libshiboken/sbkpython.h +++ b/sources/shiboken2/libshiboken/sbkpython.h @@ -72,6 +72,7 @@ extern "C" { // Now we have the usual variables from Python.h . # include "python25compat.h" # include "shibokenmacros.h" +// "pep384impl.h" may nowhere be included but in this file. # include "pep384impl.h" # include "typespec.h" # pragma pop_macro("slots") @@ -98,6 +99,7 @@ extern "C" { // Now we have the usual variables from Python.h . # include "python25compat.h" # include "shibokenmacros.h" +// "pep384impl.h" may nowhere be included but in this file. # include "pep384impl.h" # include "typespec.h" #endif diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp index 4a441222f..38bb105d0 100644 --- a/sources/shiboken2/libshiboken/sbkstring.cpp +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -202,7 +202,7 @@ Py_ssize_t len(PyObject *str) return 0; if (PyUnicode_Check(str)) - return PyUnicode_GET_SIZE(str); + return PepUnicode_GetLength(str); if (PyBytes_Check(str)) return PyBytes_GET_SIZE(str); -- cgit v1.2.3 From 79c74e1999d2b29bc918f6d42079c34174bb137d Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Sat, 28 Mar 2020 18:59:00 +0100 Subject: shiboken: Update sbkstring to use PyUnicode_GetLength rev. 2 Minor edits. Augments d77a90d4ef30d311dea39a7f4c3399e4363cc1b7 Task-number: PYSIDE-813 Change-Id: I3a24b1f49a22f4681d2c4e2457cda7110bd7b4f1 Reviewed-by: Friedemann Kleint --- sources/shiboken2/libshiboken/pep384impl.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index c18f00804..676e6c82d 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -214,7 +214,6 @@ LIBSHIBOKEN_API int Pep_GetVerboseFlag(void); // Meanwhile, the unicode objects have changed their layout very much, // and the former cheap macro call has become a real function call // that converts objects and needs PyMemory. -// PyUnicode_GET_SIZE was retained for compatibility reasons. // // That is not only inefficient, but also requires the GIL! // This problem was visible by debug Python and qdatastream_test.py . @@ -223,9 +222,6 @@ LIBSHIBOKEN_API int Pep_GetVerboseFlag(void); // // PyUnicode_GetSize is deprecated in favor of PyUnicode_GetLength. -// We undefine the PyUnicode_GET_SIZE macro, to be sure that it is not used -// by accident. Only PepUnicode_GetLength should be used. -#undef PyUnicode_GET_SIZE #if PY_VERSION_HEX < 0x03000000 #define PepUnicode_GetLength(op) PyUnicode_GetSize((PyObject *)(op)) #else -- cgit v1.2.3 From fe77dce7a7e713456454e5c0a071f7cc70261b98 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Mon, 30 Mar 2020 19:46:41 +0200 Subject: shiboken: Fix dict access without GIL In PYSIDE-803 we used an optimization that accessed a dictionary without holding the GIL. This turned out to be not correct, because PyDict_GetItem works with thread state to maintain the global error variables. PyDict_GetItemWithErrors can be used instead in a way that allows releasing the GIL. Task-number: PYSIDE-803 Task-number: PYSIDE-813 Change-Id: Ifb0cbb20c21ca9c8b3d099fff1db5410eb6824b4 Reviewed-by: Christian Tismer --- sources/pyside2/libpyside/signalmanager.cpp | 5 ++- sources/pyside2/libpyside/signalmanager.h | 1 + sources/shiboken2/libshiboken/pep384impl.cpp | 45 ++++++++++++++++++++++++ sources/shiboken2/libshiboken/pep384impl.h | 11 ++++++ sources/shiboken2/libshiboken/pep384impl_doc.rst | 10 ++++++ 5 files changed, 71 insertions(+), 1 deletion(-) diff --git a/sources/pyside2/libpyside/signalmanager.cpp b/sources/pyside2/libpyside/signalmanager.cpp index 01b347a3d..0fe0d0092 100644 --- a/sources/pyside2/libpyside/signalmanager.cpp +++ b/sources/pyside2/libpyside/signalmanager.cpp @@ -559,7 +559,10 @@ static MetaObjectBuilder *metaBuilderFromDict(PyObject *dict) if (!dict || !PyDict_Contains(dict, metaObjectAttr)) return nullptr; - PyObject *pyBuilder = PyDict_GetItem(dict, metaObjectAttr); + // PYSIDE-813: The above assumption is not true in debug mode: + // PyDict_GetItem would touch PyThreadState_GET and the global error state. + // PyDict_GetItemWithError instead can work without GIL. + PyObject *pyBuilder = PyDict_GetItemWithError(dict, metaObjectAttr); #ifdef IS_PY3K return reinterpret_cast(PyCapsule_GetPointer(pyBuilder, nullptr)); #else diff --git a/sources/pyside2/libpyside/signalmanager.h b/sources/pyside2/libpyside/signalmanager.h index 229ddb91d..fe077bd1a 100644 --- a/sources/pyside2/libpyside/signalmanager.h +++ b/sources/pyside2/libpyside/signalmanager.h @@ -43,6 +43,7 @@ #include "pysidemacros.h" #include +#include #include diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 9939bb410..9f51034f3 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -518,12 +518,57 @@ static PyTypeObject *getFunctionType(void) return reinterpret_cast(PepRun_GetResult(prog)); } +#endif // Py_LIMITED_API || Python 2 + +/***************************************************************************** + * + * Support for dictobject.h + * + */ + +// PYSIDE-803, PYSIDE-813: We need that GIL-free version from Python 2.7.12 . +#if PY_VERSION_HEX < 0x03000000 + +/* Variant of PyDict_GetItem() that doesn't suppress exceptions. + This returns NULL *with* an exception set if an exception occurred. + It returns NULL *without* an exception set if the key wasn't present. +*/ +PyObject * +PyDict_GetItemWithError(PyObject *op, PyObject *key) +{ + long hash; + PyDictObject *mp = reinterpret_cast(op); + PyDictEntry *ep; + if (!PyDict_Check(op)) { + PyErr_BadInternalCall(); + return nullptr; + } + if (!PyString_CheckExact(key) || + (hash = (reinterpret_cast(key))->ob_shash) == -1) + { + hash = PyObject_Hash(key); + if (hash == -1) { + return nullptr; + } + } + + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == nullptr) { + return nullptr; + } + return ep->me_value; +} + +#endif + /***************************************************************************** * * Extra support for signature.cpp * */ +#ifdef Py_LIMITED_API + PyTypeObject *PepStaticMethod_TypePtr = nullptr; static PyTypeObject * diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index 676e6c82d..e735095e8 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -277,6 +277,17 @@ LIBSHIBOKEN_API char *_PepUnicode_AsString(PyObject *); #define PyList_GET_SIZE(op) PyList_Size(op) #endif +/***************************************************************************** + * + * RESOLVED: dictobject.h + * + * PYSIDE-803, PYSIDE-813: We need PyDict_GetItemWithError in order to + * avoid the GIL. + */ +#if PY_VERSION_HEX < 0x03000000 +LIBSHIBOKEN_API PyObject *PyDict_GetItemWithError(PyObject *mp, PyObject *key); +#endif + /***************************************************************************** * * RESOLVED: methodobject.h diff --git a/sources/shiboken2/libshiboken/pep384impl_doc.rst b/sources/shiboken2/libshiboken/pep384impl_doc.rst index ac4b053a7..d8ebdbe70 100644 --- a/sources/shiboken2/libshiboken/pep384impl_doc.rst +++ b/sources/shiboken2/libshiboken/pep384impl_doc.rst @@ -106,6 +106,16 @@ listobject.h function calls. +dictobject.h +------------ + +``PyDict_GetItem`` also exists in a ``PyDict_GetItemWithError`` version that does +not suppress errors. This suppression has the side effect of touching global +structures. This function exists in Python 2 only since Python 2.7.12 and has +a different name. We simply implemented the function. +Needed to avoid the GIL when accessing dictionaries. + + methodobject.h -------------- -- cgit v1.2.3 From 9642f5d0afb7ca78d1a64328a3a5ee40e7d095c8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 3 Apr 2020 08:28:24 +0200 Subject: Adapt UI files tutorial to newly added UiLoader example Amends cf8e0d98821cc7e6f0fc48b56a0a16ad88cd881b. Task-number: PYSIDE-841 Change-Id: Iea6ab04e2ce8c4fb77d7d5c770dc45005f2635dc Reviewed-by: Cristian Maureira-Fredes --- sources/pyside2/doc/tutorials/basictutorial/uifiles.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst b/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst index a45bfc18c..2c0178e2e 100644 --- a/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst +++ b/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst @@ -163,12 +163,17 @@ The complete code of this example looks like this: if __name__ == "__main__": app = QApplication(sys.argv) - ui_file = QFile("mainwindow.ui") - ui_file.open(QFile.ReadOnly) - + ui_file_name = "mainwindow.ui" + ui_file = QFile(ui_file_name) + if not ui_file.open(QIODevice.ReadOnly): + print("Cannot open {}: {}".format(ui_file_name, ui_file.errorString())) + sys.exit(-1) loader = QUiLoader() window = loader.load(ui_file) ui_file.close() + if not window: + print(loader.errorString()) + sys.exit(-1) window.show() sys.exit(app.exec_()) -- cgit v1.2.3 From 11126a9811b21886acdac1e484a92044d7ffd5a2 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 3 Apr 2020 10:31:07 +0200 Subject: PySide2: Fix lockups in QMetaObject.invokeMethod with BlockingQueuedConnection Add allow-thread. Change-Id: I7feba9761a52c273cf4500a42dfbea0463d6040f Fixes: PYSIDE-1253 Reviewed-by: Christian Tismer --- sources/pyside2/PySide2/QtCore/typesystem_core_common.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml index f64a8fd73..b418d2689 100644 --- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml +++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml @@ -2885,6 +2885,7 @@ + -- cgit v1.2.3 From e15bccb0e1f40b959801860f14578c0d77ba8176 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Sat, 4 Apr 2020 23:09:14 +0200 Subject: shiboken: Fix Qt properties not working in classes inheriting QObject The fixes for PYSIDE-803 caused setattro methods to be generated for many classes, resulting in QObject's setattro method no longer being called. Generate property code in each class inheriting QObject. Task-number: PYSIDE-803 Fixes: PYSIDE-1255 Change-Id: I56f52fb43c4ddc77914090ac122776050354ddbe Reviewed-by: Christian Tismer --- sources/pyside2/tests/pysidetest/CMakeLists.txt | 1 + .../pyside2/tests/pysidetest/properties_test.py | 132 +++++++++++++++++++++ .../generator/shiboken2/shibokengenerator.cpp | 7 ++ 3 files changed, 140 insertions(+) create mode 100644 sources/pyside2/tests/pysidetest/properties_test.py diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt index 3ba2ad29d..46a8023c3 100644 --- a/sources/pyside2/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt @@ -143,6 +143,7 @@ PYSIDE_TEST(mixin_signal_slots_test.py) PYSIDE_TEST(modelview_test.py) PYSIDE_TEST(new_inherited_functions_test.py) PYSIDE_TEST(notify_id.py) +PYSIDE_TEST(properties_test.py) PYSIDE_TEST(qapp_like_a_macro_test.py) PYSIDE_TEST(qvariant_test.py) PYSIDE_TEST(repr_test.py) diff --git a/sources/pyside2/tests/pysidetest/properties_test.py b/sources/pyside2/tests/pysidetest/properties_test.py new file mode 100644 index 000000000..cedfac8d1 --- /dev/null +++ b/sources/pyside2/tests/pysidetest/properties_test.py @@ -0,0 +1,132 @@ +############################################################################# +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of Qt for Python. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +import os +import sys +import unittest + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from init_paths import init_test_paths +init_test_paths(False) + +from PySide2.QtCore import QObject, QStringListModel, Signal, Property, Slot + +"""Tests PySide2.QtCore.Property()""" + + +class TestObject(QObject): + + valueChanged = Signal() + + def __init__(self, parent=None): + super(TestObject, self).__init__(parent) + self._value = -1 + self.valueChanged.connect(self._changed) + self.getter_called = 0 + self.setter_called = 0 + self.changed_emitted = 0 + + @Slot(int) + def _changed(self): + self.changed_emitted += 1 + + def getValue(self): + self.getter_called += 1 + return self._value + + def setValue(self, value): + self.setter_called += 1 + if (self._value != value): + self._value = value + self.valueChanged.emit() + + value = Property(int, fget=getValue, fset=setValue, + notify=valueChanged) + + +class TestDerivedObject(QStringListModel): + + valueChanged = Signal() + + def __init__(self, parent=None): + super(TestDerivedObject, self).__init__(parent) + self._value = -1 + self.valueChanged.connect(self._changed) + self.getter_called = 0 + self.setter_called = 0 + self.changed_emitted = 0 + + @Slot(int) + def _changed(self): + self.changed_emitted += 1 + + def getValue(self): + self.getter_called += 1 + return self._value + + def setValue(self, value): + self.setter_called += 1 + if (self._value != value): + self._value = value + self.valueChanged.emit() + + value = Property(int, fget=getValue, fset=setValue, + notify=valueChanged) + + +class PropertyTest(unittest.TestCase): + + def test1Object(self): + """Basic property test.""" + testObject = TestObject() + v = testObject.value + self.assertEqual(v, -1) + self.assertEqual(testObject.getter_called, 1) + testObject.value = 42 + v = testObject.value + self.assertEqual(v, 42) + self.assertEqual(testObject.changed_emitted, 1) + self.assertEqual(testObject.setter_called, 1) + self.assertEqual(testObject.getter_called, 2) + + def test2DerivedObject(self): + """PYSIDE-1255: Run the same test for a class inheriting QObject.""" + testObject = TestDerivedObject() + v = testObject.value + self.assertEqual(v, -1) + self.assertEqual(testObject.getter_called, 1) + testObject.value = 42 + v = testObject.value + self.assertEqual(v, 42) + self.assertEqual(testObject.changed_emitted, 1) + self.assertEqual(testObject.setter_called, 1) + self.assertEqual(testObject.getter_called, 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index fbd3c314b..a712c3ebb 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -2219,6 +2219,13 @@ ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const A result |= AttroCheckFlag::SetattroQObject; if (useOverrideCaching(metaClass)) result |= AttroCheckFlag::SetattroMethodOverride; + // PYSIDE-1255: If setattro is generated for a class inheriting + // QObject, the property code needs to be generated, too. + if ((result & AttroCheckFlag::SetattroMask) != 0 + && !result.testFlag(AttroCheckFlag::SetattroQObject) + && metaClass->isQObject()) { + result |= AttroCheckFlag::SetattroQObject; + } } return result; } -- cgit v1.2.3 From 9ae63824a5ec550e82561b9f07fc6307ae1f3cec Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 6 Apr 2020 08:15:11 +0200 Subject: shiboken: Support Clang version 10 Adapt the version check of the internal include directory to parse the entire directory (typically named like 9.0.0) as version number instead of just checking the first digit. Change-Id: I7e09c36fd523328e962c7f2acbc8385787e94998 Fixes: PYSIDE-1259 Reviewed-by: Cristian Maureira-Fredes --- sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp index d3e5e212f..188725da9 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp @@ -274,7 +274,7 @@ static QString findClangBuiltInIncludesDir() for (const QFileInfo &fi : versionDirs) { const QString fileName = fi.fileName(); if (fileName.at(0).isDigit()) { - const QVersionNumber versionNumber = QVersionNumber::fromString(fileName.at(0)); + const QVersionNumber versionNumber = QVersionNumber::fromString(fileName); if (!versionNumber.isNull() && versionNumber > lastVersionNumber) { candidate = fi.absoluteFilePath(); lastVersionNumber = versionNumber; -- cgit v1.2.3 From e669e80e232f88121308a32a5401edc91a9bbff2 Mon Sep 17 00:00:00 2001 From: Cristian Maureira-Fredes Date: Fri, 3 Apr 2020 14:17:31 +0200 Subject: ci: pin numpy version for Python 2.7 Numpy 1.16.6 was the last version that supports Python 2.7 Change-Id: I43f401a6da350b874b2b25114fdc6d9fd07f69ef Reviewed-by: Friedemann Kleint --- coin_build_instructions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coin_build_instructions.py b/coin_build_instructions.py index 95bd4eba2..325b02dec 100644 --- a/coin_build_instructions.py +++ b/coin_build_instructions.py @@ -112,7 +112,8 @@ def call_setup(python_ver, phase): run_instruction(["virtualenv", "-p", _pExe, _env], "Failed to create virtualenv") # When the 'python_ver' variable is empty, we are using Python 2 # setuptools from v45+ removed the support for Python 2, so we pin an old release - install_pip_dependencies(env_pip, ["pip", "numpy", + install_pip_dependencies(env_pip, ["pip", + "numpy" if python_ver else "numpy==1.16.6", "setuptools" if python_ver else "setuptools==44.0.0", "sphinx", "six", "wheel"]) -- cgit v1.2.3 From b9bf10b9cff9399ef575842f286e96dc24dac5c9 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Sun, 5 Apr 2020 11:03:21 +0200 Subject: Revert "shiboken: Add XML attribute to turn off method caching" This reverts commit fcbbab0a6b5949b5c3726214ed87898b5fbcebcc. This is no longer required after a fix generating the property code into the setattro methods of QObject-derived classes. Task-number: PYSIDE-803 Task-number: PYSIDE-1255 Change-Id: I9e989c0592eaaf25aa55a1db49537daa4bdb2a57 Reviewed-by: Christian Tismer --- sources/pyside2/PySide2/QtQuick/typesystem_quick.xml | 2 +- sources/shiboken2/ApiExtractor/typesystem.h | 3 +-- sources/shiboken2/ApiExtractor/typesystemparser.cpp | 4 ---- sources/shiboken2/doc/typesystem_specifying_types.rst | 5 ----- sources/shiboken2/generator/shiboken2/shibokengenerator.cpp | 4 +--- 5 files changed, 3 insertions(+), 15 deletions(-) diff --git a/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml b/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml index 12c1ac33d..223eff773 100644 --- a/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml +++ b/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml @@ -64,7 +64,7 @@ - + diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 8d8d60f3f..4d0a23ca1 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -1219,8 +1219,7 @@ class ComplexTypeEntry : public TypeEntry { public: enum TypeFlag { - Deprecated = 0x4, - NoOverrideCaching = 0x8 + Deprecated = 0x4 }; Q_DECLARE_FLAGS(TypeFlags, TypeFlag) diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp index 5252ac00a..0bb56f0fe 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp @@ -60,7 +60,6 @@ static inline QString untilAttribute() { return QStringLiteral("until"); } static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); } static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); } static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); } -static inline QString noOverrideCachingAttribute() { return QStringLiteral("no-override-caching"); } static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); } static inline QString extensibleAttribute() { return QStringLiteral("extensible"); } static inline QString flagsAttribute() { return QStringLiteral("flags"); } @@ -1477,9 +1476,6 @@ void TypeSystemParser::applyComplexTypeAttributes(const QXmlStreamReader &reader } else if (name == deprecatedAttribute()) { if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated); - } else if (name == noOverrideCachingAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), noOverrideCachingAttribute(), false)) - ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::NoOverrideCaching); } else if (name == deleteInMainThreadAttribute()) { if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false)) ctype->setDeleteInMainThread(true); diff --git a/sources/shiboken2/doc/typesystem_specifying_types.rst b/sources/shiboken2/doc/typesystem_specifying_types.rst index 3ab6adbd6..bca1e0774 100644 --- a/sources/shiboken2/doc/typesystem_specifying_types.rst +++ b/sources/shiboken2/doc/typesystem_specifying_types.rst @@ -300,7 +300,6 @@ object-type allow-thread="..." exception-handling="..." hash-function="..." - no-override-caching="yes | no" stream="yes | no" revision="..." /> @@ -324,10 +323,6 @@ object-type specify the default handling for the corresponding function modification (see :ref:`modify-function`). - The *optional* attribute **no-override-caching** can be used to turn off the - caching of methods overridden in Python, which can trigger obscure bugs when - setting attributes in Python 2. - interface-type ^^^^^^^^^^^^^^ diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index a712c3ebb..2cdb8870c 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -2202,9 +2202,7 @@ bool ShibokenGenerator::injectedCodeUsesArgument(const AbstractMetaFunction *fun bool ShibokenGenerator::useOverrideCaching(const AbstractMetaClass *metaClass) { - return metaClass->isPolymorphic() - && !metaClass->typeEntry()->typeFlags().testFlag(ComplexTypeEntry::NoOverrideCaching); - + return metaClass->isPolymorphic(); } ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const AbstractMetaClass *metaClass) const -- cgit v1.2.3 From ad9ce332b75e54731b653e9b969330438cad0d0c Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Sun, 5 Apr 2020 12:50:00 +0200 Subject: pep384impl.cpp: Make the implementation more stateless The pep384impl.h part is quite readable and stateless concerning the state of Py_LIMITED_API. The pep384impl.cpp part is stateful, which means there is no clear separation between parts of the implementation. This had led to unnecessary confusion in the past. To avoid that in future, the #ifdef status of Py_LIMITED_API will no longer be carried over multiple sections. Also, checks which are for the limited API only are no longer executed by default. Further, PyDict_GetItem is replaced by PyDict_GetItemWithError, where we do not expect a real error. Change-Id: Ia51e551216c76f82b701ebc45c40e2d1412cabf5 Reviewed-by: Cristian Maureira-Fredes --- sources/shiboken2/libshiboken/pep384impl.cpp | 77 +++++++++++++++------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 9f51034f3..c04848eb3 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -50,26 +50,19 @@ extern "C" /* * The documentation is located in pep384impl_doc.rst */ - -/***************************************************************************** - * - * Support for object.h - * - */ - +#if PY_VERSION_HEX < 0x03000000 +#define IS_PY2 +#endif // PY_VERSION_HEX < 0x03000000 /* * Here is the verification code for PyTypeObject. * We create a type object and check if its fields * appear at the right offsets. */ +#ifdef Py_LIMITED_API #define make_dummy_int(x) (x * sizeof(void *)) #define make_dummy(x) (reinterpret_cast(make_dummy_int(x))) -#ifdef Py_LIMITED_API -datetime_struc *PyDateTimeAPI = nullptr; -#endif - static PyObject * dummy_func(PyObject * /* self */, PyObject * /* args */) { @@ -180,18 +173,18 @@ check_PyTypeObject_valid() Py_DECREF(probe_tp_mro); } - -#ifdef Py_LIMITED_API - #if PY_VERSION_HEX < PY_ISSUE33738_SOLVED #include "pep384_issue33738.cpp" #endif +#endif // Py_LIMITED_API + /***************************************************************************** * * Support for unicodeobject.h * */ +#ifdef Py_LIMITED_API char * _PepUnicode_AsString(PyObject *str) @@ -214,7 +207,7 @@ _PepUnicode_AsString(PyObject *str) Py_FatalError("Error in " AT); } PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", nullptr); - PyObject *entry = PyDict_GetItem(cstring_dict, bytesStr); + PyObject *entry = PyDict_GetItemWithError(cstring_dict, bytesStr); if (entry == nullptr) { int e = PyDict_SetItem(cstring_dict, bytesStr, bytesStr); if (e != 0) @@ -225,12 +218,14 @@ _PepUnicode_AsString(PyObject *str) Py_DECREF(bytesStr); return PyBytes_AsString(entry); } +#endif // Py_LIMITED_API /***************************************************************************** * * Support for longobject.h * */ +#ifdef Py_LIMITED_API /* * This is the original Python function _PyLong_AsInt() from longobject.c . @@ -255,12 +250,15 @@ _PepLong_AsInt(PyObject *obj) } return int(result); } +#endif // Py_LIMITED_API /***************************************************************************** * * Support for pydebug.h * */ +#ifdef Py_LIMITED_API + static PyObject *sys_flags = nullptr; int @@ -299,12 +297,14 @@ Pep_GetVerboseFlag() } return verbose_flag; } +#endif // Py_LIMITED_API /***************************************************************************** * * Support for code.h * */ +#ifdef Py_LIMITED_API int PepCode_Get(PyCodeObject *co, const char *name) @@ -321,12 +321,16 @@ PepCode_Get(PyCodeObject *co, const char *name) } return ret; } +#endif // Py_LIMITED_API /***************************************************************************** * * Support for datetime.h * */ +#ifdef Py_LIMITED_API + +datetime_struc *PyDateTimeAPI = nullptr; static PyTypeObject *dt_getCheck(const char *name) { @@ -398,12 +402,14 @@ PyTime_FromTime(int hour, int min, int sec, int usec) return PyObject_CallFunction((PyObject *)PyDateTimeAPI->TimeType, (char *)"(iiii)", hour, min, sec, usec); } +#endif // Py_LIMITED_API /***************************************************************************** * * Support for pythonrun.h * */ +#ifdef Py_LIMITED_API // Flags are ignored in these simple helpers. PyObject * @@ -423,7 +429,7 @@ PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) // This is only a simple local helper that returns a computed variable. // Used also in Python 2. -#if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x03000000 +#if defined(Py_LIMITED_API) || defined(IS_PY2) static PyObject * PepRun_GetResult(const char *command) { @@ -440,15 +446,14 @@ PepRun_GetResult(const char *command) Py_DECREF(d); return res; } -#endif // Py_LIMITED_API || Python 2 - -#ifdef Py_LIMITED_API +#endif // defined(Py_LIMITED_API) || defined(IS_PY2) /***************************************************************************** * * Support for classobject.h * */ +#ifdef Py_LIMITED_API PyTypeObject *PepMethod_TypePtr = nullptr; @@ -489,12 +494,14 @@ PyMethod_Self(PyObject *im) Py_DECREF(ret); return ret; } +#endif // Py_LIMITED_API /***************************************************************************** * * Support for funcobject.h * */ +#ifdef Py_LIMITED_API PyObject * PepFunction_Get(PyObject *ob, const char *name) @@ -517,7 +524,6 @@ static PyTypeObject *getFunctionType(void) "from types import FunctionType as result\n"; return reinterpret_cast(PepRun_GetResult(prog)); } - #endif // Py_LIMITED_API || Python 2 /***************************************************************************** @@ -527,7 +533,7 @@ static PyTypeObject *getFunctionType(void) */ // PYSIDE-803, PYSIDE-813: We need that GIL-free version from Python 2.7.12 . -#if PY_VERSION_HEX < 0x03000000 +#ifdef IS_PY2 /* Variant of PyDict_GetItem() that doesn't suppress exceptions. This returns NULL *with* an exception set if an exception occurred. @@ -558,15 +564,13 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key) } return ep->me_value; } - -#endif +#endif // IS_PY2 /***************************************************************************** * * Extra support for signature.cpp * */ - #ifdef Py_LIMITED_API PyTypeObject *PepStaticMethod_TypePtr = nullptr; @@ -601,7 +605,7 @@ PyStaticMethod_New(PyObject *callable) } #endif // Py_LIMITED_API -#if PY_VERSION_HEX < 0x03000000 +#ifdef IS_PY2 PyTypeObject *PepMethodDescr_TypePtr = nullptr; static PyTypeObject * @@ -611,7 +615,7 @@ getMethodDescrType(void) "result = type(str.split)\n"; return reinterpret_cast(PepRun_GetResult(prog)); } -#endif +#endif // IS_PY2 /***************************************************************************** * @@ -640,9 +644,9 @@ PepType_GetNameStr(PyTypeObject *type) #ifdef Py_LIMITED_API // We keep these definitions local, because they don't work in Python 2. -#define PyUnicode_GET_LENGTH(op) PyUnicode_GetLength((PyObject *)(op)) -#define PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar((PyObject *)(u), (i)) -#endif +# define PyUnicode_GET_LENGTH(op) PyUnicode_GetLength((PyObject *)(op)) +# define PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar((PyObject *)(u), (i)) +#endif // Py_LIMITED_API PyObject * _Pep_PrivateMangle(PyObject *self, PyObject *name) @@ -652,7 +656,7 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name) * This function is modelled after _Py_Mangle, but is optimized * a little for our purpose. */ -#if PY_VERSION_HEX < 0X03000000 +#ifdef IS_PY2 const char *namestr = PyString_AsString(name); if (namestr == nullptr || namestr[0] != '_' || namestr[1] != '_') { Py_INCREF(name); @@ -679,7 +683,7 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name) Py_INCREF(name); return name; } -#endif +#endif // IS_PY2 Shiboken::AutoDecRef privateobj(PyObject_GetAttr( reinterpret_cast(Py_TYPE(self)), Shiboken::PyMagicName::name())); #ifndef Py_LIMITED_API @@ -718,7 +722,7 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name) if (amount > big_stack) free(resbuf); return result; -#endif // Py_LIMITED_API +#endif // else Py_LIMITED_API } /***************************************************************************** @@ -749,17 +753,18 @@ init_PepRuntime() void Pep384_Init() { - check_PyTypeObject_valid(); init_PepRuntime(); #ifdef Py_LIMITED_API + check_PyTypeObject_valid(); Pep_GetVerboseFlag(); PepMethod_TypePtr = getMethodType(); PepFunction_TypePtr = getFunctionType(); PepStaticMethod_TypePtr = getStaticMethodType(); -#endif -#if PY_VERSION_HEX < 0x03000000 +#endif // Py_LIMITED_API + +#ifdef IS_PY2 PepMethodDescr_TypePtr = getMethodDescrType(); -#endif +#endif // IS_PY2 } } // extern "C" -- cgit v1.2.3 From 7e0d430cda22f454bc1cd81ced1f691f3efbb212 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Mon, 6 Apr 2020 12:40:26 +0200 Subject: Relax the build_scripts for macOS and designer The build_scripts are able to build Designer, optionally. For macOS, the optional status was forgotten. Instead of always patching the build_scripts, I finally fixed that buglet ;-) Change-Id: Iaa62e27253ec7035f0eebde17f0f2b8c4593be67 Reviewed-by: Friedemann Kleint --- build_scripts/platforms/unix.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_scripts/platforms/unix.py b/build_scripts/platforms/unix.py index abca942b9..fcbd010e2 100644 --- a/build_scripts/platforms/unix.py +++ b/build_scripts/platforms/unix.py @@ -144,8 +144,8 @@ def prepare_packages_posix(self, vars): executables.extend(copydir( "{install_dir}/bin/Designer.app", "{st_build_dir}/{st_package_name}/Designer.app", - filter=None, - recursive=True, vars=vars)) + filter=None, recursive=True, + force=False, vars=vars)) else: copyfile( "{install_dir}/bin/designer", -- cgit v1.2.3 From 4fc3a3ac713cdde1453619ecf1116604c36d82b5 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 11 Mar 2020 11:13:15 +0100 Subject: Fix alloc-dealloc-mismatch in MetaObjectBuilder QMetaObjectBuilder::toMetaObject uses malloc to allocate the space for the returned QMetaObject. As such, we need to use free instead of delete, otherwise ASAN will report an error: ``` 39: ==1537629==ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator delete) on 0x61200006cf40 39: #0 0x7f7952f00960 in operator delete(void*) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cc:165 39: #1 0x7f7930c4d8d4 in void qDeleteAll<__gnu_cxx::__normal_iterator > > >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >) /usr/include/qt/QtCore/qalgorithms.h:320 39: #2 0x7f7930c4cf98 in void qDeleteAll > >(std::vector > const&) /usr/include/qt/QtCore/qalgorithms.h:328 39: #3 0x7f7930c4a847 in PySide::MetaObjectBuilder::~MetaObjectBuilder() ../3rdParty/PySide2/sources/pyside2/libpyside/dynamicqmetaobject.cpp:143 39: #4 0x7f7930c54c8f in PySide::GlobalReceiverV2::~GlobalReceiverV2() ../3rdParty/PySide2/sources/pyside2/libpyside/globalreceiverv2.cpp:208 39: #5 0x7f7930c54ccf in PySide::GlobalReceiverV2::~GlobalReceiverV2() ../3rdParty/PySide2/sources/pyside2/libpyside/globalreceiverv2.cpp:223 39: #6 0x7f7930c54f63 in PySide::GlobalReceiverV2::decRef(QObject const*) ../3rdParty/PySide2/sources/pyside2/libpyside/globalreceiverv2.cpp:271 39: #7 0x7f7930c553fc in PySide::GlobalReceiverV2::qt_metacall(QMetaObject::Call, int, void**) ../3rdParty/PySide2/sources/pyside2/libpyside/globalreceiverv2.cpp:338 39: #8 0x7f7941d2e251 (/usr/lib/libQt5Core.so.5+0x2db251) 39: #9 0x7f7941d28bef in QObject::destroyed(QObject*) (/usr/lib/libQt5Core.so.5+0x2d5bef) 39: #10 0x7f7941d2c8d6 in QObject::~QObject() (/usr/lib/libQt5Core.so.5+0x2d98d6) 39: 39: 0x61200006cf40 is located 0 bytes inside of 264-byte region [0x61200006cf40,0x61200006d048) 39: allocated by thread T0 here: 39: #0 0x7f7952efdd48 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:153 39: #1 0x7f7941d1d742 in QMetaObjectBuilder::toMetaObject() const (/usr/lib/libQt5Core.so.5+0x2ca742) 39: #2 0x7f7930c4bb88 in PySide::MetaObjectBuilder::update() ../3rdParty/PySide2/sources/pyside2/libpyside/dynamicqmetaobject.cpp:425 39: #3 0x7f7930c54a85 in PySide::GlobalReceiverV2::GlobalReceiverV2(_object*, QSharedPointer >) ../3rdParty/PySide2/sources/pyside2/libpyside/globalreceiverv2.cpp:195 39: #4 0x7f7930c50a70 in PySide::SignalManager::globalReceiver(QObject*, _object*) ../3rdParty/PySide2/sources/pyside2/libpyside/signalmanager.cpp:313 39: #5 0x7f792ec3b257 in getReceiver 3rdParty/PySide2/sources/pyside2/PySide2/QtCore/PySide2/QtCore/qobject_wrapper.cpp:155 39: #6 0x7f792ec3b67f in qobjectConnectCallback 3rdParty/PySide2/sources/pyside2/PySide2/QtCore/PySide2/QtCore/qobject_wrapper.cpp:205 39: #7 0x7f792ec3e5b9 in Sbk_QObjectFunc_connect 3rdParty/PySide2/sources/pyside2/PySide2/QtCore/PySide2/QtCore/qobject_wrapper.cpp:944 39: #8 0x7f7943a66250 in PyObject_Call (/usr/lib/libpython3.8.so.1.0+0x13c250) ``` Change-Id: I8c5a745fab9785425c0844129731c7c8a17b8d21 Reviewed-by: Friedemann Kleint --- sources/pyside2/libpyside/dynamicqmetaobject.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp index 51e6598b3..dae9e2059 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp @@ -140,7 +140,8 @@ MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *meta MetaObjectBuilder::~MetaObjectBuilder() { - qDeleteAll(m_d->m_cachedMetaObjects); + for (auto *metaObject : m_d->m_cachedMetaObjects) + free(const_cast(metaObject)); delete m_d->m_builder; delete m_d; } -- cgit v1.2.3 From 52299827c64cccc1456f9050fdf3dd8596df3e6f Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Wed, 8 Apr 2020 14:46:03 +0200 Subject: shiboken: Fix race condition with unprotected Py_INCREFs The signalmanager module contains a PyObjectWrapper object into which PySide::SignalManager::qt_metacall calls via many hard-to-track indirections. Finding this problem was quite tricky. It was done by modifying the Py_INCREF and Py_DECREF macros of a debug Python interpreter and using the new PyGILState_Check function to provoke a crash if the GIL was not held. See the online documentation for details. Change-Id: Ida8246c97dcf6443ff057d206a42d22e462f1913 Fixes: PYSIDE-813 Reviewed-by: Cristian Maureira-Fredes Reviewed-by: Friedemann Kleint --- sources/pyside2/libpyside/signalmanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sources/pyside2/libpyside/signalmanager.cpp b/sources/pyside2/libpyside/signalmanager.cpp index 0fe0d0092..8e8cc9f02 100644 --- a/sources/pyside2/libpyside/signalmanager.cpp +++ b/sources/pyside2/libpyside/signalmanager.cpp @@ -114,18 +114,24 @@ namespace PySide { PyObjectWrapper::PyObjectWrapper() :m_me(Py_None) { + // PYSIDE-813: When PYSIDE-164 was solved by adding some thread allowance, + // this code was no longer protected. It was hard to find this connection. + // See the website https://bugreports.qt.io/browse/PYSIDE-813 for details. + Shiboken::GilState gil; Py_XINCREF(m_me); } PyObjectWrapper::PyObjectWrapper(PyObject *me) : m_me(me) { + Shiboken::GilState gil; Py_XINCREF(m_me); } PyObjectWrapper::PyObjectWrapper(const PyObjectWrapper &other) : m_me(other.m_me) { + Shiboken::GilState gil; Py_XINCREF(m_me); } @@ -142,6 +148,7 @@ PyObjectWrapper::~PyObjectWrapper() void PyObjectWrapper::reset(PyObject *o) { + Shiboken::GilState gil; Py_XINCREF(o); Py_XDECREF(m_me); m_me = o; -- cgit v1.2.3 From 8df43d8c9d704a3abcc58b8ba84fc6fbfee2c433 Mon Sep 17 00:00:00 2001 From: Cristian Maureira-Fredes Date: Fri, 10 Apr 2020 22:59:13 +0200 Subject: doc: fix error in shiboken getting started Fixes: PYSIDE-1266 Change-Id: Ia0aafb1f0e91b5baf070c018d4583e64f2c92f8c Reviewed-by: Friedemann Kleint --- sources/shiboken2/doc/gettingstarted.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/shiboken2/doc/gettingstarted.rst b/sources/shiboken2/doc/gettingstarted.rst index e064cec5d..caeb5a909 100644 --- a/sources/shiboken2/doc/gettingstarted.rst +++ b/sources/shiboken2/doc/gettingstarted.rst @@ -28,9 +28,9 @@ If you need only Shiboken Generator, a simple build run would look like this:: --build-tests \ --parallel=8 \ --verbose-build \ - --internal-build=shiboken2-generator + --internal-build-type=shiboken2-generator -The same can be used for the module, changing the value of ``internal-build`` to +The same can be used for the module, changing the value of ``internal-build-type`` to ``shiboken2-module``. Using the wheels -- cgit v1.2.3