File python312.patch of Package python3-pyside2

From 441ffbd4fc622e67acd81e9c1c6d3a0b0fbcacf0 Mon Sep 17 00:00:00 2001
From: Christian Tismer <tismer@stackless.com>
Date: Tue, 14 Feb 2023 14:46:22 +0100
Subject: [PATCH] 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@qt.io>
---
 build_scripts/config.py                       |  1 +
 sources/pyside2/libpyside/feature_select.cpp  | 10 +++--
 sources/pyside2/libpyside/pysideproperty.cpp  |  4 +-
 sources/pyside2/libpyside/pysidesignal.cpp    |  7 +--
 sources/pyside2/tests/QtWidgets/bug_662.py    |  3 +-
 sources/pyside2/tests/pysidetest/enum_test.py | 19 +++++++-
 sources/pyside2/tests/signals/bug_79.py       |  5 +++
 sources/shiboken2/libshiboken/pep384impl.cpp  | 44 ++++++++++++++++---
 sources/shiboken2/libshiboken/pep384impl.h    |  8 ++++
 .../shiboken2/libshiboken/sbkfeature_base.cpp | 32 +++++++++++---
 .../shiboken2/libshiboken/sbksmartpointer.cpp |  3 +-
 .../shiboken2/libshiboken/sbktypefactory.cpp  |  3 +-
 .../libshiboken/signature/signature.cpp       |  2 +-
 .../signature/signature_helper.cpp            |  6 ++-
 .../shibokensupport/signature/errorhandler.py |  6 +++
 .../signature/lib/pyi_generator.py            |  9 +++-
 .../tests/samplebinding/enum_test.py          |  2 +-
 17 files changed, 133 insertions(+), 31 deletions(-)

Index: pyside-setup-opensource-src-5.15.12/sources/pyside2/libpyside/feature_select.cpp
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/pyside2/libpyside/feature_select.cpp
+++ pyside-setup-opensource-src-5.15.12/sources/pyside2/libpyside/feature_select.cpp
@@ -358,7 +358,8 @@ static bool SelectFeatureSetSubtype(PyTy
      * 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
      * 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;
@@ -716,11 +718,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;
Index: pyside-setup-opensource-src-5.15.12/sources/pyside2/libpyside/pysideproperty.cpp
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/pyside2/libpyside/pysideproperty.cpp
+++ pyside-setup-opensource-src-5.15.12/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);
Index: pyside-setup-opensource-src-5.15.12/sources/pyside2/libpyside/pysidesignal.cpp
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/pyside2/libpyside/pysidesignal.cpp
+++ pyside-setup-opensource-src-5.15.12/sources/pyside2/libpyside/pysidesignal.cpp
@@ -671,7 +671,8 @@ void updateSourceObject(PyObject *source
     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);
Index: pyside-setup-opensource-src-5.15.12/sources/pyside2/tests/QtWidgets/bug_662.py
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/pyside2/tests/QtWidgets/bug_662.py
+++ pyside-setup-opensource-src-5.15.12/sources/pyside2/tests/QtWidgets/bug_662.py
@@ -40,7 +40,8 @@ from PySide2.QtWidgets import QTextEdit,
 import sys
 
 class testQTextBlock(unittest.TestCase):
-    def tesIterator(self):
+
+    def testIterator(self):
         edit = QTextEdit()
         cursor = edit.textCursor()
         fmt = QTextCharFormat()
Index: pyside-setup-opensource-src-5.15.12/sources/pyside2/tests/signals/bug_79.py
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/pyside2/tests/signals/bug_79.py
+++ pyside-setup-opensource-src-5.15.12/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):
Index: pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/basewrapper.cpp
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/shiboken2/libshiboken/basewrapper.cpp
+++ pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2023 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of Qt for Python.
@@ -250,7 +250,8 @@ patch_tp_new_wrapper(PyTypeObject *type)
     Py_ssize_t i, n = PyTuple_GET_SIZE(mro);
     for (i = 0; i < n; i++) {
         type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i));
-        PyObject *existing = PyDict_GetItem(type->tp_dict, newMethod);
+        Shiboken::AutoDecRef tpDict(PepType_GetDict(type));
+        PyObject *existing = PyDict_GetItem(tpDict, newMethod);
         if (existing && PyCFunction_Check(existing)
                      && type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
             auto *pycf_ob = reinterpret_cast<PyCFunctionObject *>(existing);
@@ -260,7 +261,8 @@ patch_tp_new_wrapper(PyTypeObject *type)
             if (existing_wrapper == old_tp_new_wrapper) {
                 PyObject *ob_type = reinterpret_cast<PyObject *>(type);
                 Shiboken::AutoDecRef func(PyCFunction_New(tp_new_methoddef, ob_type));
-                if (func.isNull() || PyDict_SetItem(type->tp_dict, newMethod, func))
+		Shiboken::AutoDecRef tpDict(PepType_GetDict(type));
+                if (func.isNull() || PyDict_SetItem(tpDict, newMethod, func))
                     return -1;
             }
         }
Index: pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/pep384impl.cpp
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/shiboken2/libshiboken/pep384impl.cpp
+++ pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -560,6 +560,39 @@ PyDict_GetItemWithError(PyObject *op, Py
 }
 #endif // IS_PY2
 
+#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
+}
+
 /*****************************************************************************
  *
  * Extra support for signature.cpp
Index: pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/pep384impl.h
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/shiboken2/libshiboken/pep384impl.h
+++ pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/pep384impl.h
@@ -559,6 +559,14 @@ extern LIBSHIBOKEN_API int PepRuntime_38
 
 /*****************************************************************************
  *
+ * Runtime support for Python 3.12 incompatibility
+ *
+ */
+
+LIBSHIBOKEN_API PyObject *PepType_GetDict(PyTypeObject *type);
+
+/*****************************************************************************
+ *
  * Module Initialization
  *
  */
Index: pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/signature/signature.cpp
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/shiboken2/libshiboken/signature/signature.cpp
+++ pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/signature/signature.cpp
@@ -482,7 +482,7 @@ static PyObject *adjustFuncName(const ch
 
     // 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;
Index: pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/signature/signature_helper.cpp
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/shiboken2/libshiboken/signature/signature_helper.cpp
+++ pyside-setup-opensource-src-5.15.12/sources/shiboken2/libshiboken/signature/signature_helper.cpp
@@ -105,7 +105,8 @@ int add_more_getsets(PyTypeObject *type,
      */
     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
      * 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)
Index: pyside-setup-opensource-src-5.15.12/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
+++ pyside-setup-opensource-src-5.15.12/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
@@ -113,6 +113,12 @@ def seterror_argument(args, func_name, i
             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())
Index: pyside-setup-opensource-src-5.15.12/sources/shiboken2/tests/samplebinding/enum_test.py
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/shiboken2/tests/samplebinding/enum_test.py
+++ pyside-setup-opensource-src-5.15.12/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.'''
Index: pyside-setup-opensource-src-5.15.12/sources/pyside2/PySide2/support/generate_pyi.py
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/pyside2/PySide2/support/generate_pyi.py
+++ pyside-setup-opensource-src-5.15.12/sources/pyside2/PySide2/support/generate_pyi.py
@@ -116,7 +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
Index: pyside-setup-opensource-src-5.15.12/build_scripts/config.py
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/build_scripts/config.py
+++ pyside-setup-opensource-src-5.15.12/build_scripts/config.py
@@ -94,7 +94,9 @@ 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',
+            'Programming Language :: Python :: 3.13'
         ]
 
         self.setup_script_dir = None
Index: pyside-setup-opensource-src-5.15.12/sources/shiboken2/tests/otherbinding/module_reload_test.py
===================================================================
--- pyside-setup-opensource-src-5.15.12.orig/sources/shiboken2/tests/otherbinding/module_reload_test.py
+++ pyside-setup-opensource-src-5.15.12/sources/shiboken2/tests/otherbinding/module_reload_test.py
@@ -41,7 +41,8 @@ init_paths()
 from py3kcompat import IS_PY3K
 
 if IS_PY3K:
-    from imp import reload
+    # available from 3.1
+    from importlib import reload
 
 orig_path = os.path.join(os.path.dirname(__file__))
 workdir = os.getcwd()
openSUSE Build Service is sponsored by