From 6126e76159956ab4e1828fdf9cde08205ffe51ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 12:40:00 +0200
Subject: [PATCH 01/13] remove `PyWeakref_GetObject` and `PyWeakref_GET_OBJECT`
---
Doc/c-api/weakref.rst | 24 -----------------
Doc/data/refcounts.dat | 6 -----
Doc/data/stable_abi.dat | 1 -
.../c-api-pending-removal-in-3.15.rst | 4 ---
Doc/howto/free-threading-extensions.rst | 4 ---
Doc/whatsnew/3.11.rst | 2 +-
Doc/whatsnew/3.13.rst | 6 ++---
Doc/whatsnew/3.15.rst | 2 ++
Include/cpython/weakrefobject.h | 17 ------------
Include/weakrefobject.h | 1 -
Lib/test/test_stable_abi_ctypes.py | 1 -
Misc/NEWS.d/3.11.0a2.rst | 2 +-
Misc/NEWS.d/3.13.0a1.rst | 6 ++---
...-05-08-12-40-59.gh-issue-133644.FNexLJ.rst | 3 +++
Misc/stable_abi.toml | 2 --
Modules/_testcapimodule.c | 27 -------------------
Objects/weakrefobject.c | 15 -----------
PC/python3dll.c | 1 -
18 files changed, 13 insertions(+), 111 deletions(-)
create mode 100644 Misc/NEWS.d/next/C_API/2025-05-08-12-40-59.gh-issue-133644.FNexLJ.rst
diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst
index c3c6cf413dcef5..14ec9d951c4a5f 100644
--- a/Doc/c-api/weakref.rst
+++ b/Doc/c-api/weakref.rst
@@ -64,30 +64,6 @@ as much as it can.
.. versionadded:: 3.13
-.. c:function:: PyObject* PyWeakref_GetObject(PyObject *ref)
-
- Return a :term:`borrowed reference` to the referenced object from a weak
- reference, *ref*. If the referent is no longer live, returns ``Py_None``.
-
- .. note::
-
- This function returns a :term:`borrowed reference` to the referenced object.
- This means that you should always call :c:func:`Py_INCREF` on the object
- except when it cannot be destroyed before the last usage of the borrowed
- reference.
-
- .. deprecated-removed:: 3.13 3.15
- Use :c:func:`PyWeakref_GetRef` instead.
-
-
-.. c:function:: PyObject* PyWeakref_GET_OBJECT(PyObject *ref)
-
- Similar to :c:func:`PyWeakref_GetObject`, but does no error checking.
-
- .. deprecated-removed:: 3.13 3.15
- 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
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index ca99b9e6d37141..d82db3c09d1e60 100644
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -2922,12 +2922,6 @@ PyWeakref_CheckProxy:PyObject*:ob:0:
PyWeakref_CheckRef:int:::
PyWeakref_CheckRef:PyObject*:ob:0:
-PyWeakref_GET_OBJECT:PyObject*::0:
-PyWeakref_GET_OBJECT:PyObject*:ref:0:
-
-PyWeakref_GetObject:PyObject*::0:
-PyWeakref_GetObject:PyObject*:ref:0:
-
PyWeakref_GetRef:int:::
PyWeakref_GetRef:PyObject*:ref:0:
PyWeakref_GetRef:PyObject**:pobj:+1:
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index 3d68487d07baf2..572a6b60e1daad 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -829,7 +829,6 @@ member,PyVarObject.ob_size,3.2,,
func,PyVectorcall_Call,3.12,,
func,PyVectorcall_NARGS,3.12,,
type,PyWeakReference,3.2,,opaque
-func,PyWeakref_GetObject,3.2,,
func,PyWeakref_GetRef,3.13,,
func,PyWeakref_NewProxy,3.2,,
func,PyWeakref_NewRef,3.2,,
diff --git a/Doc/deprecations/c-api-pending-removal-in-3.15.rst b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
index a5cc8f1d5b3475..0a853832c4db05 100644
--- a/Doc/deprecations/c-api-pending-removal-in-3.15.rst
+++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
@@ -4,10 +4,6 @@ Pending removal in Python 3.15
* The bundled copy of ``libmpdecimal``.
* The :c:func:`PyImport_ImportModuleNoBlock`:
Use :c:func:`PyImport_ImportModule` instead.
-* :c:func:`PyWeakref_GetObject` and :c:func:`PyWeakref_GET_OBJECT`:
- Use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project
- `__ can be used to get
- :c:func:`PyWeakref_GetRef` on Python 3.12 and older.
* :c:type:`Py_UNICODE` type and the :c:macro:`!Py_UNICODE_WIDE` macro:
Use :c:type:`wchar_t` instead.
* :c:func:`!PyUnicode_AsDecodedObject`:
diff --git a/Doc/howto/free-threading-extensions.rst b/Doc/howto/free-threading-extensions.rst
index 3f6ee517050bd8..87db6bcadcb438 100644
--- a/Doc/howto/free-threading-extensions.rst
+++ b/Doc/howto/free-threading-extensions.rst
@@ -163,10 +163,6 @@ that return :term:`strong references `.
+-----------------------------------+-----------------------------------+
| :c:func:`PyDict_Next` | none (see :ref:`PyDict_Next`) |
+-----------------------------------+-----------------------------------+
-| :c:func:`PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` |
-+-----------------------------------+-----------------------------------+
-| :c:func:`PyWeakref_GET_OBJECT` | :c:func:`PyWeakref_GetRef` |
-+-----------------------------------+-----------------------------------+
| :c:func:`PyImport_AddModule` | :c:func:`PyImport_AddModuleRef` |
+-----------------------------------+-----------------------------------+
| :c:func:`PyCell_GET` | :c:func:`PyCell_Get` |
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 2dd205dd2b8831..a095d887352127 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -2673,7 +2673,7 @@ Removed
(Contributed by Victor Stinner in :issue:`45474`.)
-* Exclude :c:func:`PyWeakref_GET_OBJECT` from the limited C API. It never
+* Exclude :c:func:`!PyWeakref_GET_OBJECT` from the limited C API. It never
worked since the :c:type:`!PyWeakReference` structure is opaque in the
limited C API.
(Contributed by Victor Stinner in :issue:`35134`.)
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index e20e49325c01d5..8ca1ae4fd64f33 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -2231,7 +2231,7 @@ New Features
(Contributed by Serhiy Storchaka in :gh:`110289`.)
* Add the :c:func:`PyWeakref_GetRef` function
- as an alternative to :c:func:`PyWeakref_GetObject`
+ as an alternative to :c:func:`!PyWeakref_GetObject`
that returns a :term:`strong reference`
or ``NULL`` if the referent is no longer live.
(Contributed by Victor Stinner in :gh:`105927`.)
@@ -2516,8 +2516,8 @@ Deprecated C APIs
are just aliases to :c:type:`!wchar_t`.
(Contributed by Victor Stinner in :gh:`105156`.)
-* Deprecate the :c:func:`PyWeakref_GetObject` and
- :c:func:`PyWeakref_GET_OBJECT` functions,
+* Deprecate the :c:func:`!PyWeakref_GetObject` and
+ :c:func:`!PyWeakref_GET_OBJECT` functions,
which return a :term:`borrowed reference`.
Replace them with the new :c:func:`PyWeakref_GetRef` function,
which returns a :term:`strong reference`.
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 5e9922069aa42c..09109d271792c4 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -155,3 +155,5 @@ Deprecated C APIs
Removed C APIs
--------------
+* :c:func:`!PyWeakref_GetObject` and :c:macro:`!PyWeakref_GET_OBJECT`:
+ use :c:func:`PyWeakref_GetRef` instead.
diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h
index da8e77cddaca63..e0711407cee470 100644
--- a/Include/cpython/weakrefobject.h
+++ b/Include/cpython/weakrefobject.h
@@ -47,20 +47,3 @@ PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);
// 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);
- PyObject *obj = ref->wr_object;
- // Explanation for the Py_REFCNT() check: when a weakref's target is part
- // of a long chain of deallocations which triggers the trashcan mechanism,
- // clearing the weakrefs can be delayed long after the target's refcount
- // has dropped to zero. In the meantime, code accessing the weakref will
- // be able to "see" the target object even though it is supposed to be
- // unreachable. See issue gh-60806.
- if (Py_REFCNT(obj) > 0) {
- return obj;
- }
- return Py_None;
-}
-#define PyWeakref_GET_OBJECT(ref) PyWeakref_GET_OBJECT(_PyObject_CAST(ref))
diff --git a/Include/weakrefobject.h b/Include/weakrefobject.h
index a6e71eb178b124..17fac62961c0fb 100644
--- a/Include/weakrefobject.h
+++ b/Include/weakrefobject.h
@@ -27,7 +27,6 @@ PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob,
PyObject *callback);
PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob,
PyObject *callback);
-Py_DEPRECATED(3.13) PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref);
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030D0000
PyAPI_FUNC(int) PyWeakref_GetRef(PyObject *ref, PyObject **pobj);
diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py
index 1e6f69d49e9335..9b4493bc05493a 100644
--- a/Lib/test/test_stable_abi_ctypes.py
+++ b/Lib/test/test_stable_abi_ctypes.py
@@ -849,7 +849,6 @@ def test_windows_feature_macros(self):
"PyUnicode_WriteChar",
"PyVectorcall_Call",
"PyVectorcall_NARGS",
- "PyWeakref_GetObject",
"PyWeakref_GetRef",
"PyWeakref_NewProxy",
"PyWeakref_NewRef",
diff --git a/Misc/NEWS.d/3.11.0a2.rst b/Misc/NEWS.d/3.11.0a2.rst
index 48cf2c1e428d87..12e03b46db0b3f 100644
--- a/Misc/NEWS.d/3.11.0a2.rst
+++ b/Misc/NEWS.d/3.11.0a2.rst
@@ -1188,7 +1188,7 @@ context objects can now be disabled.
.. nonce: Z0Zk_m
.. section: C API
-Exclude :c:func:`PyWeakref_GET_OBJECT` from the limited C API. It never
+Exclude :c:func:`!PyWeakref_GET_OBJECT` from the limited C API. It never
worked since the :c:type:`!PyWeakReference` structure is opaque in the
limited C API.
diff --git a/Misc/NEWS.d/3.13.0a1.rst b/Misc/NEWS.d/3.13.0a1.rst
index 91e9fee7e37437..fc5c7d89da8ca5 100644
--- a/Misc/NEWS.d/3.13.0a1.rst
+++ b/Misc/NEWS.d/3.13.0a1.rst
@@ -6458,8 +6458,8 @@ Victor Stinner.
.. nonce: GRxZtI
.. section: C API
-Deprecate the :c:func:`PyWeakref_GetObject` and
-:c:func:`PyWeakref_GET_OBJECT` functions: use the new
+Deprecate the :c:func:`!PyWeakref_GetObject` and
+:c:func:`!PyWeakref_GET_OBJECT` functions: use the new
:c:func:`PyWeakref_GetRef` function instead. Patch by Victor Stinner.
..
@@ -6470,7 +6470,7 @@ Deprecate the :c:func:`PyWeakref_GetObject` and
.. section: C API
Add :c:func:`PyWeakref_GetRef` function: similar to
-:c:func:`PyWeakref_GetObject` but returns a :term:`strong reference`, or
+:c:func:`!PyWeakref_GetObject` but returns a :term:`strong reference`, or
``NULL`` if the referent is no longer live. Patch by Victor Stinner.
..
diff --git a/Misc/NEWS.d/next/C_API/2025-05-08-12-40-59.gh-issue-133644.FNexLJ.rst b/Misc/NEWS.d/next/C_API/2025-05-08-12-40-59.gh-issue-133644.FNexLJ.rst
new file mode 100644
index 00000000000000..71f1eaa5290d46
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2025-05-08-12-40-59.gh-issue-133644.FNexLJ.rst
@@ -0,0 +1,3 @@
+Remove deprecated function :c:func:`!PyWeakref_GetObject` and macro
+:c:macro:`!PyWeakref_GET_OBJECT`. Use :c:func:`PyWeakref_GetRef` instead.
+Patch by Bénédikt Tran.
diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml
index d3e1f0db057023..1c01000568755e 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -1592,8 +1592,6 @@
added = '3.2'
[data.PyUnicode_Type]
added = '3.2'
-[function.PyWeakref_GetObject]
- added = '3.2'
[function.PyWeakref_NewProxy]
added = '3.2'
[function.PyWeakref_NewRef]
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 3aa6e4c9e43a26..3823a3479376a2 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2207,10 +2207,6 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
static PyObject *
test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
- // Ignore PyWeakref_GetObject() deprecation, we test it on purpose
- _Py_COMP_DIAG_PUSH
- _Py_COMP_DIAG_IGNORE_DEPR_DECLS
-
// Create a new heap type, create an instance of this type, and delete the
// type. This object supports weak references.
PyObject *new_type = PyObject_CallFunction((PyObject*)&PyType_Type,
@@ -2246,23 +2242,12 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
assert(Py_REFCNT(obj) == (refcnt + 1));
Py_DECREF(ref);
- // test PyWeakref_GetObject(), reference is alive
- ref = PyWeakref_GetObject(weakref); // borrowed ref
- assert(ref == obj);
-
- // test PyWeakref_GET_OBJECT(), reference is alive
- ref = PyWeakref_GET_OBJECT(weakref); // borrowed ref
- assert(ref == obj);
-
// delete the referenced object: clear the weakref
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);
-
// test PyWeakref_GetRef(), reference is dead
ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(weakref, &ref) == 0);
@@ -2288,11 +2273,6 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
assert(PyErr_ExceptionMatches(PyExc_TypeError));
PyErr_Clear();
- // test PyWeakref_GetObject(), invalid type
- assert(PyWeakref_GetObject(invalid_weakref) == NULL);
- assert(PyErr_ExceptionMatches(PyExc_SystemError));
- PyErr_Clear();
-
// test PyWeakref_GetRef(NULL)
ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(NULL, &ref) == -1);
@@ -2305,16 +2285,9 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
assert(PyErr_ExceptionMatches(PyExc_SystemError));
PyErr_Clear();
- // test PyWeakref_GetObject(NULL)
- assert(PyWeakref_GetObject(NULL) == NULL);
- assert(PyErr_ExceptionMatches(PyExc_SystemError));
- PyErr_Clear();
-
Py_DECREF(weakref);
Py_RETURN_NONE;
-
- _Py_COMP_DIAG_POP
}
struct simpletracer_data {
diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c
index bd4c4ac9b3475a..aa409f19da1eac 100644
--- a/Objects/weakrefobject.c
+++ b/Objects/weakrefobject.c
@@ -964,21 +964,6 @@ PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
}
-PyObject *
-PyWeakref_GetObject(PyObject *ref)
-{
- if (ref == NULL || !PyWeakref_Check(ref)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- PyObject *obj = _PyWeakref_GET_REF(ref);
- if (obj == NULL) {
- return Py_None;
- }
- Py_DECREF(obj);
- return obj; // borrowed reference
-}
-
/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
* handle_weakrefs().
*/
diff --git a/PC/python3dll.c b/PC/python3dll.c
index f0c578e11c643b..cfb317646221ac 100755
--- a/PC/python3dll.c
+++ b/PC/python3dll.c
@@ -786,7 +786,6 @@ EXPORT_FUNC(PyUnicodeTranslateError_SetReason)
EXPORT_FUNC(PyUnicodeTranslateError_SetStart)
EXPORT_FUNC(PyVectorcall_Call)
EXPORT_FUNC(PyVectorcall_NARGS)
-EXPORT_FUNC(PyWeakref_GetObject)
EXPORT_FUNC(PyWeakref_GetRef)
EXPORT_FUNC(PyWeakref_NewProxy)
EXPORT_FUNC(PyWeakref_NewRef)
From ab08a8e22f19f97d7928989269b0eb7452a3e168 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 13:43:03 +0200
Subject: [PATCH 02/13] restore file
---
Doc/deprecations/c-api-pending-removal-in-3.15.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Doc/deprecations/c-api-pending-removal-in-3.15.rst b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
index 0a853832c4db05..6e58f269baeec4 100644
--- a/Doc/deprecations/c-api-pending-removal-in-3.15.rst
+++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
@@ -4,6 +4,10 @@ Pending removal in Python 3.15
* The bundled copy of ``libmpdecimal``.
* The :c:func:`PyImport_ImportModuleNoBlock`:
Use :c:func:`PyImport_ImportModule` instead.
+* :c:func:`!PyWeakref_GetObject` and :c:func:`!PyWeakref_GET_OBJECT`:
+ Use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project
+ `__ can be used to get
+ :c:func:`PyWeakref_GetRef` on Python 3.12 and older.
* :c:type:`Py_UNICODE` type and the :c:macro:`!Py_UNICODE_WIDE` macro:
Use :c:type:`wchar_t` instead.
* :c:func:`!PyUnicode_AsDecodedObject`:
From 266c6f97d578de37eeba816a24ad687a477cdc89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:11:51 +0200
Subject: [PATCH 03/13] restore stable ABI symbols
---
Doc/data/stable_abi.dat | 1 +
Include/cpython/weakrefobject.h | 18 +++++++++++++++++
Lib/test/test_stable_abi_ctypes.py | 1 +
Misc/stable_abi.toml | 2 ++
Modules/_testcapimodule.c | 31 ++++++++++++++++++++++++++++++
Objects/weakrefobject.c | 16 +++++++++++++++
PC/python3dll.c | 1 +
7 files changed, 70 insertions(+)
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index 572a6b60e1daad..3d68487d07baf2 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -829,6 +829,7 @@ member,PyVarObject.ob_size,3.2,,
func,PyVectorcall_Call,3.12,,
func,PyVectorcall_NARGS,3.12,,
type,PyWeakReference,3.2,,opaque
+func,PyWeakref_GetObject,3.2,,
func,PyWeakref_GetRef,3.13,,
func,PyWeakref_NewProxy,3.2,,
func,PyWeakref_NewRef,3.2,,
diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h
index e0711407cee470..b848a81521c4b9 100644
--- a/Include/cpython/weakrefobject.h
+++ b/Include/cpython/weakrefobject.h
@@ -47,3 +47,21 @@ PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);
// Test if a weak reference is dead.
PyAPI_FUNC(int) PyWeakref_IsDead(PyObject *ref);
+
+/* removed in 3.15, kept for stable ABI compatibility */
+Py_DEPRECATED(3.13) static inline PyObject* PyWeakref_GET_OBJECT(PyObject *ref_obj)
+{
+ PyWeakReference *ref = _PyWeakref_CAST(ref_obj);
+ PyObject *obj = ref->wr_object;
+ // Explanation for the Py_REFCNT() check: when a weakref's target is part
+ // of a long chain of deallocations which triggers the trashcan mechanism,
+ // clearing the weakrefs can be delayed long after the target's refcount
+ // has dropped to zero. In the meantime, code accessing the weakref will
+ // be able to "see" the target object even though it is supposed to be
+ // unreachable. See issue gh-60806.
+ if (Py_REFCNT(obj) > 0) {
+ return obj;
+ }
+ return Py_None;
+}
+#define PyWeakref_GET_OBJECT(ref) PyWeakref_GET_OBJECT(_PyObject_CAST(ref))
diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py
index 9b4493bc05493a..1e6f69d49e9335 100644
--- a/Lib/test/test_stable_abi_ctypes.py
+++ b/Lib/test/test_stable_abi_ctypes.py
@@ -849,6 +849,7 @@ def test_windows_feature_macros(self):
"PyUnicode_WriteChar",
"PyVectorcall_Call",
"PyVectorcall_NARGS",
+ "PyWeakref_GetObject",
"PyWeakref_GetRef",
"PyWeakref_NewProxy",
"PyWeakref_NewRef",
diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml
index 1c01000568755e..d3e1f0db057023 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -1592,6 +1592,8 @@
added = '3.2'
[data.PyUnicode_Type]
added = '3.2'
+[function.PyWeakref_GetObject]
+ added = '3.2'
[function.PyWeakref_NewProxy]
added = '3.2'
[function.PyWeakref_NewRef]
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 3823a3479376a2..95ba2e8238eabe 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2207,6 +2207,8 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
static PyObject *
test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
+ extern PyObject *PyWeakref_GetObject(PyObject *);
+
// Create a new heap type, create an instance of this type, and delete the
// type. This object supports weak references.
PyObject *new_type = PyObject_CallFunction((PyObject*)&PyType_Type,
@@ -2242,12 +2244,29 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
assert(Py_REFCNT(obj) == (refcnt + 1));
Py_DECREF(ref);
+ // test PyWeakref_GetObject(), reference is alive
+ ref = PyWeakref_GetObject(weakref); // borrowed ref
+ assert(ref == obj);
+
+ // test PyWeakref_GET_OBJECT(), reference is alive
+ _Py_COMP_DIAG_PUSH
+ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
+ ref = PyWeakref_GET_OBJECT(weakref); // borrowed ref
+ _Py_COMP_DIAG_POP
+ assert(ref == obj);
+
// delete the referenced object: clear the weakref
assert(Py_REFCNT(obj) == 1);
Py_DECREF(obj);
assert(PyWeakref_IsDead(weakref));
+ // test PyWeakref_GET_OBJECT(), reference is dead
+ _Py_COMP_DIAG_PUSH
+ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
+ assert(PyWeakref_GET_OBJECT(weakref) == Py_None);
+ _Py_COMP_DIAG_POP
+
// test PyWeakref_GetRef(), reference is dead
ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(weakref, &ref) == 0);
@@ -2273,6 +2292,11 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
assert(PyErr_ExceptionMatches(PyExc_TypeError));
PyErr_Clear();
+ // test PyWeakref_GetObject(), invalid type
+ assert(PyWeakref_GetObject(invalid_weakref) == NULL);
+ assert(PyErr_ExceptionMatches(PyExc_SystemError));
+ PyErr_Clear();
+
// test PyWeakref_GetRef(NULL)
ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(NULL, &ref) == -1);
@@ -2285,9 +2309,16 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
assert(PyErr_ExceptionMatches(PyExc_SystemError));
PyErr_Clear();
+ // test PyWeakref_GetObject(NULL)
+ assert(PyWeakref_GetObject(NULL) == NULL);
+ assert(PyErr_ExceptionMatches(PyExc_SystemError));
+ PyErr_Clear();
+
Py_DECREF(weakref);
Py_RETURN_NONE;
+
+ _Py_COMP_DIAG_POP
}
struct simpletracer_data {
diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c
index aa409f19da1eac..61fa3ddad0bfd8 100644
--- a/Objects/weakrefobject.c
+++ b/Objects/weakrefobject.c
@@ -964,6 +964,22 @@ PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
}
+/* removed in 3.15, but kept for stable ABI compatibility */
+PyAPI_FUNC(PyObject *)
+PyWeakref_GetObject(PyObject *ref)
+{
+ if (ref == NULL || !PyWeakref_Check(ref)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ PyObject *obj = _PyWeakref_GET_REF(ref);
+ if (obj == NULL) {
+ return Py_None;
+ }
+ Py_DECREF(obj);
+ return obj; // borrowed reference
+}
+
/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
* handle_weakrefs().
*/
diff --git a/PC/python3dll.c b/PC/python3dll.c
index cfb317646221ac..f0c578e11c643b 100755
--- a/PC/python3dll.c
+++ b/PC/python3dll.c
@@ -786,6 +786,7 @@ EXPORT_FUNC(PyUnicodeTranslateError_SetReason)
EXPORT_FUNC(PyUnicodeTranslateError_SetStart)
EXPORT_FUNC(PyVectorcall_Call)
EXPORT_FUNC(PyVectorcall_NARGS)
+EXPORT_FUNC(PyWeakref_GetObject)
EXPORT_FUNC(PyWeakref_GetRef)
EXPORT_FUNC(PyWeakref_NewProxy)
EXPORT_FUNC(PyWeakref_NewRef)
From 36de136ed76ab6dfc2d0c6a65f8f235649acc155 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:33:54 +0200
Subject: [PATCH 04/13] update stable abi files
---
Doc/data/stable_abi.dat | 1 -
Misc/stable_abi.toml | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index 3d68487d07baf2..572a6b60e1daad 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -829,7 +829,6 @@ member,PyVarObject.ob_size,3.2,,
func,PyVectorcall_Call,3.12,,
func,PyVectorcall_NARGS,3.12,,
type,PyWeakReference,3.2,,opaque
-func,PyWeakref_GetObject,3.2,,
func,PyWeakref_GetRef,3.13,,
func,PyWeakref_NewProxy,3.2,,
func,PyWeakref_NewRef,3.2,,
diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml
index d3e1f0db057023..74d0d4e0ee740c 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -1594,6 +1594,7 @@
added = '3.2'
[function.PyWeakref_GetObject]
added = '3.2'
+ abi_only = true
[function.PyWeakref_NewProxy]
added = '3.2'
[function.PyWeakref_NewRef]
From 121c51fa89c4bcdb4057c8feeaad2a170336c489 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:36:24 +0200
Subject: [PATCH 05/13] update ABI imports
---
Modules/_testcapimodule.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 95ba2e8238eabe..aa12d11f9ef3cb 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2207,7 +2207,8 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
static PyObject *
test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
- extern PyObject *PyWeakref_GetObject(PyObject *);
+ // Get the function from the stable ABI.
+ PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *);
// Create a new heap type, create an instance of this type, and delete the
// type. This object supports weak references.
From b711d04aa521dbc28573be2ba5e0c47c40ce4b76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:38:18 +0200
Subject: [PATCH 06/13] update ABI imports
---
Modules/_testcapimodule.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index aa12d11f9ef3cb..b60a24102df1ac 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2207,7 +2207,7 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
static PyObject *
test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
- // Get the function from the stable ABI.
+ // Get the function (removed in 3.15) from the stable ABI.
PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *);
// Create a new heap type, create an instance of this type, and delete the
From 9a4b77e4793e1f307c70e11538c17bcc8ed6b57f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:42:10 +0200
Subject: [PATCH 07/13] entirely remove `PyWeakRef_GET_OBJECT`
---
Include/cpython/weakrefobject.h | 18 ------------------
Modules/_testcapimodule.c | 13 -------------
2 files changed, 31 deletions(-)
diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h
index b848a81521c4b9..e0711407cee470 100644
--- a/Include/cpython/weakrefobject.h
+++ b/Include/cpython/weakrefobject.h
@@ -47,21 +47,3 @@ PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);
// Test if a weak reference is dead.
PyAPI_FUNC(int) PyWeakref_IsDead(PyObject *ref);
-
-/* removed in 3.15, kept for stable ABI compatibility */
-Py_DEPRECATED(3.13) static inline PyObject* PyWeakref_GET_OBJECT(PyObject *ref_obj)
-{
- PyWeakReference *ref = _PyWeakref_CAST(ref_obj);
- PyObject *obj = ref->wr_object;
- // Explanation for the Py_REFCNT() check: when a weakref's target is part
- // of a long chain of deallocations which triggers the trashcan mechanism,
- // clearing the weakrefs can be delayed long after the target's refcount
- // has dropped to zero. In the meantime, code accessing the weakref will
- // be able to "see" the target object even though it is supposed to be
- // unreachable. See issue gh-60806.
- if (Py_REFCNT(obj) > 0) {
- return obj;
- }
- return Py_None;
-}
-#define PyWeakref_GET_OBJECT(ref) PyWeakref_GET_OBJECT(_PyObject_CAST(ref))
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index b60a24102df1ac..f83ed293eed921 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2249,25 +2249,12 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
ref = PyWeakref_GetObject(weakref); // borrowed ref
assert(ref == obj);
- // test PyWeakref_GET_OBJECT(), reference is alive
- _Py_COMP_DIAG_PUSH
- _Py_COMP_DIAG_IGNORE_DEPR_DECLS
- ref = PyWeakref_GET_OBJECT(weakref); // borrowed ref
- _Py_COMP_DIAG_POP
- assert(ref == obj);
-
// delete the referenced object: clear the weakref
assert(Py_REFCNT(obj) == 1);
Py_DECREF(obj);
assert(PyWeakref_IsDead(weakref));
- // test PyWeakref_GET_OBJECT(), reference is dead
- _Py_COMP_DIAG_PUSH
- _Py_COMP_DIAG_IGNORE_DEPR_DECLS
- assert(PyWeakref_GET_OBJECT(weakref) == Py_None);
- _Py_COMP_DIAG_POP
-
// test PyWeakref_GetRef(), reference is dead
ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(weakref, &ref) == 0);
From b819a753983a02b76bda236117d759dbb2d468c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:44:00 +0200
Subject: [PATCH 08/13] restore table
---
Doc/howto/free-threading-extensions.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Doc/howto/free-threading-extensions.rst b/Doc/howto/free-threading-extensions.rst
index 87db6bcadcb438..3f6ee517050bd8 100644
--- a/Doc/howto/free-threading-extensions.rst
+++ b/Doc/howto/free-threading-extensions.rst
@@ -163,6 +163,10 @@ that return :term:`strong references `.
+-----------------------------------+-----------------------------------+
| :c:func:`PyDict_Next` | none (see :ref:`PyDict_Next`) |
+-----------------------------------+-----------------------------------+
+| :c:func:`PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` |
++-----------------------------------+-----------------------------------+
+| :c:func:`PyWeakref_GET_OBJECT` | :c:func:`PyWeakref_GetRef` |
++-----------------------------------+-----------------------------------+
| :c:func:`PyImport_AddModule` | :c:func:`PyImport_AddModuleRef` |
+-----------------------------------+-----------------------------------+
| :c:func:`PyCell_GET` | :c:func:`PyCell_Get` |
From 03ca635e2f17a17ecbf9dbf9072465f42e2c84c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:58:27 +0200
Subject: [PATCH 09/13] fix docs
---
Doc/howto/free-threading-extensions.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Doc/howto/free-threading-extensions.rst b/Doc/howto/free-threading-extensions.rst
index 3f6ee517050bd8..3e68a2ff35348f 100644
--- a/Doc/howto/free-threading-extensions.rst
+++ b/Doc/howto/free-threading-extensions.rst
@@ -163,9 +163,9 @@ that return :term:`strong references `.
+-----------------------------------+-----------------------------------+
| :c:func:`PyDict_Next` | none (see :ref:`PyDict_Next`) |
+-----------------------------------+-----------------------------------+
-| :c:func:`PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` |
+| :c:func:`!PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` |
+-----------------------------------+-----------------------------------+
-| :c:func:`PyWeakref_GET_OBJECT` | :c:func:`PyWeakref_GetRef` |
+| :c:func:`!PyWeakref_GET_OBJECT` | :c:func:`PyWeakref_GetRef` |
+-----------------------------------+-----------------------------------+
| :c:func:`PyImport_AddModule` | :c:func:`PyImport_AddModuleRef` |
+-----------------------------------+-----------------------------------+
From 55987c32a85011e002b1a2a72db0e879f11e5998 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:59:20 +0200
Subject: [PATCH 10/13] update porting
---
Doc/whatsnew/3.15.rst | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 09109d271792c4..04a3ff8c7a2a99 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -156,4 +156,6 @@ Removed C APIs
--------------
* :c:func:`!PyWeakref_GetObject` and :c:macro:`!PyWeakref_GET_OBJECT`:
- use :c:func:`PyWeakref_GetRef` instead.
+ use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project
+ `__ can be used to get
+ :c:func:`PyWeakref_GetRef` on Python 3.12 and older.
From 94237effd96d2bb85be6d87e2b43cddcae97e6d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 14:59:37 +0200
Subject: [PATCH 11/13] update porting
---
Doc/whatsnew/3.15.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 04a3ff8c7a2a99..25c575c715955d 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -158,4 +158,4 @@ Removed C APIs
* :c:func:`!PyWeakref_GetObject` and :c:macro:`!PyWeakref_GET_OBJECT`:
use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project
`__ can be used to get
- :c:func:`PyWeakref_GetRef` on Python 3.12 and older.
+ :c:func:`!PyWeakref_GetRef` on Python 3.12 and older.
From 5bd4ba31295b004330dfedd53c335dde074b1910 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Thu, 8 May 2025 15:34:27 +0200
Subject: [PATCH 12/13] remove orphan `_Py_COMP_DIAG_POP`
---
Modules/_testcapimodule.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index f83ed293eed921..c113e01234848e 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2305,8 +2305,6 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
Py_DECREF(weakref);
Py_RETURN_NONE;
-
- _Py_COMP_DIAG_POP
}
struct simpletracer_data {
From 0884e0778f8c42f447fa251481639ef5ef665910 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?=
<10796600+picnixz@users.noreply.github.com>
Date: Fri, 9 May 2025 18:07:13 +0200
Subject: [PATCH 13/13] update docs
---
Doc/whatsnew/3.15.rst | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 940872580de7b5..b520242a43b6ce 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -186,9 +186,8 @@ Removed C APIs
of :c:func:`PyImport_ImportModule`.
* :c:func:`!PyWeakref_GetObject` and :c:macro:`!PyWeakref_GET_OBJECT`:
- use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project
- `__ can be used to get
- :c:func:`!PyWeakref_GetRef` on Python 3.12 and older.
+ use :c:func:`PyWeakref_GetRef` instead. The |pythoncapi_compat_project|
+ can be used to get :c:func:`!PyWeakref_GetRef` on Python 3.12 and older.
The following functions are removed in favor of :c:func:`PyConfig_Get`.
The |pythoncapi_compat_project| can be used to get :c:func:`!PyConfig_Get`