diff options
Diffstat (limited to 'sources/pyside2')
17 files changed, 453 insertions, 59 deletions
diff --git a/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml b/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml index dc60a509d..d91f07801 100644 --- a/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml +++ b/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml @@ -80,6 +80,8 @@ <modify-function signature="disconnectFromHost()" allow-thread="yes"/> <modify-function signature="waitForConnected(int)" allow-thread="yes"/> <modify-function signature="waitForDisconnected(int)" allow-thread="yes"/> + <modify-function signature="waitForBytesWritten(int)" allow-thread="yes"/> + <modify-function signature="waitForReadyRead(int)" allow-thread="yes"/> </object-type> <value-type name="QDnsDomainNameRecord"/> diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index 306a2239c..78de3d5d5 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -76,7 +76,7 @@ if (kwds || numArgs > 1) { PyTypeObject *typeObj = reinterpret_cast<PyTypeObject*>(%PYARG_3); -if (typeObj) { +if (typeObj && !Shiboken::ObjectType::checkType(typeObj)) { if (typeObj == &PyList_Type) { QByteArray out_ba = out.toByteArray(); if (!out_ba.isEmpty()) { @@ -122,8 +122,14 @@ if (typeObj) { Py_INCREF(Py_False); %PYARG_0 = Py_False; } + } else { + // TODO: PyDict_Type and PyTuple_Type + PyErr_SetString(PyExc_TypeError, + "Invalid type parameter.\n" + "\tUse 'list', 'bytes', 'str', 'int', 'float', 'bool', " + "or a Qt-derived type"); + return nullptr; } - // TODO: PyDict_Type and PyTuple_Type } else { if (!out.isValid()) { @@ -793,12 +799,35 @@ qRegisterMetaType<QVector<int> >("QVector<int>"); // @snippet qobject-metaobject // @snippet qobject-findchild-1 +static bool _findChildTypeMatch(const QObject *child, PyTypeObject *desiredType) +{ + auto *pyChildType = PySide::getTypeForQObject(child); + return pyChildType != nullptr && PyType_IsSubtype(pyChildType, desiredType); +} + +static inline bool _findChildrenComparator(const QObject *child, + const QRegularExpression &name) +{ + return name.match(child->objectName()).hasMatch(); +} + +static inline bool _findChildrenComparator(const QObject *child, + const QString &name) +{ + return name.isNull() || name == child->objectName(); +} + +static inline bool _findChildrenComparator(const QObject *child, + const QRegExp &name) +{ + return name.indexIn(child->objectName()) != -1; +} + static QObject *_findChildHelper(const QObject *parent, const QString &name, PyTypeObject *desiredType) { for (auto *child : parent->children()) { - Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child)); - if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) - && (name.isNull() || name == child->objectName())) { + if (_findChildrenComparator(child, name) + && _findChildTypeMatch(child, desiredType)) { return child; } } @@ -811,28 +840,15 @@ static QObject *_findChildHelper(const QObject *parent, const QString &name, PyT return nullptr; } -static inline bool _findChildrenComparator(const QObject *&child, const QRegExp &name) -{ - return name.indexIn(child->objectName()) != -1; -} - -static inline bool _findChildrenComparator(const QObject *&child, const QRegularExpression &name) -{ - return name.match(child->objectName()).hasMatch(); -} - -static inline bool _findChildrenComparator(const QObject *&child, const QString &name) -{ - return name.isNull() || name == child->objectName(); -} - -template<typename T> +template<typename T> // QString/QRegularExpression/QRegExp static void _findChildrenHelper(const QObject *parent, const T& name, PyTypeObject *desiredType, PyObject *result) { for (const auto *child : parent->children()) { - Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child)); - if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) && _findChildrenComparator(child, name)) + if (_findChildrenComparator(child, name) + && _findChildTypeMatch(child, desiredType)) { + Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child)); PyList_Append(result, pyChild); + } _findChildrenHelper(child, name, desiredType, result); } } @@ -848,19 +864,41 @@ QObject *child = _findChildHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *> _findChildrenHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %PYARG_0); // @snippet qobject-findchildren +////////////////////////////////////////////////////////////////////////////// +// PYSIDE-131: Use the class name as context where the calling function is +// living. Derived Python classes have the wrong context. +// +// The original patch uses Python introspection to look up the current +// function (from the frame stack) in the class __dict__ along the mro. +// +// The problem is that looking into the frame stack works for Python +// functions, only. For including builtin function callers, the following +// approach turned out to be much simpler: +// +// Walk the __mro__ +// - translate the string +// - if the translated string is changed: +// - return the translation. + // @snippet qobject-tr -QString result; -if (QCoreApplication::instance()) { - PyObject *klass = PyObject_GetAttr(%PYSELF, Shiboken::PyMagicName::class_()); - PyObject *cname = PyObject_GetAttr(klass, Shiboken::PyMagicName::name()); - result = QString(QCoreApplication::instance()->translate(Shiboken::String::toCString(cname), - /* %1, %2, QCoreApplication::CodecForTr, %3)); */ - %1, %2, %3)); - - Py_DECREF(klass); - Py_DECREF(cname); -} else { - result = QString(QString::fromLatin1(%1)); +PyTypeObject *type = Py_TYPE(%PYSELF); +PyObject *mro = type->tp_mro; +auto len = PyTuple_GET_SIZE(mro); +QString result = QString::fromUtf8(%1); +QString oldResult = result; +static auto *sbkObjectType = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()); +for (Py_ssize_t idx = 0; idx < len - 1; ++idx) { + // Skip the last class which is `object`. + auto *type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx)); + if (type == sbkObjectType) + continue; + const char *context = type->tp_name; + const char *dotpos = strrchr(context, '.'); + if (dotpos != nullptr) + context = dotpos + 1; + result = QCoreApplication::translate(context, %1, %2, %3); + if (result != oldResult) + break; } %PYARG_0 = %CONVERTTOPYTHON[QString](result); // @snippet qobject-tr diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py index 6a69a798a..9eb84de7a 100644 --- a/sources/pyside2/PySide2/support/generate_pyi.py +++ b/sources/pyside2/PySide2/support/generate_pyi.py @@ -1,4 +1,6 @@ # This Python file uses the following encoding: utf-8 +from __future__ import print_function, absolute_import, unicode_literals +LICENSE_TEXT = """ ############################################################################# ## ## Copyright (C) 2020 The Qt Company Ltd. @@ -37,8 +39,7 @@ ## $QT_END_LICENSE$ ## ############################################################################# - -from __future__ import print_function, absolute_import, unicode_literals +""" """ generate_pyi.py @@ -201,14 +202,6 @@ class Formatter(Writer): yield -def get_license_text(): - with io.open(sourcepath) as f: - lines = f.readlines() - license_line = next((lno for lno, line in enumerate(lines) - if "$QT_END_LICENSE$" in line)) - return "".join(lines[:license_line + 3]) - - def find_imports(text): return [imp for imp in PySide2.__all__ if imp + "." in text] @@ -228,7 +221,7 @@ def generate_pyi(import_name, outpath, options): outfile = io.StringIO() fmt = Formatter(outfile) - fmt.print(get_license_text()) # which has encoding, already + fmt.print(LICENSE_TEXT.strip()) need_imports = not USE_PEP563 if USE_PEP563: fmt.print("from __future__ import annotations") @@ -307,6 +300,8 @@ def generate_all_pyi(outpath, options): if __name__ == "__main__": + # PYSIDE-1621: Enforce embedding to ensure that it always works. + sys.pyside_uses_embedding = True parser = argparse.ArgumentParser( description="This script generates the .pyi file for all PySide modules.") parser.add_argument("modules", nargs="+", diff --git a/sources/pyside2/PySide2/templates/core_common.xml b/sources/pyside2/PySide2/templates/core_common.xml index 6d02428ad..b5d1f02e2 100644 --- a/sources/pyside2/PySide2/templates/core_common.xml +++ b/sources/pyside2/PySide2/templates/core_common.xml @@ -114,35 +114,52 @@ <insert-template name="tuple_retval_ok"/> </template> + <!-- QInputDialog: these should allow threads --> <template name="fix_arg,arg,arg,arg,arg,arg,arg,bool*,arg"> bool ok_; - %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, &ok_, %9); + %RETURN_TYPE retval_; + Py_BEGIN_ALLOW_THREADS + retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, &ok_, %9); + Py_END_ALLOW_THREADS <insert-template name="tuple_retval_ok"/> </template> <template name="fix_arg,arg,arg,arg,arg,arg,arg,bool*,arg,arg"> bool ok_; - %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, &ok_, %9, %10); + %RETURN_TYPE retval_; + Py_BEGIN_ALLOW_THREADS + retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, &ok_, %9, %10); + Py_END_ALLOW_THREADS <insert-template name="tuple_retval_ok"/> </template> <template name="fix_arg,arg,arg,arg,arg,arg,bool*,arg"> bool ok_; - %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, &ok_, %8); + %RETURN_TYPE retval_; + Py_BEGIN_ALLOW_THREADS + retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, &ok_, %8); + Py_END_ALLOW_THREADS <insert-template name="tuple_retval_ok"/> </template> <template name="fix_arg,arg,arg,arg,arg,bool*,arg"> bool ok_; - %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, &ok_, %7); + %RETURN_TYPE retval_; + Py_BEGIN_ALLOW_THREADS + retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, &ok_, %7); + Py_END_ALLOW_THREADS <insert-template name="tuple_retval_ok"/> </template> <template name="fix_arg,arg,arg,arg,bool*,arg,arg"> bool ok_; - %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, &ok_, %6, %7); + %RETURN_TYPE retval_; + Py_BEGIN_ALLOW_THREADS + retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, &ok_, %6, %7); + Py_END_ALLOW_THREADS <insert-template name="tuple_retval_ok"/> </template> + <!-- End of QInputDialog templates --> <template name="fix_char*"> char val_{}; diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp index 6a21d168d..7604f69aa 100644 --- a/sources/pyside2/libpyside/feature_select.cpp +++ b/sources/pyside2/libpyside/feature_select.cpp @@ -255,6 +255,7 @@ static bool replaceClassDict(PyTypeObject *type) // Replace `__dict__` which usually has refcount 1 (but see cyclic_test.py) Py_DECREF(type->tp_dict); type->tp_dict = new_dict; + setCurrentSelectId(type, select_id.object()); return true; } @@ -275,6 +276,7 @@ static bool addNewDict(PyTypeObject *type, PyObject *select_id) setNextDict(dict, new_dict); setNextDict(new_dict, next_dict); type->tp_dict = new_dict; + setCurrentSelectId(type, select_id); return true; } @@ -297,6 +299,7 @@ static bool moveToFeatureSet(PyTypeObject *type, PyObject *select_id) } } while (dict != initial_dict); type->tp_dict = initial_dict; + setCurrentSelectId(type, getSelectId(initial_dict)); return false; } @@ -418,6 +421,13 @@ void Select(PyObject *obj) type->tp_dict = SelectFeatureSet(type); } +PyObject *Select(PyTypeObject *type) +{ + if (featurePointer != nullptr) + type->tp_dict = SelectFeatureSet(type); + return type->tp_dict; +} + static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id); static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id); static bool feature_04_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id); @@ -446,11 +456,11 @@ void finalize() } static bool patch_property_impl(); +static bool is_initialized = false; void init() { // This function can be called multiple times. - static bool is_initialized = false; if (!is_initialized) { fast_id_array = &_fast_id_array[1]; for (int idx = -1; idx < 256; ++idx) @@ -466,6 +476,14 @@ void init() cached_globals = nullptr; } +void Enable(bool enable) +{ + if (!is_initialized) + return; + featurePointer = enable ? featureProcArray : nullptr; + initSelectableFeature(enable ? SelectFeatureSet : nullptr); +} + ////////////////////////////////////////////////////////////////////////////// // // PYSIDE-1019: Support switchable extensions diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 5d0859adc..7b01c5b8f 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -412,7 +412,7 @@ static const char invalidatePropertyName[] = "_PySideInvalidatePtr"; // PYSIDE-1214, when creating new wrappers for classes inheriting QObject but // not exposed to Python, try to find the best-matching (most-derived) Qt // class by walking up the meta objects. -static const char *typeName(QObject *cppSelf) +static const char *typeName(const QObject *cppSelf) { const char *typeName = typeid(*cppSelf).name(); if (!Shiboken::Conversions::getConverter(typeName)) { @@ -427,6 +427,20 @@ static const char *typeName(QObject *cppSelf) return typeName; } +PyTypeObject *getTypeForQObject(const QObject *cppSelf) +{ + // First check if there are any instances of Python implementations + // inheriting a PySide class. + auto *existing = Shiboken::BindingManager::instance().retrieveWrapper(cppSelf); + if (existing != nullptr) + return reinterpret_cast<PyObject *>(existing)->ob_type; + // Find the best match (will return a PySide type) + auto *sbkObjectType = Shiboken::ObjectType::typeForTypeName(typeName(cppSelf)); + if (sbkObjectType != nullptr) + return reinterpret_cast<PyTypeObject *>(sbkObjectType); + return nullptr; +} + PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type) { PyObject *pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppSelf)); diff --git a/sources/pyside2/libpyside/pyside.h b/sources/pyside2/libpyside/pyside.h index a465fec47..c72f37ae7 100644 --- a/sources/pyside2/libpyside/pyside.h +++ b/sources/pyside2/libpyside/pyside.h @@ -140,6 +140,11 @@ PYSIDE_API void setNextQObjectMemoryAddr(void *addr); PYSIDE_API PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type); +/// Return the best-matching type for a QObject (Helper for QObject.findType()) +/// \param cppSelf QObject instance +/// \return type object +PYSIDE_API PyTypeObject *getTypeForQObject(const QObject *cppSelf); + #ifdef PYSIDE_QML_SUPPORT // Used by QtQuick module to notify QtQml that custom QtQuick items can be registered. typedef bool (*QuickRegisterItemFunction)(PyObject *pyObj, const char *uri, int versionMajor, diff --git a/sources/pyside2/pyside_version.py b/sources/pyside2/pyside_version.py index 876a0e401..3ee73451b 100644 --- a/sources/pyside2/pyside_version.py +++ b/sources/pyside2/pyside_version.py @@ -39,7 +39,7 @@ major_version = "5" minor_version = "15" -patch_version = "5" +patch_version = "6" # For example: "a", "b", "rc" # (which means "alpha", "beta", "release candidate"). diff --git a/sources/pyside2/tests/QtCore/CMakeLists.txt b/sources/pyside2/tests/QtCore/CMakeLists.txt index 9d268e079..c7e50d640 100644 --- a/sources/pyside2/tests/QtCore/CMakeLists.txt +++ b/sources/pyside2/tests/QtCore/CMakeLists.txt @@ -37,6 +37,7 @@ PYSIDE_TEST(deletelater_test.py) PYSIDE_TEST(destroysignal_test.py) PYSIDE_TEST(duck_punching_test.py) PYSIDE_TEST(emoji_string_test.py) +PYSIDE_TEST(feature_with_uic_test.py) PYSIDE_TEST(hash_test.py) PYSIDE_TEST(inherits_test.py) PYSIDE_TEST(max_signals.py) diff --git a/sources/pyside2/tests/QtCore/feature_with_uic/__init__.py b/sources/pyside2/tests/QtCore/feature_with_uic/__init__.py new file mode 100644 index 000000000..396f82fb1 --- /dev/null +++ b/sources/pyside2/tests/QtCore/feature_with_uic/__init__.py @@ -0,0 +1,29 @@ +############################################################################# +## +## 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$ +## +############################################################################# + +# this file intentionally left blank diff --git a/sources/pyside2/tests/QtCore/feature_with_uic/window.py b/sources/pyside2/tests/QtCore/feature_with_uic/window.py new file mode 100644 index 000000000..db0fbd033 --- /dev/null +++ b/sources/pyside2/tests/QtCore/feature_with_uic/window.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +############################################################################# +## +## Copyright (C) 2021 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$ +## +############################################################################# + +################################################################################ +## Form generated from reading UI file 'window.ui' +## +## Created by: Qt User Interface Compiler version 5.15.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + if not MainWindow.objectName(): + MainWindow.setObjectName(u"MainWindow") + MainWindow.resize(263, 196) + self.centralwidget = QWidget(MainWindow) + self.centralwidget.setObjectName(u"centralwidget") + self.horizontalLayout = QHBoxLayout(self.centralwidget) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.verticalLayout = QVBoxLayout() + self.verticalLayout.setObjectName(u"verticalLayout") + self.pushButton = QPushButton(self.centralwidget) + self.pushButton.setObjectName(u"pushButton") + + self.verticalLayout.addWidget(self.pushButton) + + + self.horizontalLayout.addLayout(self.verticalLayout) + + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QMenuBar(MainWindow) + self.menubar.setObjectName(u"menubar") + self.menubar.setGeometry(QRect(0, 0, 263, 23)) + MainWindow.setMenuBar(self.menubar) + self.statusbar = QStatusBar(MainWindow) + self.statusbar.setObjectName(u"statusbar") + MainWindow.setStatusBar(self.statusbar) + + self.retranslateUi(MainWindow) + self.pushButton.clicked.connect(MainWindow.close) + + QMetaObject.connectSlotsByName(MainWindow) + # setupUi + + def retranslateUi(self, MainWindow): + MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None)) + self.pushButton.setText(QCoreApplication.translate("MainWindow", u"PushButton", None)) + # retranslateUi + diff --git a/sources/pyside2/tests/QtCore/feature_with_uic/window.ui b/sources/pyside2/tests/QtCore/feature_with_uic/window.ui new file mode 100644 index 000000000..0b85824ea --- /dev/null +++ b/sources/pyside2/tests/QtCore/feature_with_uic/window.ui @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>263</width> + <height>196</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>PushButton</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>263</width> + <height>23</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar"/> + </widget> + <resources/> + <connections> + <connection> + <sender>pushButton</sender> + <signal>clicked()</signal> + <receiver>MainWindow</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>131</x> + <y>97</y> + </hint> + <hint type="destinationlabel"> + <x>131</x> + <y>97</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/sources/pyside2/tests/QtCore/feature_with_uic_test.py b/sources/pyside2/tests/QtCore/feature_with_uic_test.py new file mode 100644 index 000000000..5b61a4afb --- /dev/null +++ b/sources/pyside2/tests/QtCore/feature_with_uic_test.py @@ -0,0 +1,76 @@ +############################################################################# +## +## Copyright (C) 2021 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$ +## +############################################################################# + +""" +feature_with_uic_test.py +------------------------ + +Check if feature switching works with a normal UIC file. +This crashed due to callbacks into QApplication. + +PYSIDE-1626: Switch early in `BindingManager::getOverride`. +""" + +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.QtCore import QLibraryInfo, qVersion +from PySide2.QtWidgets import QApplication, QMainWindow + +if sys.version_info[0] >= 3: + from __feature__ import snake_case + +from feature_with_uic.window import Ui_MainWindow + + +class MainWindow(QMainWindow, Ui_MainWindow): + + def __init__(self): + super().__init__() + self.setupUi(self) + + +class FeatureTest(UsesQApplication): + + def testFeaturesWorkWithUIC(self): + window = MainWindow() + window.set_window_title(qVersion()) + window.show() + while not window.window_handle().is_exposed(): + QCoreApplication.process_events() + + +if __name__ == '__main__' and sys.version_info[0] >= 3: + unittest.main() diff --git a/sources/pyside2/tests/QtCore/qobject_parent_test.py b/sources/pyside2/tests/QtCore/qobject_parent_test.py index 0a02fbc26..becc7c48e 100644 --- a/sources/pyside2/tests/QtCore/qobject_parent_test.py +++ b/sources/pyside2/tests/QtCore/qobject_parent_test.py @@ -39,6 +39,16 @@ init_test_paths(False) from PySide2.QtCore import * +class TestObject1(QTimer): + def __init(self, parent): + super().__init__(parent) + + +class TestObject2(TestObject1): + def __init(self, parent): + super().__init__(parent) + + class ParentRefCountCase(unittest.TestCase): '''Test case for the refcount changes of setParent''' @@ -158,6 +168,26 @@ class ParentCase(unittest.TestCase): child = QObject(parent) self.assertEqual(parent, child.parent()) + def testFindChildByType(self): + parent = QObject() + expected = TestObject2(parent) + actual = parent.findChild(TestObject2) + self.assertEqual(actual, expected) + actual = parent.findChild(TestObject1) + self.assertEqual(actual, expected) + actual = parent.findChild(QTimer) + self.assertEqual(actual, expected) + + def testFindChildrenByType(self): + parent = QObject() + expected = [TestObject2(parent)] + actual = parent.findChildren(TestObject2) + self.assertEqual(actual, expected) + actual = parent.findChildren(TestObject1) + self.assertEqual(actual, expected) + actual = parent.findChildren(QTimer) + self.assertEqual(actual, expected) + class TestParentOwnership(unittest.TestCase): '''Test case for Parent/Child object ownership''' diff --git a/sources/pyside2/tests/QtCore/qsettings_test.py b/sources/pyside2/tests/QtCore/qsettings_test.py index a9f42a5d5..d7e203734 100644 --- a/sources/pyside2/tests/QtCore/qsettings_test.py +++ b/sources/pyside2/tests/QtCore/qsettings_test.py @@ -38,7 +38,7 @@ init_test_paths(False) from helper.helper import adjust_filename import py3kcompat as py3k -from PySide2.QtCore import QDir, QSettings, QTemporaryDir +from PySide2.QtCore import QDir, QSettings, QTemporaryDir, QByteArray class TestQSettings(unittest.TestCase): def testConversions(self): @@ -57,6 +57,20 @@ class TestQSettings(unittest.TestCase): r = settings.value('var2', type=list) self.assertEqual(type(r), list) + # Test mixed conversions + if py3k.IS_PY3K: + ba = QByteArray("hello".encode("utf-8")) + + r = settings.value("test", ba, type=QByteArray) + self.assertEqual(type(r), QByteArray) + + r = settings.value("test", ba, type=str) + self.assertEqual(type(r), str) + + # Test invalid conversions + with self.assertRaises(TypeError): + r = settings.value("test", ba, type=dict) + def testDefaultValueConversion(self): temp_dir = QDir.tempPath() diff --git a/sources/pyside2/tests/QtCore/translation_test.py b/sources/pyside2/tests/QtCore/translation_test.py index 0f36067bd..b2e674aac 100644 --- a/sources/pyside2/tests/QtCore/translation_test.py +++ b/sources/pyside2/tests/QtCore/translation_test.py @@ -59,6 +59,19 @@ class TranslationTest(UsesQCoreApplication): obj = QObject() obj.setObjectName(obj.tr('Hello World!')) + self.assertEqual(obj.objectName(), 'Orbis, te saluto!') + + def testLatinDerived(self): + # PYSIDE-131: Test that derived classes work, too. + translator = QTranslator() + translator.load(os.path.join(self.trdir, 'trans_latin.qm')) + self.app.installTranslator(translator) + + class Derived(QObject): + pass + + obj = Derived() + obj.setObjectName(obj.tr('Hello World!')) self.assertEqual(obj.objectName(), py3k.unicode_('Orbis, te saluto!')) def testRussian(self): diff --git a/sources/pyside2/tests/pysidetest/embedding_test.py b/sources/pyside2/tests/pysidetest/embedding_test.py index 1960838ff..570686927 100644 --- a/sources/pyside2/tests/pysidetest/embedding_test.py +++ b/sources/pyside2/tests/pysidetest/embedding_test.py @@ -65,16 +65,15 @@ class EmbeddingTest(unittest.TestCase): # Unfortunately, I see no way how to shut things enough down # to trigger a second initiatization. Therefore, only one test :-/ def test_pyside_embedding(self): - import sys, os + import sys self.assertFalse(hasattr(sys, "pyside_uses_embedding")) sys.pyside_uses_embedding = "anything true" import PySide2 # everything has to be imported self.assertTrue("PySide2.support.signature" in sys.modules) self.assertEqual(sys.pyside_uses_embedding, True) - dn = os.path.dirname - name = os.path.basename(dn(dn(dn(PySide2.support.signature.__file__)))) - self.assertTrue(name.startswith("embedded.") and name.endswith(".zip")) + # We no longer use a physical zip file. + if __name__ == '__main__': unittest.main() |