https://github.com/python/cpython/commit/7b811d0562a0bf7433165785f1549ac199610f8b
commit: 7b811d0562a0bf7433165785f1549ac199610f8b
branch: main
author: Sam Gross <[email protected]>
committer: encukou <[email protected]>
date: 2024-12-19T16:17:15+01:00
summary:
gh-128008: Add `PyWeakref_IsDead()` (GH-128009)
The `PyWeakref_IsDead()` function tests if a weak reference is dead
without any side effects. Although you can also detect if a weak
reference is dead using `PyWeakref_GetRef()`, that function returns a
strong reference that must be `Py_DECREF()`'d, which can introduce side
effects if the last reference is concurrently dropped (at least in the
free threading build).
files:
A Misc/NEWS.d/next/C_API/2024-12-16-21-59-06.gh-issue-128008.fa9Jt0.rst
M Doc/c-api/weakref.rst
M Include/cpython/weakrefobject.h
M Modules/_testcapimodule.c
M Objects/weakrefobject.c
diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst
index 8f233e16fb17cf..c3c6cf413dcef5 100644
--- a/Doc/c-api/weakref.rst
+++ b/Doc/c-api/weakref.rst
@@ -88,6 +88,15 @@ as much as it can.
Use :c:func:`PyWeakref_GetRef` instead.
+.. c:function:: int PyWeakref_IsDead(PyObject *ref)
+
+ Test if the weak reference *ref* is dead. Returns 1 if the reference is
+ dead, 0 if it is alive, and -1 with an error set if *ref* is not a weak
+ reference object.
+
+ .. versionadded:: 3.14
+
+
.. c:function:: void PyObject_ClearWeakRefs(PyObject *object)
This function is called by the :c:member:`~PyTypeObject.tp_dealloc` handler
diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h
index 9aa1a92c413fe9..da8e77cddaca63 100644
--- a/Include/cpython/weakrefobject.h
+++ b/Include/cpython/weakrefobject.h
@@ -45,6 +45,9 @@ PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);
#define _PyWeakref_CAST(op) \
(assert(PyWeakref_Check(op)), _Py_CAST(PyWeakReference*, (op)))
+// Test if a weak reference is dead.
+PyAPI_FUNC(int) PyWeakref_IsDead(PyObject *ref);
+
Py_DEPRECATED(3.13) static inline PyObject* PyWeakref_GET_OBJECT(PyObject
*ref_obj)
{
PyWeakReference *ref = _PyWeakref_CAST(ref_obj);
diff --git
a/Misc/NEWS.d/next/C_API/2024-12-16-21-59-06.gh-issue-128008.fa9Jt0.rst
b/Misc/NEWS.d/next/C_API/2024-12-16-21-59-06.gh-issue-128008.fa9Jt0.rst
new file mode 100644
index 00000000000000..2349eccac8fedc
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2024-12-16-21-59-06.gh-issue-128008.fa9Jt0.rst
@@ -0,0 +1,2 @@
+Add :c:func:`PyWeakref_IsDead` function, which tests if a weak reference is
+dead.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 8d86b535effb9a..f737250ac29d57 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3144,6 +3144,7 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject
*Py_UNUSED(args))
PyObject *ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(weakref, &ref) == 1);
assert(ref == obj);
+ assert(!PyWeakref_IsDead(weakref));
assert(Py_REFCNT(obj) == (refcnt + 1));
Py_DECREF(ref);
@@ -3159,6 +3160,8 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject
*Py_UNUSED(args))
assert(Py_REFCNT(obj) == 1);
Py_DECREF(obj);
+ assert(PyWeakref_IsDead(weakref));
+
// test PyWeakref_GET_OBJECT(), reference is dead
assert(PyWeakref_GET_OBJECT(weakref) == Py_None);
@@ -3181,6 +3184,12 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject
*Py_UNUSED(args))
PyErr_Clear();
assert(ref == NULL);
+ // test PyWeakRef_IsDead(), invalid type
+ assert(!PyErr_Occurred());
+ assert(PyWeakref_IsDead(invalid_weakref) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_TypeError));
+ PyErr_Clear();
+
// test PyWeakref_GetObject(), invalid type
assert(PyWeakref_GetObject(invalid_weakref) == NULL);
assert(PyErr_ExceptionMatches(PyExc_SystemError));
@@ -3193,6 +3202,11 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject
*Py_UNUSED(args))
assert(ref == NULL);
PyErr_Clear();
+ // test PyWeakref_IsDead(NULL)
+ assert(PyWeakref_IsDead(NULL) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_SystemError));
+ PyErr_Clear();
+
// test PyWeakref_GetObject(NULL)
assert(PyWeakref_GetObject(NULL) == NULL);
assert(PyErr_ExceptionMatches(PyExc_SystemError));
diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c
index 9e3da1c3394d5b..0ee64ed70a63cd 100644
--- a/Objects/weakrefobject.c
+++ b/Objects/weakrefobject.c
@@ -932,6 +932,19 @@ PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
return (PyObject *)get_or_create_weakref(type, ob, callback);
}
+int
+PyWeakref_IsDead(PyObject *ref)
+{
+ if (ref == NULL) {
+ PyErr_BadInternalCall();
+ return -1;
+ }
+ if (!PyWeakref_Check(ref)) {
+ PyErr_Format(PyExc_TypeError, "expected a weakref, got %T", ref);
+ return -1;
+ }
+ return _PyWeakref_IS_DEAD(ref);
+}
int
PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]