]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-74929: PEP 667 C API documentation (gh-119892)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 1 Jun 2024 04:23:04 +0000 (06:23 +0200)
committerGitHub <noreply@github.com>
Sat, 1 Jun 2024 04:23:04 +0000 (04:23 +0000)
* 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

(cherry picked from commit 3859e09e3d92d004978dd838f0511364e7edfb94)

Co-authored-by: Alyssa Coghlan <ncoghlan@gmail.com>
Doc/c-api/reflection.rst
Doc/data/refcounts.dat
Doc/whatsnew/3.13.rst
Lib/test/test_sys.py
Objects/frameobject.c
Python/bytecodes.c
Python/executor_cases.c.h
Python/generated_cases.c.h
Python/sysmodule.c

index 4b1c4770848a306ed7e709afc5cac6d6eaf4c8a3..5dcfe40c2ce92b1fc8a527e652e15829554455ae 100644 (file)
@@ -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
index 62a96146d605ff7282823f20d7b09a280f359091..a7d06e076a1b5503a7c8528aaefbfdb8a5d49245 100644 (file)
@@ -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:
 
index d09d7ce98645754179abaff7823f876e39157cd9..09dc5375186993e3fd77425d0395157b237b2091 100644 (file)
@@ -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:
@@ -2131,6 +2131,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
 =============
@@ -2306,6 +2311,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
 --------------
 
index ee3bd0092f9bf3bd81a1e2c8a32996f699997c56..ed398060f791c91943e48d315ae287d0de8abda7 100644 (file)
@@ -394,10 +394,15 @@ class SysModuleTest(unittest.TestCase):
 
     @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)
index 64fded85de1468029369b996907cd23539bfb44c..0465aaa01bb38cbe8ace4b3494befb026ed7e88a 100644 (file)
@@ -1919,8 +1919,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.
             }
         }
     }
@@ -2033,18 +2032,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;
 }
 
index 434eb8042138109cbddb8e421501a0bcd20fa32f..8a6222c2bf0d77a3b3b6e1288c82f3678a18f6a6 100644 (file)
@@ -1543,7 +1543,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) {
index 347a1e677a08325f4192ef55f90541b0fe6e87c9..4699c8efebedc99bcfdbaa6a87b43ecce796cde7 100644 (file)
         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) {
index 96161c5a6586fd2a613c235d423fc51c1fe4817b..32d5b8b1c1d93c3e73a3c49cc5ba69002e1147e1 100644 (file)
             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) {
index 4da13e4552e786d4dcf2a57df1bfd2725fdee013..00aa95531026b5bd3c7e06a1a6eb265b8398f953 100644 (file)
@@ -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