https://github.com/python/cpython/commit/3859e09e3d92d004978dd838f0511364e7edfb94
commit: 3859e09e3d92d004978dd838f0511364e7edfb94
branch: main
author: Alyssa Coghlan <[email protected]>
committer: ncoghlan <[email protected]>
date: 2024-06-01T13:59:35+10:00
summary:
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
files:
M Doc/c-api/reflection.rst
M Doc/data/refcounts.dat
M Doc/whatsnew/3.13.rst
M Lib/test/test_sys.py
M Objects/frameobject.c
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/generated_cases.c.h
M Python/sysmodule.c
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 4b1c4770848a30..5dcfe40c2ce92b 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -7,18 +7,30 @@ Reflection
.. 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,
or the interpreter of the thread state if no frame is currently executing.
.. 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,
or ``NULL`` if no frame is currently executing.
.. 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,
or ``NULL`` if no frame is currently executing.
@@ -31,6 +43,32 @@ Reflection
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)
Return the name of *func* if it is a function, class or instance object,
else the
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index 62a96146d605ff..a7d06e076a1b55 100644
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -790,6 +790,12 @@ PyEval_GetGlobals:PyObject*::0:
PyEval_GetFrame:PyObject*::0:
+PyEval_GetFrameBuiltins:PyObject*::+1:
+
+PyEval_GetFrameLocals:PyObject*::+1:
+
+PyEval_GetFrameGlobals:PyObject*::+1:
+
PyEval_GetFuncDesc:const char*:::
PyEval_GetFuncDesc:PyObject*:func:0:
@@ -916,6 +922,32 @@ PyFloat_FromString:PyObject*:str:0:
PyFloat_GetInfo:PyObject*::+1:
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:PyObject*:p:0:
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index 29bb3b81f6323c..3a52baf71310a3 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -97,7 +97,7 @@ Interpreter improvements:
* :pep:`667`: The :func:`locals` builtin now has
:ref:`defined semantics <whatsnew313-locals-semantics>` when mutating the
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.
New typing features:
@@ -2143,6 +2143,11 @@ New Features
destruction the same way the :mod:`tracemalloc` module does. (Contributed
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
=============
@@ -2318,6 +2323,15 @@ Changes in the C API
to :c:func:`PyUnstable_Code_GetFirstFree`.
(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
--------------
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 8fe1d77756866a..1e5823f8883957 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -394,10 +394,15 @@ def test_dlopenflags(self):
@test.support.refcount_test
def test_refcount(self):
- # n here must be a global in order for this test to pass while
- # tracing with a python function. Tracing calls PyFrame_FastToLocals
- # which will add a copy of any locals to the frame object, causing
- # the reference count to increase by 2 instead of 1.
+ # n here originally had to be a global in order for this test to pass
+ # while tracing with a python function. Tracing used to call
+ # PyFrame_FastToLocals, which would add a copy of any locals to the
+ # 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
self.assertRaises(TypeError, sys.getrefcount)
c = sys.getrefcount(None)
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index fc8d6c7a7aee89..5c65007dae46d2 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -1888,8 +1888,7 @@ frame_get_var(_PyInterpreterFrame *frame, PyCodeObject
*co, int i,
}
// (likely) Otherwise it is an arg (kind & CO_FAST_LOCAL),
// with the initial value set when the frame was created...
- // (unlikely) ...or it was set to some initial value by
- // an earlier call to PyFrame_LocalsToFast().
+ // (unlikely) ...or it was set via the f_locals proxy.
}
}
}
@@ -2002,18 +2001,24 @@ PyFrame_GetVarString(PyFrameObject *frame, const char
*name)
int
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;
}
void
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;
}
void
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;
}
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 1c12e1cddbbc10..413ad1105f9428 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1570,7 +1570,7 @@ dummy_func(
inst(MAKE_CELL, (--)) {
// "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 *cell = PyCell_New(initial);
if (cell == NULL) {
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 0dfe490cb37047..bab629684c53f6 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -1541,7 +1541,7 @@
case _MAKE_CELL: {
oparg = CURRENT_OPARG();
// "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 *cell = PyCell_New(initial);
if (cell == NULL) {
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 1a991608385405..355be966cbb84a 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -4784,7 +4784,7 @@
next_instr += 1;
INSTRUCTION_STATS(MAKE_CELL);
// "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 *cell = PyCell_New(initial);
if (cell == NULL) {
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 4da13e4552e786..00aa95531026b5 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -35,7 +35,6 @@ Data members:
#include "pycore_sysmodule.h" // export _PySys_GetSizeOf()
#include "pycore_tuple.h" // _PyTuple_FromArray()
-#include "frameobject.h" // PyFrame_FastToLocalsWithError()
#include "pydtrace.h" // PyDTrace_AUDIT()
#include "osdefs.h" // DELIM
#include "stdlib_module_names.h" // _Py_stdlib_module_names
_______________________________________________
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]