aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2019-06-19 08:12:33 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2019-06-19 08:12:33 +0200
commitd8bd1449361835a3fe67f8ad33e82cec78940f1c (patch)
tree279e019b83fb2aa9e0673d00b5df4c432315ea51 /sources/pyside2
parentb4098737b13c91ca85b69362426f0f30768c49b1 (diff)
parent7dba09d7c4007e96fb0a39bf6f6e740cd207324a (diff)
Merge remote-tracking branch 'origin/5.12' into 5.13
Diffstat (limited to 'sources/pyside2')
-rw-r--r--sources/pyside2/PySide2/glue/qtcore.cpp13
-rw-r--r--sources/pyside2/libpyside/pyside.cpp56
-rw-r--r--sources/pyside2/tests/QtWidgets/application_test.py8
-rw-r--r--sources/pyside2/tests/pysidetest/CMakeLists.txt1
-rw-r--r--sources/pyside2/tests/pysidetest/constructor_properties_test.py64
5 files changed, 118 insertions, 24 deletions
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp
index fde016548..9db4e2e82 100644
--- a/sources/pyside2/PySide2/glue/qtcore.cpp
+++ b/sources/pyside2/PySide2/glue/qtcore.cpp
@@ -1211,8 +1211,8 @@ QByteArray ba(1 + int(%2), char(0));
// @snippet qcryptographichash-adddata
// @snippet qsocketnotifier
-Shiboken::AutoDecRef socket(%PYARG_1);
-if (!socket.isNull()) {
+PyObject *socket = %PYARG_1;
+if (socket != nullptr) {
// We use qintptr as PyLong, but we check for int
// since it is currently an alias to be Python2 compatible.
// Internally, ints are qlonglongs.
@@ -1340,18 +1340,17 @@ if (!PyTuple_SetItem(empty, 0, PyList_New(0))) {
// @snippet qcoreapplication-2
// @snippet qcoreapplication-instance
-QCoreApplication *app = QCoreApplication::instance();
PyObject *pyApp = Py_None;
-if (app) {
+if (qApp) {
pyApp = reinterpret_cast<PyObject*>(
- Shiboken::BindingManager::instance().retrieveWrapper(app));
+ Shiboken::BindingManager::instance().retrieveWrapper(qApp));
if (!pyApp)
- pyApp = %CONVERTTOPYTHON[QCoreApplication*](app);
+ pyApp = %CONVERTTOPYTHON[QCoreApplication*](qApp);
// this will keep app live after python exit (extra ref)
}
// PYSIDE-571: make sure that we return the singleton "None"
if (pyApp == Py_None)
- Py_DECREF(MakeSingletonQAppWrapper(0)); // here qApp and instance() diverge
+ Py_DECREF(MakeSingletonQAppWrapper(nullptr)); // here qApp and instance() diverge
%PYARG_0 = pyApp;
Py_XINCREF(%PYARG_0);
// @snippet qcoreapplication-instance
diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp
index 6e4a3efd4..fff28a9e7 100644
--- a/sources/pyside2/libpyside/pyside.cpp
+++ b/sources/pyside2/libpyside/pyside.cpp
@@ -94,6 +94,31 @@ void init(PyObject *module)
SignalManager::instance();
}
+static bool _setProperty(PyObject* qObj, PyObject *name, PyObject *value, bool *accept)
+{
+ QByteArray propName(Shiboken::String::toCString(name));
+ propName[0] = std::toupper(propName[0]);
+ propName.prepend("set");
+
+ Shiboken::AutoDecRef propSetter(PyObject_GetAttrString(qObj, propName.constData()));
+ if (!propSetter.isNull()) {
+ *accept = true;
+ Shiboken::AutoDecRef args(PyTuple_Pack(1, value));
+ Shiboken::AutoDecRef retval(PyObject_CallObject(propSetter, args));
+ if (retval.isNull())
+ return false;
+ } else {
+ PyErr_Clear();
+ Shiboken::AutoDecRef attr(PyObject_GenericGetAttr(qObj, name));
+ if (PySide::Property::checkType(attr)) {
+ *accept = true;
+ if (PySide::Property::setValue(reinterpret_cast<PySideProperty*>(attr.object()), qObj, value) < 0)
+ return false;
+ }
+ }
+ return true;
+}
+
bool fillQtProperties(PyObject* qObj, const QMetaObject* metaObj, PyObject* kwds, const char** blackList, unsigned int blackListSize)
{
@@ -103,28 +128,27 @@ bool fillQtProperties(PyObject* qObj, const QMetaObject* metaObj, PyObject* kwds
while (PyDict_Next(kwds, &pos, &key, &value)) {
if (!blackListSize || !std::binary_search(blackList, blackList + blackListSize, std::string(Shiboken::String::toCString(key)))) {
QByteArray propName(Shiboken::String::toCString(key));
+ bool accept = false;
if (metaObj->indexOfProperty(propName) != -1) {
- propName[0] = std::toupper(propName[0]);
- propName.prepend("set");
-
- Shiboken::AutoDecRef propSetter(PyObject_GetAttrString(qObj, propName.constData()));
- if (!propSetter.isNull()) {
- Shiboken::AutoDecRef args(PyTuple_Pack(1, value));
- Shiboken::AutoDecRef retval(PyObject_CallObject(propSetter, args));
- } else {
- PyObject* attr = PyObject_GenericGetAttr(qObj, key);
- if (PySide::Property::checkType(attr))
- PySide::Property::setValue(reinterpret_cast<PySideProperty*>(attr), qObj, value);
- }
+ if (!_setProperty(qObj, key, value, &accept))
+ return false;
} else {
propName.append("()");
if (metaObj->indexOfSignal(propName) != -1) {
+ accept = true;
propName.prepend('2');
- PySide::Signal::connect(qObj, propName, value);
- } else {
- PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal", propName.constData());
+ if (!PySide::Signal::connect(qObj, propName, value))
+ return false;
+ }
+ }
+ if (!accept) {
+ // PYSIDE-1019: Allow any existing attribute in the constructor.
+ if (!_setProperty(qObj, key, value, &accept))
return false;
- };
+ }
+ if (!accept) {
+ PyErr_Format(PyExc_AttributeError, "'%S' is not a Qt property or a signal", key);
+ return false;
}
}
}
diff --git a/sources/pyside2/tests/QtWidgets/application_test.py b/sources/pyside2/tests/QtWidgets/application_test.py
index bd0f94125..0b8f73cd6 100644
--- a/sources/pyside2/tests/QtWidgets/application_test.py
+++ b/sources/pyside2/tests/QtWidgets/application_test.py
@@ -31,19 +31,25 @@
import unittest
from testbinding import TestObject
from PySide2.QtWidgets import QApplication
+from PySide2 import __all__ as all
class QApplicationInstance(unittest.TestCase):
def appDestroyed(self):
- sefl.assertTrue(False)
+ self.assertTrue(False)
def testInstanceObject(self):
+ self.assertEqual(type(qApp), type(None))
TestObject.createApp()
app1 = QApplication.instance()
app2 = QApplication.instance()
app1.setObjectName("MyApp")
self.assertEqual(app1, app2)
self.assertEqual(app2.objectName(), app1.objectName())
+ if len(all) > 3:
+ # an import triggers qApp initialization
+ __import__("PySide2." + all[-1])
+ self.assertEqual(app1, qApp)
app1.destroyed.connect(self.appDestroyed)
if __name__ == '__main__':
diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt
index cb8ba04cf..3c993cf4e 100644
--- a/sources/pyside2/tests/pysidetest/CMakeLists.txt
+++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt
@@ -118,6 +118,7 @@ target_link_libraries(testbinding
add_dependencies(testbinding pyside2 QtCore QtGui QtWidgets pysidetest)
create_generator_target(testbinding)
+PYSIDE_TEST(constructor_properties_test.py)
PYSIDE_TEST(decoratedslot_test.py)
# Will always crash when built against Qt 5.6, no point in running it.
if (Qt5Core_VERSION VERSION_GREATER 5.7.0)
diff --git a/sources/pyside2/tests/pysidetest/constructor_properties_test.py b/sources/pyside2/tests/pysidetest/constructor_properties_test.py
new file mode 100644
index 000000000..48e2a7aae
--- /dev/null
+++ b/sources/pyside2/tests/pysidetest/constructor_properties_test.py
@@ -0,0 +1,64 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## 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 Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## 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-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import unittest
+
+from helper import UsesQApplication
+from PySide2.QtCore import Qt
+from PySide2.QtWidgets import QApplication, QLabel, QFrame
+
+
+class ConstructorPropertiesTest(UsesQApplication):
+
+ def testCallConstructor(self):
+ label = QLabel(
+ frameStyle=QFrame.Panel | QFrame.Sunken,
+ text="first line\nsecond line",
+ alignment=Qt.AlignBottom | Qt.AlignRight
+ )
+ self.assertRaises(AttributeError, lambda: QLabel(
+ somethingelse=42,
+ text="first line\nsecond line",
+ alignment=Qt.AlignBottom | Qt.AlignRight
+ ))
+
+
+if __name__ == '__main__':
+ unittest.main()
+