mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
gh-105927: Add PyWeakref_GetRef() function (#105932)
Add tests on PyWeakref_NewRef(), PyWeakref_GetObject(), PyWeakref_GET_OBJECT() and PyWeakref_GetRef().
This commit is contained in:
parent
4d140e5e06
commit
9c44656feb
11 changed files with 133 additions and 8 deletions
|
@ -11,20 +11,20 @@ simple reference object, and the second acts as a proxy for the original object
|
||||||
as much as it can.
|
as much as it can.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: int PyWeakref_Check(ob)
|
.. c:function:: int PyWeakref_Check(PyObject *ob)
|
||||||
|
|
||||||
Return true if *ob* is either a reference or proxy object. This function
|
Return non-zero if *ob* is either a reference or proxy object. This function
|
||||||
always succeeds.
|
always succeeds.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: int PyWeakref_CheckRef(ob)
|
.. c:function:: int PyWeakref_CheckRef(PyObject *ob)
|
||||||
|
|
||||||
Return true if *ob* is a reference object. This function always succeeds.
|
Return non-zero if *ob* is a reference object. This function always succeeds.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: int PyWeakref_CheckProxy(ob)
|
.. c:function:: int PyWeakref_CheckProxy(PyObject *ob)
|
||||||
|
|
||||||
Return true if *ob* is a proxy object. This function always succeeds.
|
Return non-zero if *ob* is a proxy object. This function always succeeds.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyWeakref_NewRef(PyObject *ob, PyObject *callback)
|
.. c:function:: PyObject* PyWeakref_NewRef(PyObject *ob, PyObject *callback)
|
||||||
|
@ -51,10 +51,21 @@ as much as it can.
|
||||||
``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
|
``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
|
||||||
|
|
||||||
|
Get a :term:`strong reference` to the referenced object from a weak
|
||||||
|
reference, *ref*, into *\*pobj*.
|
||||||
|
Return 0 on success. Raise an exception and return -1 on error.
|
||||||
|
|
||||||
|
If the referent is no longer live, set *\*pobj* to ``NULL`` and return 0.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyWeakref_GetObject(PyObject *ref)
|
.. c:function:: PyObject* PyWeakref_GetObject(PyObject *ref)
|
||||||
|
|
||||||
Return the referenced object from a weak reference, *ref*. If the referent is
|
Return a :term:`borrowed reference` to the referenced object from a weak
|
||||||
no longer live, returns :const:`Py_None`.
|
reference, *ref*. If the referent is no longer live, returns ``Py_None``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|
|
@ -2813,6 +2813,10 @@ PyWeakref_GET_OBJECT:PyObject*:ref:0:
|
||||||
PyWeakref_GetObject:PyObject*::0:
|
PyWeakref_GetObject:PyObject*::0:
|
||||||
PyWeakref_GetObject:PyObject*:ref:0:
|
PyWeakref_GetObject:PyObject*:ref:0:
|
||||||
|
|
||||||
|
PyWeakref_GetRef:int:::
|
||||||
|
PyWeakref_GetRef:PyObject*:ref:0:
|
||||||
|
PyWeakref_GetRef:PyObject**:pobj:+1:
|
||||||
|
|
||||||
PyWeakref_NewProxy:PyObject*::+1:
|
PyWeakref_NewProxy:PyObject*::+1:
|
||||||
PyWeakref_NewProxy:PyObject*:ob:0:
|
PyWeakref_NewProxy:PyObject*:ob:0:
|
||||||
PyWeakref_NewProxy:PyObject*:callback:0:
|
PyWeakref_NewProxy:PyObject*:callback:0:
|
||||||
|
|
1
Doc/data/stable_abi.dat
generated
1
Doc/data/stable_abi.dat
generated
|
@ -781,6 +781,7 @@ function,PyVectorcall_Call,3.12,,
|
||||||
function,PyVectorcall_NARGS,3.12,,
|
function,PyVectorcall_NARGS,3.12,,
|
||||||
type,PyWeakReference,3.2,,opaque
|
type,PyWeakReference,3.2,,opaque
|
||||||
function,PyWeakref_GetObject,3.2,,
|
function,PyWeakref_GetObject,3.2,,
|
||||||
|
function,PyWeakref_GetRef,3.13,,
|
||||||
function,PyWeakref_NewProxy,3.2,,
|
function,PyWeakref_NewProxy,3.2,,
|
||||||
function,PyWeakref_NewRef,3.2,,
|
function,PyWeakref_NewRef,3.2,,
|
||||||
var,PyWrapperDescr_Type,3.2,,
|
var,PyWrapperDescr_Type,3.2,,
|
||||||
|
|
|
@ -431,6 +431,10 @@ New Features
|
||||||
of a :term:`borrowed reference`.
|
of a :term:`borrowed reference`.
|
||||||
(Contributed by Victor Stinner in :gh:`105922`.)
|
(Contributed by Victor Stinner in :gh:`105922`.)
|
||||||
|
|
||||||
|
* Add :c:func:`PyWeakref_GetRef` function: similar to
|
||||||
|
:c:func:`PyWeakref_GetObject` but returns a :term:`strong reference`, or
|
||||||
|
``NULL`` if the referent is no longer live.
|
||||||
|
(Contributed by Victor Stinner in :gh:`105927`.)
|
||||||
|
|
||||||
Porting to Python 3.13
|
Porting to Python 3.13
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -28,6 +28,7 @@ PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob,
|
||||||
PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob,
|
PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob,
|
||||||
PyObject *callback);
|
PyObject *callback);
|
||||||
PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref);
|
PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref);
|
||||||
|
PyAPI_FUNC(int) PyWeakref_GetRef(PyObject *ref, PyObject **pobj);
|
||||||
|
|
||||||
|
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
|
|
1
Lib/test/test_stable_abi_ctypes.py
generated
1
Lib/test/test_stable_abi_ctypes.py
generated
|
@ -794,6 +794,7 @@ SYMBOL_NAMES = (
|
||||||
"PyVectorcall_Call",
|
"PyVectorcall_Call",
|
||||||
"PyVectorcall_NARGS",
|
"PyVectorcall_NARGS",
|
||||||
"PyWeakref_GetObject",
|
"PyWeakref_GetObject",
|
||||||
|
"PyWeakref_GetRef",
|
||||||
"PyWeakref_NewProxy",
|
"PyWeakref_NewProxy",
|
||||||
"PyWeakref_NewRef",
|
"PyWeakref_NewRef",
|
||||||
"PyWrapperDescr_Type",
|
"PyWrapperDescr_Type",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Add :c:func:`PyWeakref_GetRef` function: similar to
|
||||||
|
:c:func:`PyWeakref_GetObject` but returns a :term:`strong reference`, or
|
||||||
|
``NULL`` if the referent is no longer live. Patch by Victor Stinner.
|
|
@ -2430,3 +2430,5 @@
|
||||||
added = '3.12'
|
added = '3.12'
|
||||||
[function.PyImport_AddModuleRef]
|
[function.PyImport_AddModuleRef]
|
||||||
added = '3.13'
|
added = '3.13'
|
||||||
|
[function.PyWeakref_GetRef]
|
||||||
|
added = '3.13'
|
||||||
|
|
|
@ -3372,6 +3372,84 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
||||||
|
{
|
||||||
|
// 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,
|
||||||
|
"s(){}", "TypeName");
|
||||||
|
if (new_type == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *obj = PyObject_CallNoArgs(new_type);
|
||||||
|
Py_DECREF(new_type);
|
||||||
|
if (obj == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_ssize_t refcnt = Py_REFCNT(obj);
|
||||||
|
|
||||||
|
// test PyWeakref_NewRef(), reference is alive
|
||||||
|
PyObject *weakref = PyWeakref_NewRef(obj, NULL);
|
||||||
|
if (weakref == NULL) {
|
||||||
|
Py_DECREF(obj);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
assert(PyWeakref_Check(weakref));
|
||||||
|
assert(PyWeakref_CheckRefExact(weakref));
|
||||||
|
assert(PyWeakref_CheckRefExact(weakref));
|
||||||
|
assert(Py_REFCNT(obj) == refcnt);
|
||||||
|
|
||||||
|
// test PyWeakref_GetRef(), reference is alive
|
||||||
|
PyObject *ref1;
|
||||||
|
assert(PyWeakref_GetRef(weakref, &ref1) == 0);
|
||||||
|
assert(ref1 == obj);
|
||||||
|
assert(Py_REFCNT(obj) == (refcnt + 1));
|
||||||
|
Py_DECREF(ref1);
|
||||||
|
|
||||||
|
// test PyWeakref_GetObject(), reference is alive
|
||||||
|
PyObject *ref2 = PyWeakref_GetObject(weakref);
|
||||||
|
assert(ref2 == obj);
|
||||||
|
|
||||||
|
// test PyWeakref_GET_OBJECT(), reference is alive
|
||||||
|
PyObject *ref3 = PyWeakref_GET_OBJECT(weakref);
|
||||||
|
assert(ref3 == obj);
|
||||||
|
|
||||||
|
// delete the referenced object
|
||||||
|
assert(Py_REFCNT(obj) == 1);
|
||||||
|
Py_DECREF(obj);
|
||||||
|
|
||||||
|
// test PyWeakref_GET_OBJECT(), reference is dead
|
||||||
|
assert(PyWeakref_GET_OBJECT(weakref) == Py_None);
|
||||||
|
|
||||||
|
// test PyWeakref_GetRef(), reference is dead
|
||||||
|
PyObject *ref4 = Py_True; // marker to check that value was set
|
||||||
|
assert(PyWeakref_GetRef(weakref, &ref4) == 0);
|
||||||
|
assert(ref4 == NULL);
|
||||||
|
|
||||||
|
// None is not a weak reference object
|
||||||
|
PyObject *invalid_weakref = Py_None;
|
||||||
|
assert(!PyWeakref_Check(invalid_weakref));
|
||||||
|
assert(!PyWeakref_CheckRefExact(invalid_weakref));
|
||||||
|
assert(!PyWeakref_CheckRefExact(invalid_weakref));
|
||||||
|
|
||||||
|
// test PyWeakref_GetRef(), invalid type
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
|
PyObject *ref5 = Py_True; // marker to check that value was set
|
||||||
|
assert(PyWeakref_GetRef(invalid_weakref, &ref5) == -1);
|
||||||
|
assert(PyErr_ExceptionMatches(PyExc_TypeError));
|
||||||
|
PyErr_Clear();
|
||||||
|
assert(ref5 == NULL);
|
||||||
|
|
||||||
|
// test PyWeakref_GetObject(), invalid type
|
||||||
|
assert(PyWeakref_GetObject(invalid_weakref) == NULL);
|
||||||
|
assert(PyErr_ExceptionMatches(PyExc_SystemError));
|
||||||
|
PyErr_Clear();
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef TestMethods[] = {
|
static PyMethodDef TestMethods[] = {
|
||||||
{"set_errno", set_errno, METH_VARARGS},
|
{"set_errno", set_errno, METH_VARARGS},
|
||||||
{"test_config", test_config, METH_NOARGS},
|
{"test_config", test_config, METH_NOARGS},
|
||||||
|
@ -3516,6 +3594,7 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
||||||
{"test_atexit", test_atexit, METH_NOARGS},
|
{"test_atexit", test_atexit, METH_NOARGS},
|
||||||
{"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
|
{"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
|
||||||
|
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -894,6 +894,24 @@ PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
|
||||||
|
{
|
||||||
|
if (ref == NULL) {
|
||||||
|
*pobj = NULL;
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!PyWeakref_Check(ref)) {
|
||||||
|
*pobj = NULL;
|
||||||
|
PyErr_SetString(PyExc_TypeError, "expected a weakref");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*pobj = _PyWeakref_GET_REF(ref);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyWeakref_GetObject(PyObject *ref)
|
PyWeakref_GetObject(PyObject *ref)
|
||||||
{
|
{
|
||||||
|
|
1
PC/python3dll.c
generated
1
PC/python3dll.c
generated
|
@ -735,6 +735,7 @@ EXPORT_FUNC(PyUnicodeTranslateError_SetStart)
|
||||||
EXPORT_FUNC(PyVectorcall_Call)
|
EXPORT_FUNC(PyVectorcall_Call)
|
||||||
EXPORT_FUNC(PyVectorcall_NARGS)
|
EXPORT_FUNC(PyVectorcall_NARGS)
|
||||||
EXPORT_FUNC(PyWeakref_GetObject)
|
EXPORT_FUNC(PyWeakref_GetObject)
|
||||||
|
EXPORT_FUNC(PyWeakref_GetRef)
|
||||||
EXPORT_FUNC(PyWeakref_NewProxy)
|
EXPORT_FUNC(PyWeakref_NewProxy)
|
||||||
EXPORT_FUNC(PyWeakref_NewRef)
|
EXPORT_FUNC(PyWeakref_NewRef)
|
||||||
EXPORT_FUNC(PyWrapper_New)
|
EXPORT_FUNC(PyWrapper_New)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue