[3.13] gh-118934: Fix PyEval_GetLocals docs (PEP 667) (GH-119934)

PEP 667's description of the planned changes to PyEval_GetLocals
was internally inconsistent when accepted, so the docs added for
gh-74929 didn't match either the current behaviour or the intended
behaviour once gh-118934 is fixed.

This PR updates the documentation and 3.13 What's New to match the
intended behaviour (once gh-118934 is fixed).

It also tidies up lingering references to `f_locals` always being a
dictionary (this hasn't been true since at least when custom
namespace support for class statement execution was added)
(cherry picked from commit fd6cd621e0)

Co-authored-by: Alyssa Coghlan <ncoghlan@gmail.com>
This commit is contained in:
Miss Islington (bot) 2024-06-02 07:57:17 +02:00 committed by GitHub
parent 36ca00f44d
commit cf8f292a36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 21 deletions

View File

@ -19,23 +19,28 @@ Reflection
.. deprecated:: 3.13 .. deprecated:: 3.13
To avoid creating a reference cycle in :term:`optimized scopes <optimized scope>`, Use either :c:func:`PyEval_GetFrameLocals` to obtain the same behaviour as calling
use either :c:func:`PyEval_GetFrameLocals` to obtain the same behaviour as calling
:func:`locals` in Python code, or else call :c:func:`PyFrame_GetLocals` on the result :func:`locals` in Python code, or else call :c:func:`PyFrame_GetLocals` on the result
of :c:func:`PyEval_GetFrame` to get the same result as this function without having to of :c:func:`PyEval_GetFrame` to access the :attr:`~frame.f_locals` attribute of the
cache the proxy instance on the underlying frame. currently executing frame.
Return the :attr:`~frame.f_locals` attribute of the currently executing frame, Return a mapping providing access to the local variables in the current execution frame,
or ``NULL`` if no frame is currently executing. or ``NULL`` if no frame is currently executing.
If the frame refers to an :term:`optimized scope`, this returns a Refer to :func:`locals` for details of the mapping returned at different scopes.
write-through proxy object that allows modifying the locals.
In all other cases (classes, modules, :func:`exec`, :func:`eval`) it returns As this function returns a :term:`borrowed reference`, the dictionary returned for
the mapping representing the frame locals directly (as described for :term:`optimized scopes <optimized scope>` is cached on the frame object and will remain
:func:`locals`). alive as long as the frame object does. Unlike :c:func:`PyEval_GetFrameLocals` and
:func:`locals`, subsequent calls to this function in the same frame will update the
contents of the cached dictionary to reflect changes in the state of the local variables
rather than returning a new snapshot.
.. versionchanged:: 3.13 .. versionchanged:: 3.13
As part of :pep:`667`, return a proxy object for optimized scopes. As part of :pep:`667`, :c:func:`PyFrame_GetLocals`, :func:`locals`, and
:attr:`FrameType.f_locals <frame.f_locals>` no longer make use of the shared cache
dictionary. Refer to the :ref:`What's New entry <whatsnew313-locals-semantics>` for
additional details.
.. c:function:: PyObject* PyEval_GetGlobals(void) .. c:function:: PyObject* PyEval_GetGlobals(void)

View File

@ -1344,13 +1344,13 @@ Special read-only attributes
``object.__getattr__`` with arguments ``obj`` and ``"f_code"``. ``object.__getattr__`` with arguments ``obj`` and ``"f_code"``.
* - .. attribute:: frame.f_locals * - .. attribute:: frame.f_locals
- The dictionary used by the frame to look up - The mapping used by the frame to look up
:ref:`local variables <naming>`. :ref:`local variables <naming>`.
If the frame refers to an :term:`optimized scope`, If the frame refers to an :term:`optimized scope`,
this may return a write-through proxy object. this may return a write-through proxy object.
.. versionchanged:: 3.13 .. versionchanged:: 3.13
Return a proxy for functions and comprehensions. Return a proxy for optimized scopes.
* - .. attribute:: frame.f_globals * - .. attribute:: frame.f_globals
- The dictionary used by the frame to look up - The dictionary used by the frame to look up

View File

@ -287,8 +287,9 @@ returns a write-through proxy to the frame's local and locally referenced
nonlocal variables in these scopes, rather than returning an inconsistently nonlocal variables in these scopes, rather than returning an inconsistently
updated shared ``dict`` instance with undefined runtime semantics. updated shared ``dict`` instance with undefined runtime semantics.
See :pep:`667` for more details, including related C API changes and See :pep:`667` for more details, including related C API changes and deprecations. Porting
deprecations. notes are also provided below for the affected :ref:`Python APIs <pep667-porting-notes-py>`
and :ref:`C APIs <pep667-porting-notes-c>`.
(PEP and implementation contributed by Mark Shannon and Tian Gao in (PEP and implementation contributed by Mark Shannon and Tian Gao in
:gh:`74929`. Documentation updates provided by Guido van Rossum and :gh:`74929`. Documentation updates provided by Guido van Rossum and
@ -2234,6 +2235,8 @@ Changes in the Python API
returned by :meth:`zipfile.ZipFile.open` was changed from ``'r'`` to ``'rb'``. returned by :meth:`zipfile.ZipFile.open` was changed from ``'r'`` to ``'rb'``.
(Contributed by Serhiy Storchaka in :gh:`115961`.) (Contributed by Serhiy Storchaka in :gh:`115961`.)
.. _pep667-porting-notes-py:
* Calling :func:`locals` in an :term:`optimized scope` now produces an * Calling :func:`locals` in an :term:`optimized scope` now produces an
independent snapshot on each call, and hence no longer implicitly updates independent snapshot on each call, and hence no longer implicitly updates
previously returned references. Obtaining the legacy CPython behaviour now previously returned references. Obtaining the legacy CPython behaviour now
@ -2329,15 +2332,27 @@ 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`.)
* Calling :c:func:`PyFrame_GetLocals` or :c:func:`PyEval_GetLocals` in an .. _pep667-porting-notes-c:
:term:`optimized scope` now returns a write-through proxy rather than a
snapshot that gets updated at ill-specified times. If a snapshot is desired, * The effects of mutating the dictionary returned from :c:func:`PyEval_GetLocals` in an
it must be created explicitly (e.g. with :c:func:`PyDict_Copy`) or by calling :term:`optimized scope` have changed. New dict entries added this way will now *only* be
the new :c:func:`PyEval_GetFrameLocals` API. (Changed as part of :pep:`667`.) visible to subsequent :c:func:`PyEval_GetLocals` calls in that frame, as
:c:func:`PyFrame_GetLocals`, :func:`locals`, and
:attr:`FrameType.f_locals <frame.f_locals>` no longer access the same underlying cached
dictionary. Changes made to entries for actual variable names and names added via the
write-through proxy interfaces will be overwritten on subsequent calls to
:c:func:`PyEval_GetLocals` in that frame. The recommended code update depends on how the
function was being used, so refer to the deprecation notice on the function for details.
(Changed as part of :pep:`667`.)
* Calling :c:func:`PyFrame_GetLocals` in an :term:`optimized scope` now returns a
write-through proxy rather than a snapshot that gets updated at ill-specified times.
If a snapshot is desired, it must be created explicitly (e.g. with :c:func:`PyDict_Copy`)
or by calling the new :c:func:`PyEval_GetFrameLocals` API. (Changed as part of :pep:`667`.)
* :c:func:`!PyFrame_FastToLocals` and :c:func:`!PyFrame_FastToLocalsWithError` * :c:func:`!PyFrame_FastToLocals` and :c:func:`!PyFrame_FastToLocalsWithError`
no longer have any effect. Calling these functions has been redundant since no longer have any effect. Calling these functions has been redundant since
Python 3.11, when :c:func:`PyFrame_GetLocals` was first introduced. Python 3.11, when :c:func:`PyFrame_GetLocals` was first introduced.
(Changed as part of :pep:`667`.) (Changed as part of :pep:`667`.)
* :c:func:`!PyFrame_LocalsToFast` no longer has any effect. Calling this function * :c:func:`!PyFrame_LocalsToFast` no longer has any effect. Calling this function
@ -2497,6 +2512,11 @@ Deprecated C APIs
:c:func:`PyWeakref_GetRef` on Python 3.12 and older. :c:func:`PyWeakref_GetRef` on Python 3.12 and older.
(Contributed by Victor Stinner in :gh:`105927`.) (Contributed by Victor Stinner in :gh:`105927`.)
* Deprecate the :c:func:`PyEval_GetBuiltins`, :c:func:`PyEval_GetGlobals`, and
:c:func:`PyEval_GetLocals` functions, which return a :term:`borrowed reference`.
Refer to the deprecation notices on each function for their recommended replacements.
(Soft deprecated as part of :pep:`667`.)
Pending Removal in Python 3.14 Pending Removal in Python 3.14
------------------------------ ------------------------------