Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.13] gh-74929: PEP 667 C API documentation (gh-119379) #119892

Merged
merged 1 commit into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Doc/c-api/reflection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Expand Down
32 changes: 32 additions & 0 deletions Doc/data/refcounts.dat
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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:

Expand Down
16 changes: 15 additions & 1 deletion Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
=============
Expand Down Expand Up @@ -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
--------------

Expand Down
13 changes: 9 additions & 4 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 7 additions & 2 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
}
}
Expand Down Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading