Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6')
-rw-r--r--sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml5
-rw-r--r--sources/pyside6/libpyside/pysidemetafunction.cpp8
-rw-r--r--sources/pyside6/libpyside/pysideproperty.cpp25
-rw-r--r--sources/pyside6/libpyside/signalmanager.cpp71
-rw-r--r--sources/pyside6/libpyside/signalmanager.h8
-rw-r--r--sources/pyside6/tests/QtCore/qobject_property_test.py34
-rw-r--r--sources/pyside6/tests/QtWidgets/bug_433.py2
-rw-r--r--sources/pyside6/tests/QtWidgets/bug_919.py9
-rw-r--r--sources/pyside6/tests/QtWidgets/qapp_issue_585.py10
-rw-r--r--sources/pyside6/tests/QtWidgets/qmenu_test.py18
10 files changed, 143 insertions, 47 deletions
diff --git a/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml b/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
index a15527c03..c6e93cfd7 100644
--- a/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
+++ b/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
@@ -1489,6 +1489,7 @@
<enum-type name="InputMode"/>
<modify-function signature="getInt(QWidget*,const QString&amp;,const QString&amp;,int,int,int,int,bool*,QFlags&lt;Qt::WindowType&gt;)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[int, bool]"/>
<modify-argument index="8">
<remove-default-expression/>
@@ -1500,6 +1501,7 @@
</modify-function>
<modify-function signature="getItem(QWidget*,const QString&amp;,const QString&amp;,const QStringList&amp;,int,bool,bool*,QFlags&lt;Qt::WindowType&gt;,QFlags&lt;Qt::InputMethodHint&gt;)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[str, bool]"/>
<modify-argument index="7">
<remove-default-expression/>
@@ -1511,6 +1513,7 @@
</modify-function>
<modify-function signature="getMultiLineText(QWidget*,const QString&amp;,const QString&amp;,const QString&amp;,bool*,QFlags&lt;Qt::WindowType&gt;,QFlags&lt;Qt::InputMethodHint&gt;)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[str, bool]"/>
<modify-argument index="5">
<remove-default-expression/>
@@ -1522,6 +1525,7 @@
</modify-function>
<modify-function signature="getText(QWidget*,const QString&amp;,const QString&amp;,QLineEdit::EchoMode,const QString&amp;,bool*,QFlags&lt;Qt::WindowType&gt;,QFlags&lt;Qt::InputMethodHint&gt;)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[str, bool]"/>
<modify-argument index="6">
<remove-default-expression/>
@@ -1533,6 +1537,7 @@
</modify-function>
<modify-function signature="getDouble(QWidget*,const QString&amp;,const QString&amp;,double,double,double,int,bool*,QFlags&lt;Qt::WindowType&gt;,double)" allow-thread="yes">
+ <modify-argument index="1" pyi-type="Optional[PySide6.QtWidgets.QWidget]"/>
<modify-argument index="return" pyi-type="Tuple[float, bool]"/>
<modify-argument index="8">
<remove-default-expression/>
diff --git a/sources/pyside6/libpyside/pysidemetafunction.cpp b/sources/pyside6/libpyside/pysidemetafunction.cpp
index 48aba3c7b..7a496c4b7 100644
--- a/sources/pyside6/libpyside/pysidemetafunction.cpp
+++ b/sources/pyside6/libpyside/pysidemetafunction.cpp
@@ -4,6 +4,8 @@
#include "pysidemetafunction.h"
#include "pysidemetafunction_p.h"
+#include <signalmanager.h>
+
#include <autodecref.h>
#include <basewrapper.h>
#include <sbkconverter.h>
@@ -12,6 +14,8 @@
#include <QtCore/qmetaobject.h>
+using namespace Qt::StringLiterals;
+
extern "C"
{
@@ -164,6 +168,10 @@ bool call(QObject *self, int methodIndex, PyObject *args, PyObject **retVal)
QString tmp;
converter.toCpp(obj, &tmp);
methValues[i] = tmp;
+ } else if (metaType.id() == PyObjectWrapper::metaTypeId()) {
+ // Manual conversion, see PyObjectWrapper converter registration
+ methValues[i] = QVariant::fromValue(PyObjectWrapper(obj.object()));
+ methArgs[i] = methValues[i].data();
} else {
converter.toCpp(obj, methArgs[i]);
}
diff --git a/sources/pyside6/libpyside/pysideproperty.cpp b/sources/pyside6/libpyside/pysideproperty.cpp
index e8ea2fa03..69d347043 100644
--- a/sources/pyside6/libpyside/pysideproperty.cpp
+++ b/sources/pyside6/libpyside/pysideproperty.cpp
@@ -6,6 +6,7 @@
#include "pysideproperty_p.h"
#include "pysidesignal.h"
#include "pysidesignal_p.h"
+#include "signalmanager.h"
#include <autodecref.h>
#include <pep384ext.h>
@@ -17,6 +18,8 @@
using namespace Shiboken;
+using namespace Qt::StringLiterals;
+
extern "C"
{
@@ -148,16 +151,20 @@ void PySidePropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, v
switch (call) {
case QMetaObject::ReadProperty: {
AutoDecRef value(getValue(source));
- auto *obValue = value.object();
- if (obValue) {
- Conversions::SpecificConverter converter(typeName);
- if (converter) {
- converter.toCpp(obValue, args[0]);
- } else {
- // PYSIDE-2160: Report an unknown type name to the caller `qtPropertyMetacall`.
- PyErr_SetObject(PyExc_StopIteration, obValue);
- }
+ if (value.isNull())
+ return;
+ if (typeName == "PyObject"_ba) {
+ // Manual conversion, see PyObjectWrapper converter registration
+ auto *pw = reinterpret_cast<PySide::PyObjectWrapper *>(args[0]);
+ pw->reset(value.object());
+ return;
+ }
+ if (Conversions::SpecificConverter converter(typeName); converter) {
+ converter.toCpp(value.object(), args[0]);
+ return;
}
+ // PYSIDE-2160: Report an unknown type name to the caller `qtPropertyMetacall`.
+ PyErr_SetObject(PyExc_StopIteration, value.object());
}
break;
diff --git a/sources/pyside6/libpyside/signalmanager.cpp b/sources/pyside6/libpyside/signalmanager.cpp
index 933edd318..305d2f5c3 100644
--- a/sources/pyside6/libpyside/signalmanager.cpp
+++ b/sources/pyside6/libpyside/signalmanager.cpp
@@ -24,9 +24,12 @@
#include <QtCore/qcoreevent.h>
#include <QtCore/qdebug.h>
#include <QtCore/qhash.h>
+#include <QtCore/qmetatype.h>
#include <QtCore/qscopedpointer.h>
+#include <climits>
#include <memory>
+#include <utility>
using namespace Qt::StringLiterals;
@@ -36,6 +39,8 @@ using namespace Qt::StringLiterals;
static PyObject *metaObjectAttr = nullptr;
+static int pyObjectWrapperMetaTypeId = QMetaType::UnknownType;
+
static void destroyMetaObject(PyObject *obj)
{
void *ptr = PyCapsule_GetPointer(obj, nullptr);
@@ -125,6 +130,17 @@ PyObjectWrapper::PyObjectWrapper(const PyObjectWrapper &other)
Py_XINCREF(m_me);
}
+PyObjectWrapper::PyObjectWrapper(PyObjectWrapper &&other) noexcept
+ : m_me{std::exchange(other.m_me, nullptr)}
+{
+}
+
+PyObjectWrapper &PyObjectWrapper::operator=(PyObjectWrapper &&other) noexcept
+{
+ m_me = std::exchange(other.m_me, nullptr);
+ return *this;
+}
+
PyObjectWrapper::~PyObjectWrapper()
{
// Check that Python is still initialized as sometimes this is called by a static destructor
@@ -156,6 +172,10 @@ PyObjectWrapper::operator PyObject *() const
return m_me;
}
+int PyObjectWrapper::metaTypeId()
+{
+ return pyObjectWrapperMetaTypeId;
+}
int PyObjectWrapper::toInt() const
{
@@ -221,7 +241,29 @@ QDataStream &operator>>(QDataStream &in, PyObjectWrapper &myObj)
return in;
}
-};
+PYSIDE_API QDebug operator<<(QDebug debug, const PyObjectWrapper &myObj)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ // Do not repeat the type name as it is typically called from the QVariant debug
+ // operator, which outputs the type.
+ debug << '<';
+ if (PyObject *ob = myObj) {
+ const auto refs = Py_REFCNT(ob);
+ debug << Py_TYPE(ob)->tp_name << " at " << ob;
+ if (refs == UINT_MAX) // _Py_IMMORTAL_REFCNT
+ debug << ", immortal";
+ else
+ debug << ", refs=" << refs;
+ } else {
+ debug << '0';
+ }
+ debug << '>';
+ return debug;
+}
+
+} // namespace PySide
using namespace PySide;
@@ -238,19 +280,11 @@ struct SignalManagerPrivate
SignalManager::QmlMetaCallErrorHandler
SignalManagerPrivate::m_qmlMetaCallErrorHandler = nullptr;
-static void PyObject_PythonToCpp_PyObject_PTR(PyObject *pyIn, void *cppOut)
-{
- *reinterpret_cast<PyObject **>(cppOut) = pyIn;
-}
-static PythonToCppFunc is_PyObject_PythonToCpp_PyObject_PTR_Convertible(PyObject * /* pyIn */)
-{
- return PyObject_PythonToCpp_PyObject_PTR;
-}
-static PyObject *PyObject_PTR_CppToPython_PyObject(const void *cppIn)
+static PyObject *CopyCppToPythonPyObject(const void *cppIn)
{
- auto *pyOut = reinterpret_cast<PyObject *>(const_cast<void *>(cppIn));
- if (pyOut)
- Py_INCREF(pyOut);
+ const auto *wrapper = reinterpret_cast<const PyObjectWrapper *>(cppIn);
+ PyObject *pyOut = *wrapper;
+ Py_XINCREF(pyOut);
return pyOut;
}
@@ -260,13 +294,16 @@ void SignalManager::init()
using namespace Shiboken;
// Register PyObject type to use in queued signal and slot connections
- qRegisterMetaType<PyObjectWrapper>("PyObject");
+ pyObjectWrapperMetaTypeId = qRegisterMetaType<PyObjectWrapper>("PyObject");
// Register QVariant(enum) conversion to QVariant(int)
QMetaType::registerConverter<PyObjectWrapper, int>(&PyObjectWrapper::toInt);
- SbkConverter *converter = Shiboken::Conversions::createConverter(&PyBaseObject_Type, nullptr);
- Shiboken::Conversions::setCppPointerToPythonFunction(converter, PyObject_PTR_CppToPython_PyObject);
- Shiboken::Conversions::setPythonToCppPointerFunctions(converter, PyObject_PythonToCpp_PyObject_PTR, is_PyObject_PythonToCpp_PyObject_PTR_Convertible);
+ // Register a shiboken converter for PyObjectWrapper->Python (value conversion).
+ // Python->PyObjectWrapper is not registered since the converters do not work for
+ // non-SbkObject types (falling back to plain pointer pass through).
+ // This conversion needs to be done manually via QVariant.
+ SbkConverter *converter = Shiboken::Conversions::createConverter(&PyBaseObject_Type,
+ CopyCppToPythonPyObject);
Shiboken::Conversions::registerConverterName(converter, "PyObject");
Shiboken::Conversions::registerConverterName(converter, "object");
Shiboken::Conversions::registerConverterName(converter, "PyObjectWrapper");
diff --git a/sources/pyside6/libpyside/signalmanager.h b/sources/pyside6/libpyside/signalmanager.h
index d5c007dbe..9fe56efc2 100644
--- a/sources/pyside6/libpyside/signalmanager.h
+++ b/sources/pyside6/libpyside/signalmanager.h
@@ -14,6 +14,7 @@
#include <optional>
QT_FORWARD_DECLARE_CLASS(QDataStream)
+QT_FORWARD_DECLARE_CLASS(QDebug)
namespace PySide
{
@@ -22,13 +23,13 @@ namespace PySide
class PYSIDE_API PyObjectWrapper
{
public:
- PyObjectWrapper(PyObjectWrapper&&) = delete;
- PyObjectWrapper& operator=(PyObjectWrapper &&) = delete;
PyObjectWrapper();
explicit PyObjectWrapper(PyObject* me);
PyObjectWrapper(const PyObjectWrapper &other);
PyObjectWrapper& operator=(const PyObjectWrapper &other);
+ PyObjectWrapper(PyObjectWrapper&&) noexcept;
+ PyObjectWrapper &operator=(PyObjectWrapper &&) noexcept;
void reset(PyObject *o);
@@ -43,12 +44,15 @@ public:
// The proper fix would be to associate PyObjectWrapper to the corresponding C++ Enum.
int toInt() const;
+ static int metaTypeId();
+
private:
PyObject* m_me;
};
PYSIDE_API QDataStream &operator<<(QDataStream& out, const PyObjectWrapper& myObj);
PYSIDE_API QDataStream &operator>>(QDataStream& in, PyObjectWrapper& myObj);
+PYSIDE_API QDebug operator<<(QDebug debug, const PyObjectWrapper &myObj);
class PYSIDE_API SignalManager
{
diff --git a/sources/pyside6/tests/QtCore/qobject_property_test.py b/sources/pyside6/tests/QtCore/qobject_property_test.py
index 37936205e..80387ec77 100644
--- a/sources/pyside6/tests/QtCore/qobject_property_test.py
+++ b/sources/pyside6/tests/QtCore/qobject_property_test.py
@@ -32,6 +32,26 @@ class MyObjectWithNotifyProperty(QObject):
myProperty = Property(int, readP, fset=writeP, notify=notifyP)
+class OtherClass:
+ """Helper for QObjectWithOtherClassPropertyTest."""
+ pass
+
+
+class MyObjectWithOtherClassProperty(QObject):
+ """Helper for QObjectWithOtherClassPropertyTest."""
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._otherclass = None
+
+ def _get_otherclass(self):
+ return self._otherclass
+
+ def _set_otherclass(self, o):
+ self._otherclass = o
+
+ otherclass = Property(OtherClass, fget=_get_otherclass, fset=_set_otherclass)
+
+
class PropertyWithNotify(unittest.TestCase):
def called(self):
self.called_ = True
@@ -50,5 +70,19 @@ class PropertyWithNotify(unittest.TestCase):
self.assertEqual(o.property("myProperty"), 10)
+class QObjectWithOtherClassPropertyTest(unittest.TestCase):
+ """PYSIDE-2193: For properties of custom classes not wrapped by shiboken,
+ QVariant<PyObjectWrapper> is used, which had refcount issues causing crashes.
+ Exercise the QVariant conversion by setting and retrieving via the
+ QVariant-based property()/setProperty() API."""
+ def testNotify(self):
+ obj = MyObjectWithOtherClassProperty()
+ obj.setProperty("otherclass", OtherClass())
+ for i in range(10):
+ pv = obj.property("otherclass")
+ print(pv) # Exercise repr
+ self.assertTrue(type(pv) is OtherClass)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside6/tests/QtWidgets/bug_433.py b/sources/pyside6/tests/QtWidgets/bug_433.py
index 5adcacccc..6d5c4333a 100644
--- a/sources/pyside6/tests/QtWidgets/bug_433.py
+++ b/sources/pyside6/tests/QtWidgets/bug_433.py
@@ -26,4 +26,4 @@ a = QApplication(sys.argv)
t = Test()
t.show()
QTimer.singleShot(0, t.close)
-sys.exit(a.exec_())
+sys.exit(a.exec())
diff --git a/sources/pyside6/tests/QtWidgets/bug_919.py b/sources/pyside6/tests/QtWidgets/bug_919.py
index 6f2fc128d..a95d3aa37 100644
--- a/sources/pyside6/tests/QtWidgets/bug_919.py
+++ b/sources/pyside6/tests/QtWidgets/bug_919.py
@@ -26,10 +26,11 @@ class MyWidget(QPushButton):
self.paintReceived.emit()
def paintEvent(self, e):
- p = QPainter(self)
- style = QApplication.style()
- option = QStyleOptionButton()
- style.drawControl(QStyle.ControlElement.CE_PushButton, option, p)
+ with QPainter(self) as p:
+ style = QApplication.style()
+ option = QStyleOptionButton()
+ self.initStyleOption(option)
+ style.drawControl(QStyle.ControlElement.CE_PushButton, option, p)
self._painted = True
QTimer.singleShot(0, self._emitPainted)
diff --git a/sources/pyside6/tests/QtWidgets/qapp_issue_585.py b/sources/pyside6/tests/QtWidgets/qapp_issue_585.py
index ec8a47569..1300ea4aa 100644
--- a/sources/pyside6/tests/QtWidgets/qapp_issue_585.py
+++ b/sources/pyside6/tests/QtWidgets/qapp_issue_585.py
@@ -40,15 +40,15 @@ import sys
from pathlib import Path
sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
sys.path.append(os.fspath(Path(__file__).resolve().parents[1] / "util"))
-from init_paths import init_test_paths
+from init_paths import init_test_paths # noqa: E402
init_test_paths()
-from PySide6.QtCore import QTimer
-from PySide6.QtWidgets import QApplication
+from PySide6.QtCore import QTimer # noqa: E402
+from PySide6.QtWidgets import QApplication # noqa: E402
app_instance = QApplication([])
# If the following line is commented, application doesn't crash on exit anymore.
app_instance2 = app_instance
-QTimer.singleShot(0, qApp.quit)
-app_instance.exec_()
+QTimer.singleShot(0, qApp.quit) # noqa: F821
+app_instance.exec()
diff --git a/sources/pyside6/tests/QtWidgets/qmenu_test.py b/sources/pyside6/tests/QtWidgets/qmenu_test.py
index 7d1d262e4..8bd5d1624 100644
--- a/sources/pyside6/tests/QtWidgets/qmenu_test.py
+++ b/sources/pyside6/tests/QtWidgets/qmenu_test.py
@@ -33,16 +33,16 @@ class QMenuAddAction(UsesQApplication):
def testAddActionWithoutKeySequenceCallable(self):
# bug #280
- action = self.menu.addAction(self.app.tr('aaa'), lambda: 1)
+ action = self.menu.addAction(self.app.tr('aaa'), lambda: 1) # noqa: F841
def testAddActionKeySequenceCallable(self):
# bug #228
- action = self.menu.addAction(self.app.tr('aaa'), lambda: 1,
+ action = self.menu.addAction(self.app.tr('aaa'), lambda: 1, # noqa: F841
QKeySequence(self.app.tr('Ctrl+O')))
def testAddActionKeySequenceSlot(self):
- action = self.menu.addAction('Quit', self.app, SLOT('quit()'),
- QKeySequence('Ctrl+O'))
+ action = self.menu.addAction('Quit', QKeySequence('Ctrl+O'), # noqa: F841
+ self.app, SLOT('quit()'))
class QMenuAddActionWithIcon(UsesQApplication):
@@ -61,16 +61,16 @@ class QMenuAddActionWithIcon(UsesQApplication):
def testAddActionWithoutKeySequenceCallable(self):
# bug #280
- action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1)
+ action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1) # noqa: F841
def testAddActionKeySequenceCallable(self):
# bug #228
- action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1,
- QKeySequence(self.app.tr('Ctrl+O')))
+ action = self.menu.addAction(self.icon, self.app.tr('aaa'), lambda: 1, # noqa: F841
+ QKeySequence(self.app.tr('Ctrl+O'))) # noqa: F841
def testAddActionKeySequenceSlot(self):
- action = self.menu.addAction(self.icon, 'Quit', self.app, SLOT('quit()'),
- QKeySequence('Ctrl+O'))
+ action = self.menu.addAction(self.icon, 'Quit', QKeySequence('Ctrl+O'), # noqa: F841
+ self.app, SLOT('quit()')) # noqa: F841
if __name__ == '__main__':