mirror of https://github.com/python/cpython
gh-74929: PEP 667 C API documentation (gh-119379)
* Add docs for new APIs * Add soft-deprecation notices * Add What's New porting entries * Update comments referencing `PyFrame_LocalsToFast()` to mention the proxy instead * Other related cleanups found when looking for refs to the deprecated APIs
This commit is contained in:
parent
cc5cd4d93e
commit
3859e09e3d
|
@ -7,18 +7,30 @@ Reflection
|
||||||
|
|
||||||
.. c:function:: PyObject* PyEval_GetBuiltins(void)
|
.. c:function:: PyObject* PyEval_GetBuiltins(void)
|
||||||
|
|
||||||
|
.. deprecated:: 3.13
|
||||||
|
|
||||||
|
Use :c:func:`PyEval_GetFrameBuiltins` instead.
|
||||||
|
|
||||||
Return a dictionary of the builtins in the current execution frame,
|
Return a dictionary of the builtins in the current execution frame,
|
||||||
or the interpreter of the thread state if no frame is currently executing.
|
or the interpreter of the thread state if no frame is currently executing.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyEval_GetLocals(void)
|
.. c:function:: PyObject* PyEval_GetLocals(void)
|
||||||
|
|
||||||
|
.. deprecated:: 3.13
|
||||||
|
|
||||||
|
Use :c:func:`PyEval_GetFrameLocals` instead.
|
||||||
|
|
||||||
Return a dictionary of the local variables in the current execution frame,
|
Return a dictionary of the local variables in the current execution frame,
|
||||||
or ``NULL`` if no frame is currently executing.
|
or ``NULL`` if no frame is currently executing.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyEval_GetGlobals(void)
|
.. c:function:: PyObject* PyEval_GetGlobals(void)
|
||||||
|
|
||||||
|
.. deprecated:: 3.13
|
||||||
|
|
||||||
|
Use :c:func:`PyEval_GetFrameGlobals` instead.
|
||||||
|
|
||||||
Return a dictionary of the global variables in the current execution frame,
|
Return a dictionary of the global variables in the current execution frame,
|
||||||
or ``NULL`` if no frame is currently executing.
|
or ``NULL`` if no frame is currently executing.
|
||||||
|
|
||||||
|
@ -31,6 +43,32 @@ Reflection
|
||||||
See also :c:func:`PyThreadState_GetFrame`.
|
See also :c:func:`PyThreadState_GetFrame`.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyEval_GetFrameBuiltins(void)
|
||||||
|
|
||||||
|
Return a dictionary of the builtins in the current execution frame,
|
||||||
|
or the interpreter of the thread state if no frame is currently executing.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyEval_GetFrameLocals(void)
|
||||||
|
|
||||||
|
Return a dictionary of the local variables in the current execution frame,
|
||||||
|
or ``NULL`` if no frame is currently executing. Equivalent to calling
|
||||||
|
:func:`locals` in Python code.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyEval_GetFrameGlobals(void)
|
||||||
|
|
||||||
|
Return a dictionary of the global variables in the current execution frame,
|
||||||
|
or ``NULL`` if no frame is currently executing. Equivalent to calling
|
||||||
|
:func:`globals` in Python code.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: const char* PyEval_GetFuncName(PyObject *func)
|
.. c:function:: const char* PyEval_GetFuncName(PyObject *func)
|
||||||
|
|
||||||
Return the name of *func* if it is a function, class or instance object, else the
|
Return the name of *func* if it is a function, class or instance object, else the
|
||||||
|
|
|
@ -790,6 +790,12 @@ PyEval_GetGlobals:PyObject*::0:
|
||||||
|
|
||||||
PyEval_GetFrame:PyObject*::0:
|
PyEval_GetFrame:PyObject*::0:
|
||||||
|
|
||||||
|
PyEval_GetFrameBuiltins:PyObject*::+1:
|
||||||
|
|
||||||
|
PyEval_GetFrameLocals:PyObject*::+1:
|
||||||
|
|
||||||
|
PyEval_GetFrameGlobals:PyObject*::+1:
|
||||||
|
|
||||||
PyEval_GetFuncDesc:const char*:::
|
PyEval_GetFuncDesc:const char*:::
|
||||||
PyEval_GetFuncDesc:PyObject*:func:0:
|
PyEval_GetFuncDesc:PyObject*:func:0:
|
||||||
|
|
||||||
|
@ -916,6 +922,32 @@ PyFloat_FromString:PyObject*:str:0:
|
||||||
PyFloat_GetInfo:PyObject*::+1:
|
PyFloat_GetInfo:PyObject*::+1:
|
||||||
PyFloat_GetInfo::void::
|
PyFloat_GetInfo::void::
|
||||||
|
|
||||||
|
PyFrame_GetBack:PyObject*::+1:
|
||||||
|
PyFrame_GetBack:PyFrameObject*:frame:0:
|
||||||
|
|
||||||
|
PyFrame_GetBuiltins:PyObject*::+1:
|
||||||
|
PyFrame_GetBuiltins:PyFrameObject*:frame:0:
|
||||||
|
|
||||||
|
PyFrame_GetCode:PyObject*::+1:
|
||||||
|
PyFrame_GetCode:PyFrameObject*:frame:0:
|
||||||
|
|
||||||
|
PyFrame_GetGenerator:PyObject*::+1:
|
||||||
|
PyFrame_GetGenerator:PyFrameObject*:frame:0:
|
||||||
|
|
||||||
|
PyFrame_GetGlobals:PyObject*::+1:
|
||||||
|
PyFrame_GetGlobals:PyFrameObject*:frame:0:
|
||||||
|
|
||||||
|
PyFrame_GetLocals:PyObject*::+1:
|
||||||
|
PyFrame_GetLocals:PyFrameObject*:frame:0:
|
||||||
|
|
||||||
|
PyFrame_GetVar:PyObject*::+1:
|
||||||
|
PyFrame_GetVar:PyFrameObject*:frame:0:
|
||||||
|
PyFrame_GetVar:PyObject*:name:0:
|
||||||
|
|
||||||
|
PyFrame_GetVarString:PyObject*::+1:
|
||||||
|
PyFrame_GetVarString:PyFrameObject*:frame:0:
|
||||||
|
PyFrame_GetVarString:const char*:name::
|
||||||
|
|
||||||
PyFrozenSet_Check:int:::
|
PyFrozenSet_Check:int:::
|
||||||
PyFrozenSet_Check:PyObject*:p:0:
|
PyFrozenSet_Check:PyObject*:p:0:
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ Interpreter improvements:
|
||||||
* :pep:`667`: The :func:`locals` builtin now has
|
* :pep:`667`: The :func:`locals` builtin now has
|
||||||
:ref:`defined semantics <whatsnew313-locals-semantics>` when mutating the
|
:ref:`defined semantics <whatsnew313-locals-semantics>` when mutating the
|
||||||
returned mapping. Python debuggers and similar tools may now more reliably
|
returned mapping. Python debuggers and similar tools may now more reliably
|
||||||
update local variables in optimized frames even during concurrent code
|
update local variables in optimized scopes even during concurrent code
|
||||||
execution.
|
execution.
|
||||||
|
|
||||||
New typing features:
|
New typing features:
|
||||||
|
@ -2143,6 +2143,11 @@ New Features
|
||||||
destruction the same way the :mod:`tracemalloc` module does. (Contributed
|
destruction the same way the :mod:`tracemalloc` module does. (Contributed
|
||||||
by Pablo Galindo in :gh:`93502`.)
|
by Pablo Galindo in :gh:`93502`.)
|
||||||
|
|
||||||
|
* Add :c:func:`PyEval_GetFrameBuiltins`, :c:func:`PyEval_GetFrameGlobals`, and
|
||||||
|
:c:func:`PyEval_GetFrameLocals` to the C API. These replacements for
|
||||||
|
:c:func:`PyEval_GetBuiltins`, :c:func:`PyEval_GetGlobals`, and
|
||||||
|
:c:func:`PyEval_GetLocals` return :term:`strong references <strong reference>`
|
||||||
|
rather than borrowed references. (Added as part of :pep:`667`.)
|
||||||
|
|
||||||
Build Changes
|
Build Changes
|
||||||
=============
|
=============
|
||||||
|
@ -2318,6 +2323,15 @@ Changes in the C API
|
||||||
to :c:func:`PyUnstable_Code_GetFirstFree`.
|
to :c:func:`PyUnstable_Code_GetFirstFree`.
|
||||||
(Contributed by Bogdan Romanyuk in :gh:`115781`.)
|
(Contributed by Bogdan Romanyuk in :gh:`115781`.)
|
||||||
|
|
||||||
|
* :c:func:`!PyFrame_FastToLocals` and :c:func:`!PyFrame_FastToLocalsWithError`
|
||||||
|
no longer have any effect. Calling these functions has been redundant since
|
||||||
|
Python 3.11, when :c:func:`PyFrame_GetLocals` was first introduced.
|
||||||
|
(Changed as part of :pep:`667`.)
|
||||||
|
|
||||||
|
* :c:func:`!PyFrame_LocalsToFast` no longer has any effect. Calling this function
|
||||||
|
is redundant now that :c:func:`PyFrame_GetLocals` returns a write-through proxy
|
||||||
|
for :term:`optimized scopes <optimized scope>`. (Changed as part of :pep:`667`.)
|
||||||
|
|
||||||
Removed C APIs
|
Removed C APIs
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
|
@ -394,10 +394,15 @@ class SysModuleTest(unittest.TestCase):
|
||||||
|
|
||||||
@test.support.refcount_test
|
@test.support.refcount_test
|
||||||
def test_refcount(self):
|
def test_refcount(self):
|
||||||
# n here must be a global in order for this test to pass while
|
# n here originally had to be a global in order for this test to pass
|
||||||
# tracing with a python function. Tracing calls PyFrame_FastToLocals
|
# while tracing with a python function. Tracing used to call
|
||||||
# which will add a copy of any locals to the frame object, causing
|
# PyFrame_FastToLocals, which would add a copy of any locals to the
|
||||||
# the reference count to increase by 2 instead of 1.
|
# frame object, causing the ref count to increase by 2 instead of 1.
|
||||||
|
# While that no longer happens (due to PEP 667), this test case retains
|
||||||
|
# its original global-based implementation
|
||||||
|
# PEP 683's immortal objects also made this point moot, since the
|
||||||
|
# refcount for None doesn't change anyway. Maybe this test should be
|
||||||
|
# using a different constant value? (e.g. an integer)
|
||||||
global n
|
global n
|
||||||
self.assertRaises(TypeError, sys.getrefcount)
|
self.assertRaises(TypeError, sys.getrefcount)
|
||||||
c = sys.getrefcount(None)
|
c = sys.getrefcount(None)
|
||||||
|
|
|
@ -1888,8 +1888,7 @@ frame_get_var(_PyInterpreterFrame *frame, PyCodeObject *co, int i,
|
||||||
}
|
}
|
||||||
// (likely) Otherwise it is an arg (kind & CO_FAST_LOCAL),
|
// (likely) Otherwise it is an arg (kind & CO_FAST_LOCAL),
|
||||||
// with the initial value set when the frame was created...
|
// with the initial value set when the frame was created...
|
||||||
// (unlikely) ...or it was set to some initial value by
|
// (unlikely) ...or it was set via the f_locals proxy.
|
||||||
// an earlier call to PyFrame_LocalsToFast().
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2002,18 +2001,24 @@ PyFrame_GetVarString(PyFrameObject *frame, const char *name)
|
||||||
int
|
int
|
||||||
PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
||||||
{
|
{
|
||||||
|
// Nothing to do here, as f_locals is now a write-through proxy in
|
||||||
|
// optimized frames. Soft-deprecated, since there's no maintenance hassle.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PyFrame_FastToLocals(PyFrameObject *f)
|
PyFrame_FastToLocals(PyFrameObject *f)
|
||||||
{
|
{
|
||||||
|
// Nothing to do here, as f_locals is now a write-through proxy in
|
||||||
|
// optimized frames. Soft-deprecated, since there's no maintenance hassle.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
||||||
{
|
{
|
||||||
|
// Nothing to do here, as f_locals is now a write-through proxy in
|
||||||
|
// optimized frames. Soft-deprecated, since there's no maintenance hassle.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1570,7 +1570,7 @@ dummy_func(
|
||||||
|
|
||||||
inst(MAKE_CELL, (--)) {
|
inst(MAKE_CELL, (--)) {
|
||||||
// "initial" is probably NULL but not if it's an arg (or set
|
// "initial" is probably NULL but not if it's an arg (or set
|
||||||
// via PyFrame_LocalsToFast() before MAKE_CELL has run).
|
// via the f_locals proxy before MAKE_CELL has run).
|
||||||
PyObject *initial = GETLOCAL(oparg);
|
PyObject *initial = GETLOCAL(oparg);
|
||||||
PyObject *cell = PyCell_New(initial);
|
PyObject *cell = PyCell_New(initial);
|
||||||
if (cell == NULL) {
|
if (cell == NULL) {
|
||||||
|
|
|
@ -1541,7 +1541,7 @@
|
||||||
case _MAKE_CELL: {
|
case _MAKE_CELL: {
|
||||||
oparg = CURRENT_OPARG();
|
oparg = CURRENT_OPARG();
|
||||||
// "initial" is probably NULL but not if it's an arg (or set
|
// "initial" is probably NULL but not if it's an arg (or set
|
||||||
// via PyFrame_LocalsToFast() before MAKE_CELL has run).
|
// via the f_locals proxy before MAKE_CELL has run).
|
||||||
PyObject *initial = GETLOCAL(oparg);
|
PyObject *initial = GETLOCAL(oparg);
|
||||||
PyObject *cell = PyCell_New(initial);
|
PyObject *cell = PyCell_New(initial);
|
||||||
if (cell == NULL) {
|
if (cell == NULL) {
|
||||||
|
|
|
@ -4784,7 +4784,7 @@
|
||||||
next_instr += 1;
|
next_instr += 1;
|
||||||
INSTRUCTION_STATS(MAKE_CELL);
|
INSTRUCTION_STATS(MAKE_CELL);
|
||||||
// "initial" is probably NULL but not if it's an arg (or set
|
// "initial" is probably NULL but not if it's an arg (or set
|
||||||
// via PyFrame_LocalsToFast() before MAKE_CELL has run).
|
// via the f_locals proxy before MAKE_CELL has run).
|
||||||
PyObject *initial = GETLOCAL(oparg);
|
PyObject *initial = GETLOCAL(oparg);
|
||||||
PyObject *cell = PyCell_New(initial);
|
PyObject *cell = PyCell_New(initial);
|
||||||
if (cell == NULL) {
|
if (cell == NULL) {
|
||||||
|
|
|
@ -35,7 +35,6 @@ Data members:
|
||||||
#include "pycore_sysmodule.h" // export _PySys_GetSizeOf()
|
#include "pycore_sysmodule.h" // export _PySys_GetSizeOf()
|
||||||
#include "pycore_tuple.h" // _PyTuple_FromArray()
|
#include "pycore_tuple.h" // _PyTuple_FromArray()
|
||||||
|
|
||||||
#include "frameobject.h" // PyFrame_FastToLocalsWithError()
|
|
||||||
#include "pydtrace.h" // PyDTrace_AUDIT()
|
#include "pydtrace.h" // PyDTrace_AUDIT()
|
||||||
#include "osdefs.h" // DELIM
|
#include "osdefs.h" // DELIM
|
||||||
#include "stdlib_module_names.h" // _Py_stdlib_module_names
|
#include "stdlib_module_names.h" // _Py_stdlib_module_names
|
||||||
|
|
Loading…
Reference in New Issue