aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2020-09-17 12:42:52 +0200
committerChristian Tismer <tismer@stackless.com>2020-09-21 18:57:25 +0200
commitea89199e0ec036957dd103bb55ff480979be8622 (patch)
tree31175eef743cb2c8e2adc913310415eb660082b4
parent70be4a4c400d8a2cbf0522cc1773d54d8cecee61 (diff)
signal: Supply the missing __get__ method
The `__get__` method gets created by `PyType_Ready` when the slot `tp_descr_get` is set in the signal class. Change-Id: Id853c59546c0382afeda837f0abfd596b6ca5c7f Fixes: PYSIDE-68 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--sources/pyside2/libpyside/pysidesignal.cpp20
-rw-r--r--sources/pyside2/tests/pysidetest/CMakeLists.txt1
-rw-r--r--sources/pyside2/tests/pysidetest/signal_tp_descr_get_test.py87
3 files changed, 106 insertions, 2 deletions
diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp
index ff1d6002c..b7941f8d6 100644
--- a/sources/pyside2/libpyside/pysidesignal.cpp
+++ b/sources/pyside2/libpyside/pysidesignal.cpp
@@ -88,6 +88,7 @@ static void signalFree(void *);
static void signalInstanceFree(void *);
static PyObject *signalGetItem(PyObject *self, PyObject *key);
static PyObject *signalToString(PyObject *self);
+static PyObject *signalDescrGet(PyObject *self, PyObject *obj, PyObject *type);
// Signal Instance methods
static PyObject *signalInstanceConnect(PyObject *, PyObject *, PyObject *);
@@ -137,6 +138,7 @@ static PyTypeObject *PySideMetaSignalTypeF(void)
static PyType_Slot PySideSignalType_slots[] = {
{Py_mp_subscript, reinterpret_cast<void *>(signalGetItem)},
+ {Py_tp_descr_get, reinterpret_cast<void *>(signalDescrGet)},
{Py_tp_call, reinterpret_cast<void *>(signalCall)},
{Py_tp_str, reinterpret_cast<void *>(signalToString)},
{Py_tp_init, reinterpret_cast<void *>(signalTpInit)},
@@ -546,6 +548,19 @@ static PyObject *signalInstanceDisconnect(PyObject *self, PyObject *args)
return 0;
}
+// PYSIDE-68: Supply the missing __get__ function
+static PyObject *signalDescrGet(PyObject *self, PyObject *obj, PyObject * /*type*/)
+{
+ auto signal = reinterpret_cast<PySideSignal *>(self);
+ // Return the unbound signal if there is nothing to bind it to.
+ if (obj == nullptr || obj == Py_None) {
+ Py_INCREF(self);
+ return self;
+ }
+ Shiboken::AutoDecRef name(Py_BuildValue("s", signal->data->signalName.data()));
+ return reinterpret_cast<PyObject *>(PySide::Signal::initialize(signal, name, obj));
+}
+
static PyObject *signalCall(PyObject *self, PyObject *args, PyObject *kw)
{
auto signal = reinterpret_cast<PySideSignal *>(self);
@@ -759,11 +774,12 @@ static void instanceInitialize(PySideSignalInstance *self, PyObject *name, PySid
PySideSignalInstance *initialize(PySideSignal *self, PyObject *name, PyObject *object)
{
- PySideSignalInstance *instance = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF());
+ PySideSignalInstance *instance = PyObject_New(PySideSignalInstance,
+ PySideSignalInstanceTypeF());
+ instanceInitialize(instance, name, self, object, 0);
auto sbkObj = reinterpret_cast<SbkObject *>(object);
if (!Shiboken::Object::wasCreatedByPython(sbkObj))
Py_INCREF(object); // PYSIDE-79: this flag was crucial for a wrapper call.
- instanceInitialize(instance, name, self, object, 0);
return instance;
}
diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt
index bdd88ea37..97d04426d 100644
--- a/sources/pyside2/tests/pysidetest/CMakeLists.txt
+++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt
@@ -157,6 +157,7 @@ PYSIDE_TEST(properties_test.py)
PYSIDE_TEST(qapp_like_a_macro_test.py)
PYSIDE_TEST(qvariant_test.py)
PYSIDE_TEST(repr_test.py)
+PYSIDE_TEST(signal_tp_descr_get_test.py)
PYSIDE_TEST(signal_slot_warning.py)
PYSIDE_TEST(signalandnamespace_test.py)
PYSIDE_TEST(signalemissionfrompython_test.py)
diff --git a/sources/pyside2/tests/pysidetest/signal_tp_descr_get_test.py b/sources/pyside2/tests/pysidetest/signal_tp_descr_get_test.py
new file mode 100644
index 000000000..61ad8b730
--- /dev/null
+++ b/sources/pyside2/tests/pysidetest/signal_tp_descr_get_test.py
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+
+#############################################################################
+##
+## 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$
+##
+#############################################################################
+
+"""
+PYSIDE-68: Test that signals have a `__get__` function after all.
+
+We supply a `tp_descr_get` slot for the signal type.
+That creates the `__get__` method via `PyType_Ready`.
+
+The original test script was converted to a unittest.
+See https://bugreports.qt.io/browse/PYSIDE-68 .
+
+Created: 16 May '12 21:25
+Updated: 17 Sep '20 17:02
+
+This fix was over 8 years late. :)
+"""
+
+from __future__ import print_function
+
+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 import QtCore
+
+
+def emit_upon_success(signal):
+ def f_(f):
+ def f__(self):
+ result = f(self)
+ s = signal.__get__(self)
+ print(result)
+ return result
+ return f__
+ return f_
+
+
+class Foo(QtCore.QObject):
+ SIG = QtCore.Signal()
+
+ @emit_upon_success(SIG)
+ def do_something(self):
+ print("hooka, it worrrks")
+ return 42
+
+
+class UnderUnderGetUnderUnderTest(unittest.TestCase):
+ def test_tp_descr_get(self):
+ foo = Foo()
+ ret = foo.do_something()
+ self.assertEqual(ret, 42)
+
+
+if __name__ == "__main__":
+ unittest.main()