pyqt5: FTBFS building against python 3.15

Maximiliano Curia <[email protected]>
Newsgroups gmane.linux.debian.devel.python
Message-ID <[email protected]>
Package: src:pyqt5
Version: 5.15.11+dfsg-5
User: [email protected]
Usertags: python3.15
Tags: patch

Hi!

While rebuilding the python related packages against the python version
3.15rc1 we found that pyqt5 fails to build from source[1]. This is due
to the removal of PyWeakref_GetObject which was deprecated in python
3.13. I'm attaching a patch that's almost identical to the one needed
for pyqt6.

Please consider applying this or a similar patch in your next upload.

Happy hacking,

[1]: https://debusine.debian.net/debian/r-python-python3.15/work-request/1017822/
-- 
"Can you imagine what I would do if I could do all I can?" -- Sun Tzu
Saludos /\/\ /\ >< `/
python3.15.patch (text/x-diff, 3.9 KB)
Description: Fix build against Python 3.15 by using PyWeakref_GetRef
 PyWeakref_GetObject was deprecated in Python 3.13 and removed in Python 3.15.
 Replace its usage with PyWeakref_GetRef, properly handling strong references
 and providing a compatibility fallback for older Python versions and limited API.
Author: Maximiliano Curia <[email protected]>
Forwarded: no
Last-Update: 2026-08-19

Index: pyqt5/qpy/QtCore/qpycore_pyqtslot.cpp
===================================================================
--- pyqt5.orig/qpy/QtCore/qpycore_pyqtslot.cpp
+++ pyqt5/qpy/QtCore/qpycore_pyqtslot.cpp
@@ -24,6 +24,40 @@
 #include "qpycore_pyqtslot.h"
 
 
+#if PY_VERSION_HEX < 0x030D0000
+static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
+{
+    PyObject *obj;
+
+    if (ref != NULL && !PyWeakref_Check(ref))
+    {
+        *pobj = NULL;
+        PyErr_SetString(PyExc_TypeError, "expected a weakref");
+        return -1;
+    }
+
+    obj = PyWeakref_GetObject(ref);
+    if (obj == NULL)
+    {
+        *pobj = NULL;
+        return -1;
+    }
+
+    if (obj == Py_None)
+    {
+        *pobj = NULL;
+        return 0;
+    }
+
+    Py_INCREF(obj);
+    *pobj = obj;
+    return 1;
+}
+#elif defined(Py_LIMITED_API) && Py_LIMITED_API < 0x030D0000
+extern "C" PyAPI_FUNC(int) PyWeakref_GetRef(PyObject *ref, PyObject **pobj);
+#endif
+
+
 // Create the slot for an unbound method.
 PyQtSlot::PyQtSlot(PyObject *method, PyObject *type,
         const Chimera::Signature *slot_signature)
@@ -54,6 +88,8 @@ PyQtSlot::PyQtSlot(PyObject *callable, c
 
         // Try and create a weak reference to the instance object.
         mself_wr = PyWeakref_NewRef(mself, 0);
+        if (!mself_wr)
+            PyErr_Clear();
     }
     else
     {
@@ -100,9 +136,11 @@ PyQtSlot::Result PyQtSlot::invoke(void *
     }
     else
     {
+        PyObject *self_ref = 0;
+
         // Use the value we have if one wasn't supplied.
         if (!self)
-            self = instance();
+            self = self_ref = instance();
 
         // If self is NULL then we didn't have a method in the first place.
         // Instead we had a callable that has been cleared during garbage
@@ -112,12 +150,18 @@ PyQtSlot::Result PyQtSlot::invoke(void *
 
         // See if the instance has gone (which isn't an error).
         if (self == Py_None)
+        {
+            Py_XDECREF(self_ref);
             return PyQtSlot::Ignored;
+        }
 
         // If the receiver wraps a C++ object then ignore the call if it no
         // longer exists.
         if (!no_receiver_check && PyObject_TypeCheck(self, sipSimpleWrapper_Type) && !sipGetAddress((sipSimpleWrapper *)self))
+        {
+            Py_XDECREF(self_ref);
             return PyQtSlot::Ignored;
+        }
 
         sipMethodDef callable_m;
 
@@ -128,6 +172,8 @@ PyQtSlot::Result PyQtSlot::invoke(void *
 #endif
 
         callable = sipFromMethod(&callable_m);
+
+        Py_XDECREF(self_ref);
     }
 
     // Convert the C++ arguments to Python objects.
@@ -188,12 +234,17 @@ bool PyQtSlot::operator==(PyObject *call
         if (other)
             return false;
 
-        return (mfunc == callable_m.pm_function
-                && instance() == callable_m.pm_self
+        PyObject *self = instance();
+        bool match = (mfunc == callable_m.pm_function
+                && self == callable_m.pm_self
 #if PY_MAJOR_VERSION < 3
                 && mclass == callable_m.pm_class
 #endif
                 );
+
+        Py_XDECREF(self);
+
+        return match;
     }
 
     if (!other)
@@ -219,8 +270,19 @@ PyObject *PyQtSlot::instance() const
 {
     // Use the weak reference if possible.
     if (mself_wr)
-        return PyWeakref_GetObject(mself_wr);
+    {
+        PyObject *obj = 0;
+
+        if (PyWeakref_GetRef(mself_wr, &obj) < 0)
+        {
+            PyErr_Clear();
+            return 0;
+        }
+
+        return obj;
+    }
 
+    Py_XINCREF(mself);
     return mself;
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.