aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-05-26 07:40:56 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-05-26 07:41:36 +0200
commit49c4d1f31014605c9355b1f6901e28e5762301d1 (patch)
tree8293343bf138ef2d53ab118b667fe1205d2b0bd7
parent10390cc16084c5f386163664f6e42d9e4d28b129 (diff)
parent6717d3540fac74c91d9381958a08e60f6532d402 (diff)
Merge remote-tracking branch 'origin/5.14' into 5.15
-rw-r--r--sources/pyside2/PySide2/QtCore/typesystem_core_common.xml4
-rw-r--r--sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml36
-rw-r--r--sources/pyside2/PySide2/glue/qtcore.cpp16
-rw-r--r--sources/pyside2/PySide2/glue/qtuitools.cpp138
-rw-r--r--sources/pyside2/PySide2/support/deprecated.py2
-rw-r--r--sources/pyside2/PySide2/support/generate_pyi.py8
-rw-r--r--sources/pyside2/doc/inheritance_diagram.py2
-rw-r--r--sources/pyside2/libpyside/pysideweakref.cpp5
-rw-r--r--sources/pyside2/tests/QtCore/qenum_test.py50
-rw-r--r--sources/pyside2/tests/QtUiTools/loadUiType_test.py75
-rw-r--r--sources/pyside2/tests/QtWidgets/qwidget_test.py4
-rw-r--r--sources/pyside2/tests/registry/existence_test.py16
-rw-r--r--sources/shiboken2/ApiExtractor/CMakeLists.txt2
-rw-r--r--sources/shiboken2/generator/CMakeLists.txt2
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp55
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp32
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.h10
-rw-r--r--sources/shiboken2/libshiboken/sbkenum.cpp143
-rw-r--r--sources/shiboken2/libshiboken/sbkenum.h2
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp46
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py17
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py2
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py2
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py16
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py10
-rw-r--r--sources/shiboken2/shibokenmodule/typesystem_shiboken.xml6
-rw-r--r--sources/shiboken2/tests/shiboken_test_helper.py6
27 files changed, 641 insertions, 66 deletions
diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
index 272f9a766..c27029f03 100644
--- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
+++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
@@ -223,9 +223,9 @@
</primitive-type>
<primitive-type name="quintptr" target-lang-api-name="PyLong">
<conversion-rule>
- <native-to-target file="../glue/qtcore.cpp" snippet="return-pylong-unsigned"/>
+ <native-to-target file="../glue/qtcore.cpp" snippet="return-pylong-quintptr"/>
<target-to-native>
- <add-conversion type="PyLong" file="../glue/qtcore.cpp" snippet="conversion-pylong-unsigned"/>
+ <add-conversion type="PyLong" file="../glue/qtcore.cpp" snippet="conversion-pylong-quintptr"/>
</target-to-native>
</conversion-rule>
</primitive-type>
diff --git a/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml b/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml
index 7b27e8783..2ca12e788 100644
--- a/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml
+++ b/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml
@@ -139,4 +139,40 @@
</add-function>
</object-type>
+ <!--
+ After the removal of the 'pysideuic' Python module, many users were unable to generate and
+ load UI classes dynamically.
+ This function was created to provide an equivalent solution to the 'loadUiType' function from
+ Riverbank's PyQt.
+ -->
+ <add-function signature="loadUiType(const QString&amp; @uifile@)" return-type="PyObject*">
+ <inject-documentation format="target" mode="append">
+ This function will allow users to generate and load a `.ui` file at runtime, and it returns
+ a `tuple` containing the reference to the Python class, and the base class.
+
+ We don't recommend this approach since the workflow should be to generate a Python file
+ from the `.ui` file, and then import and load it to use it, but we do understand that
+ there are some corner cases when such functionality is required.
+
+ The internal process relies on `uic` being in the PATH, which is the same requirement for
+ the new `pyside2-uic` to work (which is just a wrapper around `uic -g python`)
+
+ A Simple use can be:
+
+ .. code-block:: python
+
+ from PySide2.QtUiTools import loadUiType
+
+ generated_class, base_class = loadUiType("themewidget.ui")
+ # the values will be:
+ # (&lt;class '__main__.Ui_ThemeWidgetForm'&gt;, &lt;class 'PySide2.QtWidgets.QWidget'&gt;)
+
+
+ In that case, `generated_class` will be a reference to the Python class,
+ and `base_class` will be a reference to the base class.
+ </inject-documentation>
+ <inject-code file="../glue/qtuitools.cpp" snippet="loaduitype"/>
+ </add-function>
+
+
</typesystem>
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp
index 83c8f8656..9b927cce4 100644
--- a/sources/pyside2/PySide2/glue/qtcore.cpp
+++ b/sources/pyside2/PySide2/glue/qtcore.cpp
@@ -1678,6 +1678,14 @@ Py_END_ALLOW_THREADS
%out = %OUTTYPE(PyLong_AsUnsignedLong(%in));
// @snippet conversion-pylong-unsigned
+// @snippet conversion-pylong-quintptr
+#if defined(IS_PY3K) && QT_POINTER_SIZE == 8
+%out = %OUTTYPE(PyLong_AsUnsignedLongLong(%in));
+#else
+%out = %OUTTYPE(PyLong_AsUnsignedLong(%in));
+#endif
+// @snippet conversion-pylong-quintptr
+
// @snippet conversion-pyunicode
#ifndef Py_LIMITED_API
Py_UNICODE *unicode = PyUnicode_AS_UNICODE(%in);
@@ -1878,6 +1886,14 @@ return PyLong_FromLong(%in);
return PyLong_FromUnsignedLong(%in);
// @snippet return-pylong-unsigned
+// @snippet return-pylong-quintptr
+#if defined(IS_PY3K) && QT_POINTER_SIZE == 8
+return PyLong_FromUnsignedLongLong(%in);
+#else
+return PyLong_FromUnsignedLong(%in);
+#endif
+// @snippet return-pylong-quintptr
+
// @snippet return-pyunicode
QByteArray ba = %in.toUtf8();
return PyUnicode_FromStringAndSize(ba.constData(), ba.size());
diff --git a/sources/pyside2/PySide2/glue/qtuitools.cpp b/sources/pyside2/PySide2/glue/qtuitools.cpp
index 00fc8e44a..668b512e4 100644
--- a/sources/pyside2/PySide2/glue/qtuitools.cpp
+++ b/sources/pyside2/PySide2/glue/qtuitools.cpp
@@ -109,3 +109,141 @@ registerCustomWidget(%PYARG_1);
// Avoid calling the original function: %CPPSELF.%FUNCTION_NAME()
%PYARG_0 = QUiLoaderLoadUiFromFileName(%CPPSELF, %1, %2);
// @snippet quiloader-load-2
+
+// @snippet loaduitype
+/*
+Arguments:
+ %PYARG_1 (uifile)
+*/
+// 1. Generate the Python code from the UI file
+#ifdef IS_PY3K
+PyObject *strObj = PyUnicode_AsUTF8String(%PYARG_1);
+char *arg1 = PyBytes_AsString(strObj);
+QByteArray uiFileName(arg1);
+Py_DECREF(strObj);
+#else
+QByteArray uiFileName(PyBytes_AsString(%PYARG_1));
+#endif
+
+QFile uiFile(uiFileName);
+
+if (!uiFile.exists()) {
+ qCritical().noquote() << "File" << uiFileName << "does not exists";
+ Py_RETURN_NONE;
+}
+
+if (uiFileName.isEmpty()) {
+ qCritical() << "Error converting the UI filename to QByteArray";
+ Py_RETURN_NONE;
+}
+
+QString uicBin("uic");
+QStringList uicArgs = {"-g", "python", QString::fromUtf8(uiFileName)};
+
+QProcess uicProcess;
+uicProcess.start(uicBin, uicArgs);
+if (!uicProcess.waitForFinished()) {
+ qCritical() << "Cannot run 'uic': " << uicProcess.errorString() << " - "
+ << "Exit status " << uicProcess.exitStatus()
+ << " (" << uicProcess.exitCode() << ")\n"
+ << "Check if 'uic' is in PATH";
+ Py_RETURN_NONE;
+}
+QByteArray uiFileContent = uicProcess.readAllStandardOutput();
+QByteArray errorOutput = uicProcess.readAllStandardError();
+
+if (!errorOutput.isEmpty()) {
+ qCritical().noquote() << errorOutput;
+ Py_RETURN_NONE;
+}
+
+// 2. Obtain the 'classname' and the Qt base class.
+QByteArray className;
+QByteArray baseClassName;
+
+// Problem
+// The generated Python file doesn't have the Qt Base class information.
+
+// Solution
+// Use the XML file
+if (!uiFile.open(QIODevice::ReadOnly))
+ Py_RETURN_NONE;
+
+// This will look for the first <widget> tag, e.g.:
+// <widget class="QWidget" name="ThemeWidgetForm">
+// and then extract the information from "class", and "name",
+// to get the baseClassName and className respectively
+QXmlStreamReader reader(&uiFile);
+while (!reader.atEnd() && baseClassName.isEmpty() && className.isEmpty()) {
+ auto token = reader.readNext();
+ if (token == QXmlStreamReader::StartElement && reader.name() == "widget") {
+ baseClassName = reader.attributes().value(QLatin1String("class")).toUtf8();
+ className = reader.attributes().value(QLatin1String("name")).toUtf8();
+ }
+}
+
+uiFile.close();
+
+if (className.isEmpty() || baseClassName.isEmpty() || reader.hasError()) {
+ qCritical() << "An error occurred when parsing the UI file while looking for the class info "
+ << reader.errorString();
+ Py_RETURN_NONE;
+}
+
+QByteArray pyClassName("Ui_"+className);
+
+PyObject *module = PyImport_ImportModule("__main__");
+PyObject *loc = PyModule_GetDict(module);
+
+// 3. exec() the code so the class exists in the context: exec(uiFileContent)
+// The context of PyRun_SimpleString is __main__.
+// 'Py_file_input' is the equivalent to using exec(), since it will execute
+// the code, without returning anything.
+Shiboken::AutoDecRef codeUi(Py_CompileString(uiFileContent.constData(), "<stdin>", Py_file_input));
+if (codeUi.isNull()) {
+ qCritical() << "Error while compiling the generated Python file";
+ Py_RETURN_NONE;
+}
+PyObject *uiObj = nullptr;
+#ifdef IS_PY3K
+uiObj = PyEval_EvalCode(codeUi, loc, loc);
+#else
+uiObj = PyEval_EvalCode(reinterpret_cast<PyCodeObject *>(codeUi.object()), loc, loc);
+#endif
+
+if (uiObj == nullptr) {
+ qCritical() << "Error while running exec() on the generated code";
+ Py_RETURN_NONE;
+}
+
+// 4. eval() the name of the class on a variable to return
+// 'Py_eval_input' is the equivalent to using eval(), since it will just
+// evaluate an expression.
+Shiboken::AutoDecRef codeClass(Py_CompileString(pyClassName.constData(),"<stdin>", Py_eval_input));
+if (codeClass.isNull()) {
+ qCritical() << "Error while compiling the Python class";
+ Py_RETURN_NONE;
+}
+
+Shiboken::AutoDecRef codeBaseClass(Py_CompileString(baseClassName.constData(), "<stdin>", Py_eval_input));
+if (codeBaseClass.isNull()) {
+ qCritical() << "Error while compiling the base class";
+ Py_RETURN_NONE;
+}
+
+#ifdef IS_PY3K
+PyObject *classObj = PyEval_EvalCode(codeClass, loc, loc);
+PyObject *baseClassObj = PyEval_EvalCode(codeBaseClass, loc, loc);
+#else
+PyObject *classObj = PyEval_EvalCode(reinterpret_cast<PyCodeObject *>(codeClass.object()), loc, loc);
+PyObject *baseClassObj = PyEval_EvalCode(reinterpret_cast<PyCodeObject *>(codeBaseClass.object()), loc, loc);
+#endif
+
+%PYARG_0 = PyTuple_New(2);
+if (%PYARG_0 == nullptr) {
+ qCritical() << "Error while creating the return Tuple";
+ Py_RETURN_NONE;
+}
+PyTuple_SET_ITEM(%PYARG_0, 0, classObj);
+PyTuple_SET_ITEM(%PYARG_0, 1, baseClassObj);
+// @snippet loaduitype
diff --git a/sources/pyside2/PySide2/support/deprecated.py b/sources/pyside2/PySide2/support/deprecated.py
index 8538826e4..57f33d9e2 100644
--- a/sources/pyside2/PySide2/support/deprecated.py
+++ b/sources/pyside2/PySide2/support/deprecated.py
@@ -64,7 +64,7 @@ class PySideDeprecationWarningRemovedInQt6(Warning):
def constData(self):
cls = self.__class__
- name = cls.__name__
+ name = cls.__qualname__
warnings.warn(dedent("""
{name}.constData is unpythonic and will be removed in Qt For Python 6.0 .
Please use {name}.data instead."""
diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py
index f92367c82..af9f4d4f5 100644
--- a/sources/pyside2/PySide2/support/generate_pyi.py
+++ b/sources/pyside2/PySide2/support/generate_pyi.py
@@ -1,7 +1,7 @@
# This Python file uses the following encoding: utf-8
#############################################################################
##
-## Copyright (C) 2019 The Qt Company Ltd.
+## Copyright (C) 2020 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -169,12 +169,6 @@ class Formatter(Writer):
else:
self.print("{spaces}class {class_str}: ...".format(**locals()))
yield
- if "<" in class_name:
- # This is happening in QtQuick for some reason:
- ## class QSharedPointer<QQuickItemGrabResult >:
- # We simply skip over this class.
- self.outfile.seek(here)
- self.outfile.truncate()
@contextmanager
def function(self, func_name, signature, modifier=None):
diff --git a/sources/pyside2/doc/inheritance_diagram.py b/sources/pyside2/doc/inheritance_diagram.py
index 054cb7be9..875e17b50 100644
--- a/sources/pyside2/doc/inheritance_diagram.py
+++ b/sources/pyside2/doc/inheritance_diagram.py
@@ -176,7 +176,7 @@ class InheritanceGraph(object):
if module == '__builtin__':
fullname = cls.__name__
else:
- fullname = '%s.%s' % (module, cls.__name__)
+ fullname = '%s.%s' % (module, cls.__qualname__)
if parts == 0:
return fullname
name_parts = fullname.split('.')
diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp
index 84b390e96..cd90634bd 100644
--- a/sources/pyside2/libpyside/pysideweakref.cpp
+++ b/sources/pyside2/libpyside/pysideweakref.cpp
@@ -98,11 +98,6 @@ PyObject *create(PyObject *obj, PySideWeakRefFunction func, void *userData)
PySideCallableObject *callable = PyObject_New(PySideCallableObject, type);
if (!callable || PyErr_Occurred())
return 0;
- if (!PepRuntime_38_flag) {
- // PYSIDE-939: Handling references correctly.
- // Workaround for Python issue 35810; no longer necessary in Python 3.8
- Py_INCREF(type);
- }
PyObject *weak = PyWeakref_NewRef(obj, reinterpret_cast<PyObject *>(callable));
if (!weak || PyErr_Occurred())
diff --git a/sources/pyside2/tests/QtCore/qenum_test.py b/sources/pyside2/tests/QtCore/qenum_test.py
index dd91d1581..1edb8981a 100644
--- a/sources/pyside2/tests/QtCore/qenum_test.py
+++ b/sources/pyside2/tests/QtCore/qenum_test.py
@@ -30,15 +30,18 @@
'''Test cases for QEnum and QFlags'''
+import gc
import os
import sys
+import pickle
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 *
+from PySide2.QtCore import Qt, QIODevice
+
class TestEnum(unittest.TestCase):
@@ -73,6 +76,23 @@ class TestEnum(unittest.TestCase):
with self.assertRaises(TypeError):
a = k*2.0
+ @unittest.skipUnless(getattr(sys, "getobjects", None), "requires debug build")
+ def testEnumNew_NoLeak(self):
+ gc.collect()
+ total = sys.gettotalrefcount()
+ for idx in range(1000):
+ ret = Qt.Key(42)
+ gc.collect()
+ delta = sys.gettotalrefcount() - total
+ print("delta total refcount =", delta)
+ if abs(delta) >= 10:
+ all = sys.getobjects(0)
+ all.sort(key=lambda x: sys.getrefcount(x), reverse=True)
+ for ob in all[:10]:
+ print(sys.getrefcount(ob), ob)
+ self.assertTrue(abs(delta) < 10)
+
+
class TestQFlags(unittest.TestCase):
def testToItn(self):
om = QIODevice.NotOpen
@@ -94,5 +114,33 @@ class TestQFlags(unittest.TestCase):
except:
pass
+
+# PYSIDE-15: Pickling of enums
+class TestEnumPickling(unittest.TestCase):
+ def testPickleEnum(self):
+
+ # Pickling of enums with different depth works.
+ ret = pickle.loads(pickle.dumps(QIODevice.Append))
+ self.assertEqual(ret, QIODevice.Append)
+
+ ret = pickle.loads(pickle.dumps(Qt.Key.Key_Asterisk))
+ self.assertEqual(ret, Qt.Key.Key_Asterisk)
+ self.assertEqual(ret, Qt.Key(42))
+
+ # We can also pickle the whole enum class (built in):
+ ret = pickle.loads(pickle.dumps(QIODevice))
+
+ # This works also with nested classes for Python 3, after we
+ # introduced the correct __qualname__ attribute.
+
+ # Note: For Python 2, we would need quite strange patches.
+ func = lambda: pickle.loads(pickle.dumps(Qt.Key))
+ if sys.version_info[0] < 3:
+ with self.assertRaises(pickle.PicklingError):
+ func()
+ else:
+ func()
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtUiTools/loadUiType_test.py b/sources/pyside2/tests/QtUiTools/loadUiType_test.py
new file mode 100644
index 000000000..9a3756376
--- /dev/null
+++ b/sources/pyside2/tests/QtUiTools/loadUiType_test.py
@@ -0,0 +1,75 @@
+#############################################################################
+##
+## 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 helper.usesqapplication import UsesQApplication
+
+from PySide2.QtWidgets import QWidget, QFrame, QPushButton
+from PySide2.QtUiTools import loadUiType
+
+class loadUiTypeTester(UsesQApplication):
+ def testFunction(self):
+ filePath = os.path.join(os.path.dirname(__file__), "minimal.ui")
+ loaded = loadUiType(filePath)
+ self.assertNotEqual(loaded, None)
+
+ # (<class '__main__.Ui_Form'>, <class 'PySide2.QtWidgets.QFrame'>)
+ generated, base = loaded
+
+ # Generated class contains retranslateUi method
+ self.assertTrue("retranslateUi" in dir(generated))
+
+ # Base class instance will be QFrame for this example
+ self.assertTrue(isinstance(base(), QFrame))
+
+ anotherFileName = os.path.join(os.path.dirname(__file__), "test.ui")
+ another = loadUiType(anotherFileName)
+ self.assertNotEqual(another, None)
+
+ generated, base = another
+ # Base class instance will be QWidget for this example
+ self.assertTrue(isinstance(base(), QWidget))
+
+ w = base()
+ ui = generated()
+ ui.setupUi(w)
+
+ self.assertTrue(isinstance(ui.child_object, QFrame))
+ self.assertTrue(isinstance(ui.grandson_object, QPushButton))
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/sources/pyside2/tests/QtWidgets/qwidget_test.py b/sources/pyside2/tests/QtWidgets/qwidget_test.py
index 74e97d7be..5e94a8248 100644
--- a/sources/pyside2/tests/QtWidgets/qwidget_test.py
+++ b/sources/pyside2/tests/QtWidgets/qwidget_test.py
@@ -61,7 +61,9 @@ class QWidgetTest(UsesQApplication):
if sys.version_info[0] < 3:
def testCallType_Issue_816(self):
thing = type(QWidget).__new__(type(QWidget), "", (), {})
- self.assertEqual(repr(thing), "<class '__main__.'>")
+ # PYSIDE-1286: This works now like in Python 3
+ #self.assertEqual(repr(thing), "<class '__main__.'>")
+ self.assertEqual(repr(thing), "<class '__main__.ObjectType'>")
class QWidgetVisible(UsesQApplication):
diff --git a/sources/pyside2/tests/registry/existence_test.py b/sources/pyside2/tests/registry/existence_test.py
index 4bfd63cc3..b8a42058d 100644
--- a/sources/pyside2/tests/registry/existence_test.py
+++ b/sources/pyside2/tests/registry/existence_test.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2019 The Qt Company Ltd.
+## Copyright (C) 2020 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -67,6 +67,7 @@ List entry
"""
import os
+import re
import sys
from textwrap import dedent
import unittest
@@ -144,8 +145,19 @@ class TestSignaturesExists(unittest.TestCase):
name = key.rsplit(".", 1)[-1]
if name in ("next", "__next__"): # ignore problematic cases
continue
+ if "<" in key:
+ # Skip over remaining crap in "<...>"
+ continue
+ if key.startswith("sample.SampleNamespace"):
+ # We cannot work with sample namespaces after the change to __qualname__.
+ continue
+ if (key.startswith("smart.SharedPtr") or
+ re.match(r"PySide2\..*?\.QSharedPointer_", key)):
+ # These mangled names are not supported.
+ # We should fix them.
+ continue
if key not in found_sigs:
- warn("missing key: '{}'".format(key), stacklevel=3)
+ warn("missing key: '{} value={}'".format(key, value), stacklevel=3)
else:
found_val = found_sigs[key]
if type(value) is list and (
diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt
index de6bf019f..f8e504583 100644
--- a/sources/shiboken2/ApiExtractor/CMakeLists.txt
+++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt
@@ -84,7 +84,7 @@ endif()
target_compile_definitions(apiextractor PRIVATE CMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}")
-set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE)
+set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE)
if (BUILD_TESTS)
find_package(Qt${QT_MAJOR_VERSION}Test 5.12 REQUIRED)
diff --git a/sources/shiboken2/generator/CMakeLists.txt b/sources/shiboken2/generator/CMakeLists.txt
index e311d400e..1a3f4e5c4 100644
--- a/sources/shiboken2/generator/CMakeLists.txt
+++ b/sources/shiboken2/generator/CMakeLists.txt
@@ -30,7 +30,7 @@ configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h
install(TARGETS shiboken2
EXPORT Shiboken2Targets
- DESTINATION bin)
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
set(shiboken_generator_package_name "shiboken2_generator")
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 5543427fc..443d25cdf 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -104,6 +104,23 @@ static PyGetSetDef SbkObjectType_Type_getsetlist[] = {
{nullptr} // Sentinel
};
+#if PY_VERSION_HEX < 0x03000000
+
+static PyObject *SbkObjectType_repr(PyObject *type)
+{
+ Shiboken::AutoDecRef mod(PyObject_GetAttr(type, Shiboken::PyMagicName::module()));
+ if (mod.isNull())
+ return nullptr;
+ Shiboken::AutoDecRef name(PyObject_GetAttr(type, Shiboken::PyMagicName::qualname()));
+ if (name.isNull())
+ return nullptr;
+ return PyString_FromFormat("<class '%s.%s'>",
+ PyString_AS_STRING(mod.object()),
+ PyString_AS_STRING(name.object()));
+}
+
+#endif // PY_VERSION_HEX < 0x03000000
+
static PyType_Slot SbkObjectType_Type_slots[] = {
{Py_tp_dealloc, reinterpret_cast<void *>(SbkObjectTypeDealloc)},
{Py_tp_setattro, reinterpret_cast<void *>(PyObject_GenericSetAttr)},
@@ -112,6 +129,9 @@ static PyType_Slot SbkObjectType_Type_slots[] = {
{Py_tp_new, reinterpret_cast<void *>(SbkObjectTypeTpNew)},
{Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)},
{Py_tp_getset, reinterpret_cast<void *>(SbkObjectType_Type_getsetlist)},
+#if PY_VERSION_HEX < 0x03000000
+ {Py_tp_repr, reinterpret_cast<void *>(SbkObjectType_repr)},
+#endif
{0, nullptr}
};
static PyType_Spec SbkObjectType_Type_spec = {
@@ -633,11 +653,42 @@ PyObject *SbkType_FromSpec(PyType_Spec *spec)
PyObject *SbkType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
{
+ // PYSIDE-1286: Generate correct __module__ and __qualname__
+ // The name field can now be extended by an "n:" prefix which is
+ // the number of modules in the name. The default is 1.
+ //
+ // Example:
+ // "2:mainmod.submod.mainclass.subclass"
+ // results in
+ // __module__ : "mainmod.submod"
+ // __qualname__ : "mainclass.subclass"
+ // __name__ : "subclass"
+
PyType_Spec new_spec = *spec;
const char *colon = strchr(spec->name, ':');
assert(colon);
- new_spec.name = colon + 1;
- return PyType_FromSpecWithBases(&new_spec, bases);
+ int package_level = atoi(spec->name);
+ const char *mod = new_spec.name = colon + 1;
+
+ PyObject *type = PyType_FromSpecWithBases(&new_spec, bases);
+ if (type == nullptr)
+ return nullptr;
+
+ const char *qual = mod;
+ for (int idx = package_level; idx > 0; --idx) {
+ const char *dot = strchr(qual, '.');
+ if (!dot)
+ break;
+ qual = dot + 1;
+ }
+ int mlen = qual - mod - 1;
+ Shiboken::AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
+ Shiboken::AutoDecRef qualname(Shiboken::String::fromCString(qual));
+ if (PyObject_SetAttr(type, Shiboken::PyMagicName::module(), module) < 0)
+ return nullptr;
+ if (PyObject_SetAttr(type, Shiboken::PyMagicName::qualname(), qualname) < 0)
+ return nullptr;
+ return type;
}
} //extern "C"
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index c04848eb3..f07cac613 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -638,6 +638,38 @@ PepType_GetNameStr(PyTypeObject *type)
/*****************************************************************************
*
+ * Newly introduced convenience functions
+ *
+ */
+#if PY_VERSION_HEX < 0x03070000 || defined(Py_LIMITED_API)
+
+PyObject *
+PyImport_GetModule(PyObject *name)
+{
+ PyObject *m;
+ PyObject *modules = PyImport_GetModuleDict();
+ if (modules == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
+ return NULL;
+ }
+ Py_INCREF(modules);
+ if (PyDict_CheckExact(modules)) {
+ m = PyDict_GetItemWithError(modules, name); /* borrowed */
+ Py_XINCREF(m);
+ }
+ else {
+ m = PyObject_GetItem(modules, name);
+ if (m == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ }
+ }
+ Py_DECREF(modules);
+ return m;
+}
+
+#endif // PY_VERSION_HEX < 0x03070000 || defined(Py_LIMITED_API)
+/*****************************************************************************
+ *
* Extra support for name mangling
*
*/
diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
index e735095e8..541b0e775 100644
--- a/sources/shiboken2/libshiboken/pep384impl.h
+++ b/sources/shiboken2/libshiboken/pep384impl.h
@@ -523,6 +523,16 @@ extern LIBSHIBOKEN_API PyTypeObject *PepMethodDescr_TypePtr;
/*****************************************************************************
*
+ * Newly introduced convenience functions
+ *
+ * This is not defined if Py_LIMITED_API is defined.
+ */
+#if PY_VERSION_HEX < 0x03070000 || defined(Py_LIMITED_API)
+LIBSHIBOKEN_API PyObject *PyImport_GetModule(PyObject *name);
+#endif // PY_VERSION_HEX < 0x03070000 || defined(Py_LIMITED_API)
+
+/*****************************************************************************
+ *
* Runtime support for Python 3.8 incompatibilities
*
*/
diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp
index f49623440..36f2f48f9 100644
--- a/sources/shiboken2/libshiboken/sbkenum.cpp
+++ b/sources/shiboken2/libshiboken/sbkenum.cpp
@@ -107,16 +107,18 @@ static PyObject *SbkEnum_tp_new(PyTypeObject *type, PyObject *args, PyObject *)
if (!self)
return nullptr;
self->ob_value = itemValue;
- PyObject *item = Shiboken::Enum::getEnumItemFromValue(type, itemValue);
- if (item) {
- self->ob_name = SbkEnumObject_name(item, nullptr);
- Py_XDECREF(item);
- } else {
- self->ob_name = nullptr;
- }
+ Shiboken::AutoDecRef item(Shiboken::Enum::getEnumItemFromValue(type, itemValue));
+ self->ob_name = item.object() ? SbkEnumObject_name(item, nullptr) : nullptr;
return reinterpret_cast<PyObject *>(self);
}
+void enum_object_dealloc(PyObject *ob)
+{
+ auto self = reinterpret_cast<SbkEnumObject *>(ob);
+ Py_XDECREF(self->ob_name);
+ Sbk_object_dealloc(ob);
+}
+
static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) {
PyObject *valA = a;
PyObject *valB = b;
@@ -260,6 +262,23 @@ static PyGetSetDef SbkEnumGetSetList[] = {
{nullptr, nullptr, nullptr, nullptr, nullptr} // Sentinel
};
+#if PY_VERSION_HEX < 0x03000000
+
+static PyObject *SbkEnumType_repr(PyObject *type)
+{
+ Shiboken::AutoDecRef mod(PyObject_GetAttr(type, Shiboken::PyMagicName::module()));
+ if (mod.isNull())
+ return nullptr;
+ Shiboken::AutoDecRef name(PyObject_GetAttr(type, Shiboken::PyMagicName::qualname()));
+ if (name.isNull())
+ return nullptr;
+ return PyString_FromFormat("<class '%s.%s'>",
+ PyString_AS_STRING(mod.object()),
+ PyString_AS_STRING(name.object()));
+}
+
+#endif // PY_VERSION_HEX < 0x03000000
+
static void SbkEnumTypeDealloc(PyObject *pyObj);
static PyObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds);
@@ -287,6 +306,9 @@ static PyType_Slot SbkEnumType_Type_slots[] = {
{Py_tp_alloc, (void *)PyType_GenericAlloc},
{Py_tp_new, (void *)SbkEnumTypeTpNew},
{Py_tp_free, (void *)PyObject_GC_Del},
+#if PY_VERSION_HEX < 0x03000000
+ {Py_tp_repr, (void *)SbkEnumType_repr},
+#endif
{0, nullptr}
};
static PyType_Spec SbkEnumType_Type_spec = {
@@ -341,6 +363,107 @@ PyObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwd
} // extern "C"
+///////////////////////////////////////////////////////////////
+//
+// PYSIDE-15: Pickling Support for Qt Enum objects
+// This works very well and fixes the issue.
+//
+extern "C" {
+
+static void init_enum(); // forward
+
+static PyObject *enum_unpickler = nullptr;
+
+// Pickling: reduce the Qt Enum object
+static PyObject *enum___reduce__(PyObject *obj)
+{
+ init_enum();
+ return Py_BuildValue("O(Ni)",
+ enum_unpickler,
+ Py_BuildValue("s", Py_TYPE(obj)->tp_name),
+ PyInt_AS_LONG(obj));
+}
+
+} // extern "C"
+
+namespace Shiboken { namespace Enum {
+
+// Unpickling: rebuild the Qt Enum object
+PyObject *unpickleEnum(PyObject *enum_class_name, PyObject *value)
+{
+ Shiboken::AutoDecRef parts(PyObject_CallMethod(enum_class_name,
+ const_cast<char *>("split"), const_cast<char *>("s"), "."));
+ if (parts.isNull())
+ return nullptr;
+ PyObject *top_name = PyList_GetItem(parts, 0); // borrowed ref
+ if (top_name == nullptr)
+ return nullptr;
+ PyObject *module = PyImport_GetModule(top_name);
+ if (module == nullptr) {
+ PyErr_Format(PyExc_ImportError, "could not import module %.200s",
+ Shiboken::String::toCString(top_name));
+ return nullptr;
+ }
+ Shiboken::AutoDecRef cur_thing(module);
+ int len = PyList_Size(parts);
+ for (int idx = 1; idx < len; ++idx) {
+ PyObject *name = PyList_GetItem(parts, idx); // borrowed ref
+ PyObject *thing = PyObject_GetAttr(cur_thing, name);
+ if (thing == nullptr) {
+ PyErr_Format(PyExc_ImportError, "could not import Qt Enum type %.200s",
+ Shiboken::String::toCString(enum_class_name));
+ return nullptr;
+ }
+ cur_thing.reset(thing);
+ }
+ PyObject *klass = cur_thing;
+ return PyObject_CallFunctionObjArgs(klass, value, nullptr);
+}
+
+} // namespace Enum
+} // namespace Shiboken
+
+extern "C" {
+
+// Initialization
+static bool _init_enum()
+{
+ static PyObject *shiboken_name = Py_BuildValue("s", "shiboken2");
+ if (shiboken_name == nullptr)
+ return false;
+ Shiboken::AutoDecRef shibo(PyImport_GetModule(shiboken_name));
+ if (shibo.isNull())
+ return false;
+ Shiboken::AutoDecRef sub(PyObject_GetAttr(shibo, shiboken_name));
+ PyObject *mod = sub.object();
+ if (mod == nullptr) {
+ // We are in the build dir and already in shiboken.
+ PyErr_Clear();
+ mod = shibo.object();
+ }
+ enum_unpickler = PyObject_GetAttrString(mod, "_unpickle_enum");
+ if (enum_unpickler == nullptr)
+ return false;
+ return true;
+}
+
+static void init_enum()
+{
+ if (!(enum_unpickler || _init_enum()))
+ Py_FatalError("could not load enum pickling helper function");
+}
+
+static PyMethodDef SbkEnumObject_Methods[] = {
+ {const_cast<char *>("__reduce__"), reinterpret_cast<PyCFunction>(enum___reduce__),
+ METH_NOARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr} // Sentinel
+};
+
+} // extern "C"
+
+//
+///////////////////////////////////////////////////////////////
+
namespace Shiboken {
class DeclaredEnumTypes
@@ -376,7 +499,7 @@ PyObject *getEnumItemFromValue(PyTypeObject *enumType, long itemValue)
while (PyDict_Next(values, &pos, &key, &value)) {
auto *obj = reinterpret_cast<SbkEnumObject *>(value);
if (obj->ob_value == itemValue) {
- Py_INCREF(obj);
+ Py_INCREF(value);
return value;
}
}
@@ -501,6 +624,7 @@ static PyType_Slot SbkNewType_slots[] = {
{Py_tp_repr, (void *)SbkEnumObject_repr},
{Py_tp_str, (void *)SbkEnumObject_repr},
{Py_tp_getset, (void *)SbkEnumGetSetList},
+ {Py_tp_methods, (void *)SbkEnumObject_Methods},
{Py_tp_new, (void *)SbkEnum_tp_new},
{Py_nb_add, (void *)enum_add},
{Py_nb_subtract, (void *)enum_subtract},
@@ -522,7 +646,7 @@ static PyType_Slot SbkNewType_slots[] = {
{Py_nb_index, (void *)enum_int},
{Py_tp_richcompare, (void *)enum_richcompare},
{Py_tp_hash, (void *)enum_hash},
- {Py_tp_dealloc, (void *)Sbk_object_dealloc},
+ {Py_tp_dealloc, (void *)enum_object_dealloc},
{0, nullptr}
};
static PyType_Spec SbkNewType_spec = {
@@ -613,7 +737,6 @@ newTypeWithName(const char *name,
newspec->slots = newslots;
auto *type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(newspec));
Py_TYPE(type) = SbkEnumType_TypeF();
- Py_INCREF(Py_TYPE(type));
auto *enumType = reinterpret_cast<SbkEnumType *>(type);
PepType_SETP(enumType)->cppName = cppName;
diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h
index 759d72636..c294c17d9 100644
--- a/sources/shiboken2/libshiboken/sbkenum.h
+++ b/sources/shiboken2/libshiboken/sbkenum.h
@@ -114,6 +114,8 @@ namespace Enum
LIBSHIBOKEN_API void setTypeConverter(PyTypeObject *enumType, SbkConverter *converter);
/// Returns the converter assigned to the enum \p type.
LIBSHIBOKEN_API SbkConverter *getTypeConverter(PyTypeObject *enumType);
+
+ LIBSHIBOKEN_API PyObject *unpickleEnum(PyObject *, PyObject *);
}
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index 5430ab064..ba1fc119e 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -39,6 +39,7 @@
#include "basewrapper.h"
#include "autodecref.h"
+#include "sbkstring.h"
#include "sbkstaticstrings.h"
#include "sbkstaticstrings_p.h"
@@ -185,7 +186,6 @@ _get_class_of_sm(PyObject *ob_sm)
static PyObject *
_get_class_of_descr(PyObject *ob)
{
- Shiboken::AutoDecRef func_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name()));
return PyObject_GetAttr(ob, Shiboken::PyMagicName::objclass());
}
@@ -318,6 +318,20 @@ pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier)
static PyObject *
GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier);
+// Helper for __qualname__ which might not always exist in Python 2 (type).
+static PyObject *
+_get_qualname(PyObject *ob)
+{
+ // We support __qualname__ for types, only.
+ assert(PyType_Check(ob));
+ PyObject *name = PyObject_GetAttr(ob, Shiboken::PyMagicName::qualname());
+ if (name == nullptr) {
+ PyErr_Clear();
+ name = PyObject_GetAttr(ob, Shiboken::PyMagicName::name());
+ }
+ return name;
+}
+
static PyObject *
GetTypeKey(PyObject *ob)
{
@@ -334,19 +348,20 @@ GetTypeKey(PyObject *ob)
*
* This is the PyCFunction behavior, as opposed to Python functions.
*/
- Shiboken::AutoDecRef class_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name()));
+ // PYSIDE-1286: We use correct __module__ and __qualname__, now.
Shiboken::AutoDecRef module_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::module()));
-
- if (module_name.isNull())
+ if (module_name.isNull()) {
+ // We have no module_name because this is a module ;-)
PyErr_Clear();
-
- // Note: if we have a module, then __module__ is null, and we get
- // the module name through __name__ .
- if (class_name.isNull())
+ module_name.reset(PyObject_GetAttr(ob, Shiboken::PyMagicName::name()));
+ return Py_BuildValue("O", module_name.object());
+ }
+ Shiboken::AutoDecRef class_name(_get_qualname(ob));
+ if (class_name.isNull()) {
+ Py_FatalError("Signature: missing class name in GetTypeKey");
return nullptr;
- if (module_name.object())
- return Py_BuildValue("(OO)", module_name.object(), class_name.object());
- return Py_BuildValue("O", class_name.object());
+ }
+ return Py_BuildValue("(OO)", module_name.object(), class_name.object());
}
static PyObject *empty_dict = nullptr;
@@ -402,7 +417,6 @@ GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
Shiboken::AutoDecRef func_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name()));
Shiboken::AutoDecRef objclass(PyObject_GetAttr(ob, Shiboken::PyMagicName::objclass()));
Shiboken::AutoDecRef class_key(GetTypeKey(objclass));
-
if (func_name.isNull() || objclass.isNull() || class_key.isNull())
return nullptr;
PyObject *dict = TypeKey_to_PropsDict(class_key, objclass);
@@ -851,12 +865,15 @@ get_signature(PyObject * /* self */, PyObject *args)
////////////////////////////////////////////////////////////////////////////
// a stack trace for linux-like platforms
#include <stdio.h>
-#include <execinfo.h>
+#if defined(__GLIBC__)
+# include <execinfo.h>
+#endif
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void handler(int sig) {
+#if defined(__GLIBC__)
void *array[30];
size_t size;
@@ -864,8 +881,11 @@ void handler(int sig) {
size = backtrace(array, 30);
// print out all the frames to stderr
+#endif
fprintf(stderr, "Error: signal %d:\n", sig);
+#if defined(__GLIBC__)
backtrace_symbols_fd(array, size, STDERR_FILENO);
+#endif
exit(1);
}
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py
index 1f6d70b31..0f9598c64 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py
@@ -109,8 +109,13 @@ CO_NOFREE = 0x0040
###############################################################################
+
+# PYSIDE-1286: We now use the added __qualname__ for classes.
+def _get_class_name(cls):
+ return getattr(cls, "__qualname__", cls.__name__)
+
# This function was changed: 'builtins' and 'qualname' don't exist.
-# We use '__builtin__' and '__name__' instead.
+# We use '__builtin__' and '__(qual)?name__' instead.
def formatannotation(annotation, base_module=None):
if getattr(annotation, '__module__', None) == 'typing':
# The replace must not be done on Python 2.7 because it
@@ -118,8 +123,8 @@ def formatannotation(annotation, base_module=None):
return repr(annotation) ##.replace('typing.', '')
if isinstance(annotation, type):
if annotation.__module__ in ('__builtin__', base_module):
- return annotation.__name__
- return annotation.__module__+'.'+annotation.__name__
+ return _get_class_name(annotation)
+ return annotation.__module__ + '.' + _get_class_name(annotation)
return repr(annotation)
@@ -393,7 +398,7 @@ class Parameter(object):
return formatted
def __repr__(self):
- return '<{} "{}">'.format(self.__class__.__name__, self)
+ return '<{} "{}">'.format(_get_class_name(self.__class__), self)
def __hash__(self):
return hash((self.name, self.kind, self.annotation, self.default))
@@ -536,7 +541,7 @@ class BoundArguments(object):
args = []
for arg, value in self.arguments.items():
args.append('{}={!r}'.format(arg, value))
- return '<{} ({})>'.format(self.__class__.__name__, ', '.join(args))
+ return '<{} ({})>'.format(_get_class_name(self.__class__), ', '.join(args))
class Signature(object):
@@ -842,7 +847,7 @@ class Signature(object):
self._return_annotation = state['_return_annotation']
def __repr__(self):
- return '<{} {}>'.format(self.__class__.__name__, self)
+ return '<{} {}>'.format(_get_class_name(self.__class__), self)
def __str__(self):
result = []
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
index 0403358bb..4dbed077d 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2019 The Qt Company Ltd.
+## Copyright (C) 2020 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
index 0417f132a..7af43bea0 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
@@ -70,7 +70,7 @@ def finish_import(module):
if func:
func(module)
except Exception as e:
- name = e.__class__.__name__
+ name = e.__class__.__qualname__
print(72 * "*")
print("Error in deprecated.py, ignored:")
print(" {name}: {e}".format(**locals()))
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
index f11f3cf3d..fa4d5e77c 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2018 The Qt Company Ltd.
+## Copyright (C) 2020 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -100,17 +100,19 @@ class ExactEnumerator(object):
return ret
def klass(self, class_name, klass):
+ ret = self.result_type()
+ if "<" in class_name:
+ # This is happening in QtQuick for some reason:
+ ## class QSharedPointer<QQuickItemGrabResult >:
+ # We simply skip over this class.
+ return ret
bases_list = []
for base in klass.__bases__:
name = base.__name__
- if name in ("object", "type"):
- pass
- else:
- modname = base.__module__
- name = modname + "." + base.__name__
+ if name not in ("object", "type"):
+ name = base.__module__ + "." + name
bases_list.append(name)
class_str = "{}({})".format(class_name, ", ".join(bases_list))
- ret = self.result_type()
# class_members = inspect.getmembers(klass)
# gives us also the inherited things.
class_members = sorted(list(klass.__dict__.items()))
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
index 8d970956b..2053c3e9d 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -165,6 +165,11 @@ def try_to_guess(thing, valtype):
return ret
return None
+def get_name(thing):
+ if isinstance(thing, type):
+ return getattr(thing, "__qualname__", thing.__name__)
+ else:
+ return thing.__name__
def _resolve_value(thing, valtype, line):
if thing in ("0", "None") and valtype:
@@ -172,7 +177,7 @@ def _resolve_value(thing, valtype, line):
return None
map = type_map[valtype]
# typing.Any: '_SpecialForm' object has no attribute '__name__'
- name = map.__name__ if hasattr(map, "__name__") else str(map)
+ name = get_name(map) if hasattr(map, "__name__") else str(map)
thing = "zero({})".format(name)
if thing in type_map:
return type_map[thing]
@@ -212,7 +217,8 @@ def to_string(thing):
return thing
if hasattr(thing, "__name__"):
dot = "." in str(thing)
- return thing.__module__ + "." + thing.__name__ if dot else thing.__name__
+ name = get_name(thing)
+ return thing.__module__ + "." + name if dot else name
# Note: This captures things from the typing module:
return str(thing)
diff --git a/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml
index bdb0c9338..3eba557fb 100644
--- a/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml
+++ b/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml
@@ -103,6 +103,12 @@
</inject-code>
</add-function>
+ <add-function signature="_unpickle_enum(PyObject*, PyObject*)" return-type="PyObject*">
+ <inject-code>
+ %PYARG_0 = Shiboken::Enum::unpickleEnum(%1, %2);
+ </inject-code>
+ </add-function>
+
<extra-includes>
<include file-name="sbkversion.h" location="local"/>
<include file-name="voidptr.h" location="local"/>
diff --git a/sources/shiboken2/tests/shiboken_test_helper.py b/sources/shiboken2/tests/shiboken_test_helper.py
index 2564c91d4..793baf4ad 100644
--- a/sources/shiboken2/tests/shiboken_test_helper.py
+++ b/sources/shiboken2/tests/shiboken_test_helper.py
@@ -31,8 +31,10 @@
def objectFullname(t):
+ # '__qualname__' for Python 2 does exist for PySide types, only.
+ name = getattr(t, "__qualname__", t.__name__)
module = t.__module__
if module is None or module == str.__class__.__module__:
- return t.__name__
+ return name
else:
- return module + '.' + t.__name__
+ return module + '.' + name