[neon/qt/pyside2/Neon/release] debian: Backport upstream patches to support Python 3.12.

Dmitry Shachnev null at kde.org
Thu Jul 25 03:06:04 BST 2024


Git commit 34279c27272f57c3be78ed71bde92c477bb3a894 by Dmitry Shachnev.
Committed on 24/01/2024 at 20:11.
Pushed by carlosdem into branch 'Neon/release'.

Backport upstream patches to support Python 3.12.

M  +2    -0    debian/changelog
A  +27   -0    debian/patches/Final-details-to-enable-3.12-wheel-compatibility.patch
A  +38   -0    debian/patches/Python-3.12-Fix-the-structure-of-class-property.patch
A  +297  -0    debian/patches/Support-running-PySide-on-Python-3.12.patch
M  +3    -0    debian/patches/series

https://invent.kde.org/neon/qt/pyside2/-/commit/34279c27272f57c3be78ed71bde92c477bb3a894

diff --git a/debian/changelog b/debian/changelog
index db7abc84..9e90facb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,7 @@
 pyside2 (5.15.12-2) UNRELEASED; urgency=medium
 
+  [ Dmitry Shachnev ]
+  * Backport upstream patches to support Python 3.12.
 
  -- Debian Qt/KDE Maintainers <debian-qt-kde at lists.debian.org>  Tue, 23 Jan 2024 15:39:08 +0300
 
diff --git a/debian/patches/Final-details-to-enable-3.12-wheel-compatibility.patch b/debian/patches/Final-details-to-enable-3.12-wheel-compatibility.patch
new file mode 100644
index 00000000..b40d6aa2
--- /dev/null
+++ b/debian/patches/Final-details-to-enable-3.12-wheel-compatibility.patch
@@ -0,0 +1,27 @@
+From: =?utf-8?q?Cristi=C3=A1n_Maureira-Fredes?=
+ <Cristian.Maureira-Fredes at qt.io>
+Date: Tue, 10 Oct 2023 15:52:09 +0200
+Subject: Final details to enable 3.12 wheel compatibility
+
+Change-Id: I0252c4e73e8c214ef8aa418ddf88bc452c0fdf53
+Pick-to: 6.6
+Task-number: PYSIDE-2230
+Reviewed-by: Friedemann Kleint <Friedemann.Kleint at qt.io>
+(cherry picked from commit 6c7bb7b6e1008909e49bc04d2a48024309a784cc)
+---
+ build_scripts/config.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/build_scripts/config.py b/build_scripts/config.py
+index 5fc23d4..fb27394 100644
+--- a/build_scripts/config.py
++++ b/build_scripts/config.py
+@@ -138,7 +138,7 @@ class Config(object):
+         setup_kwargs['zip_safe'] = False
+         setup_kwargs['cmdclass'] = cmd_class_dict
+         setup_kwargs['version'] = package_version
+-        setup_kwargs['python_requires'] = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.12"
++        setup_kwargs['python_requires'] = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.13"
+ 
+         if quiet:
+             # Tells distutils / setuptools to be quiet, and only print warnings or errors.
diff --git a/debian/patches/Python-3.12-Fix-the-structure-of-class-property.patch b/debian/patches/Python-3.12-Fix-the-structure-of-class-property.patch
new file mode 100644
index 00000000..0eadc118
--- /dev/null
+++ b/debian/patches/Python-3.12-Fix-the-structure-of-class-property.patch
@@ -0,0 +1,38 @@
+From: Christian Tismer <tismer at stackless.com>
+Date: Tue, 14 Feb 2023 14:46:22 +0100
+Subject: Python 3.12: Fix the structure of class property
+
+There is a PySide bug in Python 3.10 already: The structure for
+classproperty derives from the property structure. This was extended
+in Python 3.10, already, but the type generation check was made more
+exhaustive in Python 3.12 and recognized that.
+
+This change is only for making the compiler/C API happy.
+In order to use the extension field, it is necessary to do a runtime
+check because of the Limited API.
+
+Task-number: PYSIDE-2230
+Change-Id: I88dcaa11589ff41852f08fa2defa5200a0dd4eb6
+Reviewed-by: Adrian Herrmann <adrian.herrmann at qt.io>
+Reviewed-by: Friedemann Kleint <Friedemann.Kleint at qt.io>
+(cherry picked from commit edfd9a5ad174a48f8d7da511dc6a1c69e931a418)
+---
+ sources/pyside2/libpyside/feature_select.cpp | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp
+index 3011b35..b9e1470 100644
+--- a/sources/pyside2/libpyside/feature_select.cpp
++++ b/sources/pyside2/libpyside/feature_select.cpp
+@@ -671,6 +671,11 @@ typedef struct {
+     PyObject *prop_set;
+     PyObject *prop_del;
+     PyObject *prop_doc;
++#if PY_VERSION_HEX >= 0x030A0000
++    // Note: This is a problem with Limited API: We have no direct access.
++    //       You need to pick it from runtime info.
++    PyObject *prop_name;
++#endif
+     int getter_doc;
+ } propertyobject;
+ 
diff --git a/debian/patches/Support-running-PySide-on-Python-3.12.patch b/debian/patches/Support-running-PySide-on-Python-3.12.patch
new file mode 100644
index 00000000..5ced839b
--- /dev/null
+++ b/debian/patches/Support-running-PySide-on-Python-3.12.patch
@@ -0,0 +1,297 @@
+From: Christian Tismer <tismer at stackless.com>
+Date: Tue, 14 Feb 2023 14:46:22 +0100
+Subject: Support running PySide on Python 3.12
+
+Builtin types no longer have tp_dict set. We need to
+use PyType_GetDict, instead. This works without Limited API
+at the moment.
+
+With some great cheating, this works with Limited API, too.
+We emulate PyType_GetDict by tp_dict if that is not 0.
+Otherwise we create an empty dict.
+
+Some small changes to Exception handling and longer
+warm-up in leaking tests were found, too.
+
+Pick-to: 6.6 6.5 6.2
+Task-number: PYSIDE-2230
+Change-Id: I8a56de6208ec00979255b39b5784dfc9b4b92def
+Reviewed-by: Friedemann Kleint <Friedemann.Kleint at qt.io>
+(cherry picked from commit 441ffbd4fc622e67acd81e9c1c6d3a0b0fbcacf0)
+---
+ build_scripts/config.py                            |  3 +-
+ sources/pyside2/PySide2/support/generate_pyi.py    |  8 ++++--
+ sources/pyside2/libpyside/feature_select.cpp       | 10 ++++---
+ sources/pyside2/libpyside/pysideproperty.cpp       |  4 +--
+ sources/pyside2/libpyside/pysidesignal.cpp         |  4 +--
+ sources/pyside2/tests/QtWidgets/bug_662.py         |  3 +-
+ sources/pyside2/tests/signals/bug_79.py            |  5 ++++
+ sources/shiboken2/libshiboken/pep384impl.cpp       | 33 ++++++++++++++++++++++
+ sources/shiboken2/libshiboken/pep384impl.h         |  8 ++++++
+ .../shiboken2/libshiboken/signature/signature.cpp  |  2 +-
+ .../libshiboken/signature/signature_helper.cpp     |  6 ++--
+ .../shibokensupport/signature/errorhandler.py      |  6 ++++
+ sources/shiboken2/tests/samplebinding/enum_test.py |  2 +-
+ 13 files changed, 78 insertions(+), 16 deletions(-)
+
+diff --git a/build_scripts/config.py b/build_scripts/config.py
+index f2b4c40..5fc23d4 100644
+--- a/build_scripts/config.py
++++ b/build_scripts/config.py
+@@ -94,7 +94,8 @@ class Config(object):
+             'Programming Language :: Python :: 3.8',
+             'Programming Language :: Python :: 3.9',
+             'Programming Language :: Python :: 3.10',
+-            'Programming Language :: Python :: 3.11'
++            'Programming Language :: Python :: 3.11',
++            'Programming Language :: Python :: 3.12',
+         ]
+ 
+         self.setup_script_dir = None
+diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py
+index 1956533..fd05b1f 100644
+--- a/sources/pyside2/PySide2/support/generate_pyi.py
++++ b/sources/pyside2/PySide2/support/generate_pyi.py
+@@ -116,8 +116,12 @@ class Formatter(Writer):
+         """
+         def _typevar__repr__(self):
+             return "typing." + self.__name__
+-        typing.TypeVar.__repr__ = _typevar__repr__
+-
++        # This is no longer necessary for modern typing versions.
++        # Ignore therefore if the repr is read-only and cannot be changed.
++        try:
++            typing.TypeVar.__repr__ = _typevar__repr__
++        except TypeError:
++            pass
+         # Adding a pattern to substitute "Union[T, NoneType]" by "Optional[T]"
+         # I tried hard to replace typing.Optional by a simple override, but
+         # this became _way_ too much.
+diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp
+index b9e1470..533c09d 100644
+--- a/sources/pyside2/libpyside/feature_select.cpp
++++ b/sources/pyside2/libpyside/feature_select.cpp
+@@ -358,7 +358,8 @@ static bool SelectFeatureSetSubtype(PyTypeObject *type, PyObject *select_id)
+      * This is the selector for one sublass. We need to call this for
+      * every subclass until no more subclasses or reaching the wanted id.
+      */
+-    if (Py_TYPE(type->tp_dict) == Py_TYPE(PyType_Type.tp_dict)) {
++    static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
++    if (Py_TYPE(type->tp_dict) == Py_TYPE(pyTypeType_tp_dict)) {
+         // On first touch, we initialize the dynamic naming.
+         // The dict type will be replaced after the first call.
+         if (!replaceClassDict(type)) {
+@@ -385,7 +386,8 @@ static inline PyObject *SelectFeatureSet(PyTypeObject *type)
+      * Generated functions call this directly.
+      * Shiboken will assign it via a public hook of `basewrapper.cpp`.
+      */
+-    if (Py_TYPE(type->tp_dict) == Py_TYPE(PyType_Type.tp_dict)) {
++    static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
++    if (Py_TYPE(type->tp_dict) == Py_TYPE(pyTypeType_tp_dict)) {
+         // We initialize the dynamic features by using our own dict type.
+         if (!replaceClassDict(type))
+             return nullptr;
+@@ -721,11 +723,11 @@ static bool patch_property_impl()
+     // Turn `__doc__` into a computed attribute without changing writability.
+     auto gsp = property_getset;
+     auto type = &PyProperty_Type;
+-    auto dict = type->tp_dict;
++    AutoDecRef dict(PepType_GetDict(type));
+     AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
+     if (descr.isNull())
+         return false;
+-    if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
++    if (PyDict_SetItemString(dict.object(), gsp->name, descr) < 0)
+         return false;
+     // Replace property_descr_get/set by slightly changed versions
+     return true;
+diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp
+index 86909d3..d2e2c68 100644
+--- a/sources/pyside2/libpyside/pysideproperty.cpp
++++ b/sources/pyside2/libpyside/pysideproperty.cpp
+@@ -445,8 +445,8 @@ namespace {
+ 
+ static PyObject *getFromType(PyTypeObject *type, PyObject *name)
+ {
+-    PyObject *attr = nullptr;
+-    attr = PyDict_GetItem(type->tp_dict, name);
++    AutoDecRef tpDict(PepType_GetDict(type));
++    auto *attr = PyDict_GetItem(tpDict.object(), name);
+     if (!attr) {
+         PyObject *bases = type->tp_bases;
+         int size = PyTuple_GET_SIZE(bases);
+diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp
+index 6824a71..f15d7aa 100644
+--- a/sources/pyside2/libpyside/pysidesignal.cpp
++++ b/sources/pyside2/libpyside/pysidesignal.cpp
+@@ -670,8 +670,8 @@ void updateSourceObject(PyObject *source)
+     Py_ssize_t pos = 0;
+     PyObject *value;
+     PyObject *key;
+-
+-    while (PyDict_Next(objType->tp_dict, &pos, &key, &value)) {
++    Shiboken::AutoDecRef tpDict(PepType_GetDict(objType));
++    while (PyDict_Next(tpDict, &pos, &key, &value)) {
+         if (PyObject_TypeCheck(value, PySideSignalTypeF())) {
+             Shiboken::AutoDecRef signalInstance(reinterpret_cast<PyObject *>(PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF())));
+             instanceInitialize(signalInstance.cast<PySideSignalInstance *>(), key, reinterpret_cast<PySideSignal *>(value), source, 0);
+diff --git a/sources/pyside2/tests/QtWidgets/bug_662.py b/sources/pyside2/tests/QtWidgets/bug_662.py
+index 7fb97de..ec0e6f9 100644
+--- a/sources/pyside2/tests/QtWidgets/bug_662.py
++++ b/sources/pyside2/tests/QtWidgets/bug_662.py
+@@ -40,7 +40,8 @@ from PySide2.QtWidgets import QTextEdit, QApplication
+ import sys
+ 
+ class testQTextBlock(unittest.TestCase):
+-    def tesIterator(self):
++
++    def testIterator(self):
+         edit = QTextEdit()
+         cursor = edit.textCursor()
+         fmt = QTextCharFormat()
+diff --git a/sources/pyside2/tests/signals/bug_79.py b/sources/pyside2/tests/signals/bug_79.py
+index ca25fb3..b70c8c5 100644
+--- a/sources/pyside2/tests/signals/bug_79.py
++++ b/sources/pyside2/tests/signals/bug_79.py
+@@ -60,6 +60,11 @@ class ConnectTest(unittest.TestCase):
+         gc.collect()
+         # if this is no debug build, then we check at least that
+         # we do not crash any longer.
++        for idx in range(200):
++            # PYSIDE-2230: Warm-up is necessary before measuring, because
++            # the code changes the constant parts after some time.
++            o.selectionModel().destroyed.connect(self.callback)
++            o.selectionModel().destroyed.disconnect(self.callback)
+         if not skiptest:
+             total = gettotalrefcount()
+         for idx in range(1000):
+diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
+index fb28d88..cc85bb1 100644
+--- a/sources/shiboken2/libshiboken/pep384impl.cpp
++++ b/sources/shiboken2/libshiboken/pep384impl.cpp
+@@ -811,6 +811,39 @@ init_PepRuntime()
+         PepRuntime_38_flag = 1;
+ }
+ 
++#ifdef Py_LIMITED_API
++static PyObject *emulatePyType_GetDict(PyTypeObject *type)
++{
++    if (_PepRuntimeVersion() < 0x030C00 || type->tp_dict) {
++        auto *res = type->tp_dict;
++        Py_XINCREF(res);
++        return res;
++    }
++    // PYSIDE-2230: Here we are really cheating. We don't know how to
++    //              access an internal dict, and so we simply pretend
++    //              it were an empty dict. This works great for our types.
++    // This was an unexpectedly simple solution :D
++    return PyDict_New();
++}
++#endif
++
++// PyType_GetDict: replacement for <static type>.tp_dict, which is
++// zero for builtin types since 3.12.
++PyObject *PepType_GetDict(PyTypeObject *type)
++{
++#if !defined(Py_LIMITED_API)
++#  if PY_VERSION_HEX >= 0x030C0000
++    return PyType_GetDict(type);
++#  else
++    // pre 3.12 fallback code, mimicking the addref-behavior.
++    Py_XINCREF(type->tp_dict);
++    return type->tp_dict;
++#  endif
++#else
++    return emulatePyType_GetDict(type);
++#endif // Py_LIMITED_API
++}
++
+ /*****************************************************************************
+  *
+  * Module Initialization
+diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
+index 1ba8205..de06b6b 100644
+--- a/sources/shiboken2/libshiboken/pep384impl.h
++++ b/sources/shiboken2/libshiboken/pep384impl.h
+@@ -568,6 +568,14 @@ extern LIBSHIBOKEN_API PyObject *PepMapping_Items(PyObject *o);
+ 
+ extern LIBSHIBOKEN_API int PepRuntime_38_flag;
+ 
++/*****************************************************************************
++ *
++ * Runtime support for Python 3.12 incompatibility
++ *
++ */
++
++LIBSHIBOKEN_API PyObject *PepType_GetDict(PyTypeObject *type);
++
+ /*****************************************************************************
+  *
+  * Module Initialization
+diff --git a/sources/shiboken2/libshiboken/signature/signature.cpp b/sources/shiboken2/libshiboken/signature/signature.cpp
+index 191af3d..f817e47 100644
+--- a/sources/shiboken2/libshiboken/signature/signature.cpp
++++ b/sources/shiboken2/libshiboken/signature/signature.cpp
+@@ -482,7 +482,7 @@ static PyObject *adjustFuncName(const char *func_name)
+ 
+     // Find the feature flags
+     auto type = reinterpret_cast<PyTypeObject *>(obtype.object());
+-    auto dict = type->tp_dict;
++    AutoDecRef dict(PepType_GetDict(type));
+     int id = SbkObjectType_GetReserved(type);
+     id = id < 0 ? 0 : id;   // if undefined, set to zero
+     auto lower = id & 0x01;
+diff --git a/sources/shiboken2/libshiboken/signature/signature_helper.cpp b/sources/shiboken2/libshiboken/signature/signature_helper.cpp
+index 0246ec6..05eaa14 100644
+--- a/sources/shiboken2/libshiboken/signature/signature_helper.cpp
++++ b/sources/shiboken2/libshiboken/signature/signature_helper.cpp
+@@ -105,7 +105,8 @@ int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr)
+      */
+     assert(PyType_Check(type));
+     PyType_Ready(type);
+-    PyObject *dict = type->tp_dict;
++    AutoDecRef tpDict(PepType_GetDict(type));
++    auto *dict = tpDict.object();
+     for (; gsp->name != nullptr; gsp++) {
+         PyObject *have_descr = PyDict_GetItemString(dict, gsp->name);
+         if (have_descr != nullptr) {
+@@ -346,7 +347,8 @@ static int _build_func_to_type(PyObject *obtype)
+      * We also check for hidden methods, see below.
+      */
+     auto *type = reinterpret_cast<PyTypeObject *>(obtype);
+-    PyObject *dict = type->tp_dict;
++    AutoDecRef tpDict(PepType_GetDict(type));
++    auto *dict = tpDict.object();
+     PyMethodDef *meth = type->tp_methods;
+ 
+     if (meth == nullptr)
+diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
+index 47ab89a..3e1266c 100644
+--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
++++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
+@@ -113,6 +113,12 @@ def seterror_argument(args, func_name, info):
+             msg = "{func_name}(): {info}".format(**locals())
+             err = AttributeError
+         return err, msg
++    if isinstance(info, Exception):
++        # PYSIDE-2230: Python 3.12 seems to always do normalization.
++        err = type(info)
++        info = info.args[0]
++        msg = f"{func_name}(): {info}"
++        return err, msg
+     if info and type(info) is dict:
+         keyword = tuple(info)[0]
+         msg = "{func_name}(): unsupported keyword '{keyword}'".format(**locals())
+diff --git a/sources/shiboken2/tests/samplebinding/enum_test.py b/sources/shiboken2/tests/samplebinding/enum_test.py
+index 0beb720..f2606a4 100644
+--- a/sources/shiboken2/tests/samplebinding/enum_test.py
++++ b/sources/shiboken2/tests/samplebinding/enum_test.py
+@@ -95,7 +95,7 @@ class EnumTest(unittest.TestCase):
+ 
+     def testEnumConstructorWithTooManyParameters(self):
+         '''Calling the constructor of non-extensible enum with the wrong number of parameters.'''
+-        self.assertRaises(TypeError, SampleNamespace.InValue, 13, 14)
++        self.assertRaises((TypeError, ValueError), SampleNamespace.InValue, 13, 14)
+ 
+     def testEnumConstructorWithNonNumberParameter(self):
+         '''Calling the constructor of non-extensible enum with a string.'''
diff --git a/debian/patches/series b/debian/patches/series
index 3d7656ca..ccdf9235 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -5,3 +5,6 @@ test-with-current-interpreter.patch
 Shiboken-Fix-the-oldest-shiboken-bug-ever.patch
 PyEnum-make-forgiving-duplicates-work-with-Python-3.11.patch
 Fix-tests-sample_privatector-sample_privatedtor-failing-w.patch
+Python-3.12-Fix-the-structure-of-class-property.patch
+Support-running-PySide-on-Python-3.12.patch
+Final-details-to-enable-3.12-wheel-compatibility.patch



More information about the Neon-commits mailing list