gh-136492: Add FrameLocalsProxyType to types (GH-136546)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
This commit is contained in:
Peter Bierma
2025-07-20 20:49:00 +02:00
committed by GitHub
parent e24c66d55a
commit 8f59fbb082
8 changed files with 47 additions and 1 deletions

View File

@@ -333,6 +333,16 @@ Standard names are defined for the following types:
:attr:`tb.tb_frame <traceback.tb_frame>` if ``tb`` is a traceback object.
.. data:: FrameLocalsProxyType
The type of frame locals proxy objects, as found on the
:attr:`frame.f_locals` attribute.
.. versionadded:: next
.. seealso:: :pep:`667`
.. data:: GetSetDescriptorType
The type of objects defined in extension modules with ``PyGetSetDef``, such

View File

@@ -312,6 +312,15 @@ tarfile
and :cve:`2025-4435`.)
types
------
* Expose the write-through :func:`locals` proxy type
as :data:`types.FrameLocalsProxyType`.
This represents the type of the :attr:`frame.f_locals` attribute,
as described in :pep:`667`.
unittest
--------

View File

@@ -5786,6 +5786,7 @@ class TestSignatureDefinitions(unittest.TestCase):
'AsyncGeneratorType': {'athrow'},
'CoroutineType': {'throw'},
'GeneratorType': {'throw'},
'FrameLocalsProxyType': {'setdefault', 'pop', 'get'},
}
self._test_module_has_signatures(types,
unsupported_signature=unsupported_signature,

View File

@@ -53,6 +53,7 @@ class TypesTests(unittest.TestCase):
'AsyncGeneratorType', 'BuiltinFunctionType', 'BuiltinMethodType',
'CapsuleType', 'CellType', 'ClassMethodDescriptorType', 'CodeType',
'CoroutineType', 'EllipsisType', 'FrameType', 'FunctionType',
'FrameLocalsProxyType',
'GeneratorType', 'GenericAlias', 'GetSetDescriptorType',
'LambdaType', 'MappingProxyType', 'MemberDescriptorType',
'MethodDescriptorType', 'MethodType', 'MethodWrapperType',
@@ -711,6 +712,16 @@ class TypesTests(unittest.TestCase):
"""
assert_python_ok("-c", code)
def test_frame_locals_proxy_type(self):
self.assertIsInstance(types.FrameLocalsProxyType, type)
self.assertIsInstance(types.FrameLocalsProxyType.__doc__, str)
self.assertEqual(types.FrameLocalsProxyType.__module__, 'builtins')
self.assertEqual(types.FrameLocalsProxyType.__name__, 'FrameLocalsProxy')
frame = inspect.currentframe()
self.assertIsNotNone(frame)
self.assertIsInstance(frame.f_locals, types.FrameLocalsProxyType)
class UnionTests(unittest.TestCase):

View File

@@ -58,7 +58,10 @@ except ImportError:
raise TypeError
except TypeError as exc:
TracebackType = type(exc.__traceback__)
FrameType = type(exc.__traceback__.tb_frame)
_f = (lambda: sys._getframe())()
FrameType = type(_f)
FrameLocalsProxyType = type(_f.f_locals)
GetSetDescriptorType = type(FunctionType.__code__)
MemberDescriptorType = type(FunctionType.__globals__)

View File

@@ -0,0 +1 @@
Expose :pep:`667`'s :data:`~types.FrameLocalsProxyType` in the :mod:`types` module.

View File

@@ -28,6 +28,7 @@ _types_exec(PyObject *m)
EXPORT_STATIC_TYPE("CoroutineType", PyCoro_Type);
EXPORT_STATIC_TYPE("EllipsisType", PyEllipsis_Type);
EXPORT_STATIC_TYPE("FrameType", PyFrame_Type);
EXPORT_STATIC_TYPE("FrameLocalsProxyType", PyFrameLocalsProxy_Type);
EXPORT_STATIC_TYPE("FunctionType", PyFunction_Type);
EXPORT_STATIC_TYPE("GeneratorType", PyGen_Type);
EXPORT_STATIC_TYPE("GenericAlias", Py_GenericAliasType);

View File

@@ -913,6 +913,15 @@ static PyMethodDef framelocalsproxy_methods[] = {
{NULL, NULL} /* sentinel */
};
PyDoc_STRVAR(framelocalsproxy_doc,
"FrameLocalsProxy($frame)\n"
"--\n"
"\n"
"Create a write-through view of the locals dictionary for a frame.\n"
"\n"
" frame\n"
" the frame object to wrap.");
PyTypeObject PyFrameLocalsProxy_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
.tp_name = "FrameLocalsProxy",
@@ -933,6 +942,7 @@ PyTypeObject PyFrameLocalsProxy_Type = {
.tp_alloc = PyType_GenericAlloc,
.tp_new = framelocalsproxy_new,
.tp_free = PyObject_GC_Del,
.tp_doc = framelocalsproxy_doc,
};
PyObject *