From 78b842c03b78bec6d21ac2abd4694ede0a3d6835 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:12:33 -0400 Subject: [PATCH 01/27] Expose FrameLocalsProxy in types and _types --- Lib/types.py | 1 + Modules/_typesmodule.c | 1 + 2 files changed, 2 insertions(+) diff --git a/Lib/types.py b/Lib/types.py index cf0549315a7814..a4189ac4f9fae5 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -69,6 +69,7 @@ def _m(self): pass EllipsisType = type(Ellipsis) NoneType = type(None) NotImplementedType = type(NotImplemented) + FrameLocalsProxy = (lambda: type(sys._getframe().f_locals)() # CapsuleType cannot be accessed from pure Python, # so there is no fallback definition. diff --git a/Modules/_typesmodule.c b/Modules/_typesmodule.c index a30a88196e7192..60ea2fda5ed04f 100644 --- a/Modules/_typesmodule.c +++ b/Modules/_typesmodule.c @@ -46,6 +46,7 @@ _types_exec(PyObject *m) EXPORT_STATIC_TYPE("TracebackType", PyTraceBack_Type); EXPORT_STATIC_TYPE("UnionType", _PyUnion_Type); EXPORT_STATIC_TYPE("WrapperDescriptorType", PyWrapperDescr_Type); + EXPORT_STATIC_TYPE("FrameLocalsProxy", PyFrameLocalsProxy_Type); #undef EXPORT_STATIC_TYPE return 0; } From e2ddcbec09fb7270183ad2e203550339c2065e79 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:16:59 -0400 Subject: [PATCH 02/27] Add a test case. --- Lib/test/test_types.py | 5 +++++ Lib/types.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index fccdcc975e6c43..149aac7424cfc2 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -711,6 +711,11 @@ def call(part): """ assert_python_ok("-c", code) + def test_frame_locals_proxy(self): + frame = inspect.currentframe() + self.assertIsNotNone(frame) + self.assertIsInstance(frame.f_locals, types.FrameLocalsProxy) + class UnionTests(unittest.TestCase): diff --git a/Lib/types.py b/Lib/types.py index a4189ac4f9fae5..30932b1f6021f8 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -69,7 +69,7 @@ def _m(self): pass EllipsisType = type(Ellipsis) NoneType = type(None) NotImplementedType = type(NotImplemented) - FrameLocalsProxy = (lambda: type(sys._getframe().f_locals)() + FrameLocalsProxy = (lambda: type(sys._getframe().f_locals))() # CapsuleType cannot be accessed from pure Python, # so there is no fallback definition. From 22e056dbfb8f328c79fa23b85679d2874d80b241 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:20:35 -0400 Subject: [PATCH 03/27] Add a documentation entry. --- Doc/library/types.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 2bedd7fdd3c8c8..927ea5b044f897 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -333,6 +333,14 @@ Standard names are defined for the following types: :attr:`tb.tb_frame ` if ``tb`` is a traceback object. +.. data:: FrameLocalsProxyType + + The type of frame :func:`locals` proxy objects, as found on the + :attr:`frame.f_locals` attribute. See :pep:`667` for more information. + + .. versionadded:: next + + .. data:: GetSetDescriptorType The type of objects defined in extension modules with ``PyGetSetDef``, such From b8fd7330fe1aa2062efbc58f4380bf79da8c8d44 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:21:04 -0400 Subject: [PATCH 04/27] Use the 'type' suffix. --- Lib/types.py | 2 +- Modules/_typesmodule.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/types.py b/Lib/types.py index 30932b1f6021f8..7fc4db13eeaa54 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -69,7 +69,7 @@ def _m(self): pass EllipsisType = type(Ellipsis) NoneType = type(None) NotImplementedType = type(NotImplemented) - FrameLocalsProxy = (lambda: type(sys._getframe().f_locals))() + FrameLocalsProxyType = (lambda: type(sys._getframe().f_locals))() # CapsuleType cannot be accessed from pure Python, # so there is no fallback definition. diff --git a/Modules/_typesmodule.c b/Modules/_typesmodule.c index 60ea2fda5ed04f..d2e941f4677503 100644 --- a/Modules/_typesmodule.c +++ b/Modules/_typesmodule.c @@ -46,7 +46,7 @@ _types_exec(PyObject *m) EXPORT_STATIC_TYPE("TracebackType", PyTraceBack_Type); EXPORT_STATIC_TYPE("UnionType", _PyUnion_Type); EXPORT_STATIC_TYPE("WrapperDescriptorType", PyWrapperDescr_Type); - EXPORT_STATIC_TYPE("FrameLocalsProxy", PyFrameLocalsProxy_Type); + EXPORT_STATIC_TYPE("FrameLocalsProxyType", PyFrameLocalsProxy_Type); #undef EXPORT_STATIC_TYPE return 0; } From abbe1d36732d4a1b264d5f6576aab2edc3defd95 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:22:44 -0400 Subject: [PATCH 05/27] Add a whatsnew entry. --- Doc/whatsnew/3.15.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index e9b88458acdd79..9aec3a4d8a1c8c 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -226,6 +226,13 @@ os.path (Contributed by Petr Viktorin for :cve:`2025-4517`.) +types +------ + +* Added :data:`types.FrameLocalsProxyType` for representing the type of + the :attr:`frame.f_locals` attribute, as determined in :pep:`667`. + + shelve ------ From 753c9bc21fea5f7c325bedf4b6bb91319d226308 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:23:50 -0400 Subject: [PATCH 06/27] Add blurb. --- .../next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst diff --git a/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst b/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst new file mode 100644 index 00000000000000..41114c781b2193 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst @@ -0,0 +1 @@ +Add :data:`~types.FrameLocalsProxyType` to the :mod:`types` module. From b087d9b9e4ebe35e38a008cb3625f6a7fb4c0e15 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:24:50 -0400 Subject: [PATCH 07/27] Fix the tests. --- Lib/test/test_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 149aac7424cfc2..bb57d7e1e63aa9 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -57,7 +57,7 @@ def test_names(self): 'LambdaType', 'MappingProxyType', 'MemberDescriptorType', 'MethodDescriptorType', 'MethodType', 'MethodWrapperType', 'ModuleType', 'NoneType', 'NotImplementedType', 'SimpleNamespace', - 'TracebackType', 'UnionType', 'WrapperDescriptorType', + 'TracebackType', 'UnionType', 'WrapperDescriptorType', 'FrameLocalsProxyType' } self.assertEqual(all_names, set(c_types.__all__)) self.assertEqual(all_names - c_only_names, set(py_types.__all__)) @@ -714,7 +714,7 @@ def call(part): def test_frame_locals_proxy(self): frame = inspect.currentframe() self.assertIsNotNone(frame) - self.assertIsInstance(frame.f_locals, types.FrameLocalsProxy) + self.assertIsInstance(frame.f_locals, types.FrameLocalsProxyType) class UnionTests(unittest.TestCase): From 1971a14fc8ff68fa74455b727521d7c060346ae1 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:25:40 -0400 Subject: [PATCH 08/27] Sort the name alphabetically. --- Lib/test/test_types.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index bb57d7e1e63aa9..bfa23899521251 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -53,11 +53,12 @@ def test_names(self): 'AsyncGeneratorType', 'BuiltinFunctionType', 'BuiltinMethodType', 'CapsuleType', 'CellType', 'ClassMethodDescriptorType', 'CodeType', 'CoroutineType', 'EllipsisType', 'FrameType', 'FunctionType', - 'GeneratorType', 'GenericAlias', 'GetSetDescriptorType', - 'LambdaType', 'MappingProxyType', 'MemberDescriptorType', - 'MethodDescriptorType', 'MethodType', 'MethodWrapperType', - 'ModuleType', 'NoneType', 'NotImplementedType', 'SimpleNamespace', - 'TracebackType', 'UnionType', 'WrapperDescriptorType', 'FrameLocalsProxyType' + 'FrameLocalsProxyType', 'GeneratorType', 'GenericAlias', + 'GetSetDescriptorType', 'LambdaType', 'MappingProxyType', + 'MemberDescriptorType', 'MethodDescriptorType', 'MethodType', + 'MethodWrapperType', 'ModuleType', 'NoneType', 'NotImplementedType', + 'SimpleNamespace', 'TracebackType', 'UnionType', + 'WrapperDescriptorType', } self.assertEqual(all_names, set(c_types.__all__)) self.assertEqual(all_names - c_only_names, set(py_types.__all__)) From fdeb2d084b39f88b92da0dcfddc52f256b16799c Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 10:28:57 -0400 Subject: [PATCH 09/27] Sort alphabetically in _types. --- Modules/_typesmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_typesmodule.c b/Modules/_typesmodule.c index d2e941f4677503..df6b4c93cb87a6 100644 --- a/Modules/_typesmodule.c +++ b/Modules/_typesmodule.c @@ -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); @@ -46,7 +47,6 @@ _types_exec(PyObject *m) EXPORT_STATIC_TYPE("TracebackType", PyTraceBack_Type); EXPORT_STATIC_TYPE("UnionType", _PyUnion_Type); EXPORT_STATIC_TYPE("WrapperDescriptorType", PyWrapperDescr_Type); - EXPORT_STATIC_TYPE("FrameLocalsProxyType", PyFrameLocalsProxy_Type); #undef EXPORT_STATIC_TYPE return 0; } From c8600b9cde1cbd70a89a77f7dcef459dd65cde8e Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 11:08:29 -0400 Subject: [PATCH 10/27] Move whatsnew section. --- Doc/whatsnew/3.15.rst | 14 +++++++------- Lib/test/test_inspect/test_inspect.py | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 9aec3a4d8a1c8c..c086dd85d14174 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -226,13 +226,6 @@ os.path (Contributed by Petr Viktorin for :cve:`2025-4517`.) -types ------- - -* Added :data:`types.FrameLocalsProxyType` for representing the type of - the :attr:`frame.f_locals` attribute, as determined in :pep:`667`. - - shelve ------ @@ -285,6 +278,13 @@ tarfile and :cve:`2025-4435`.) +types +------ + +* Added :data:`types.FrameLocalsProxyType` for representing the type of + the :attr:`frame.f_locals` attribute, as determined in :pep:`667`. + + zlib ---- diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 0ea029b977b3fc..2ce7e15a10210a 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -5786,6 +5786,7 @@ def test_types_module_has_signatures(self): 'AsyncGeneratorType': {'athrow'}, 'CoroutineType': {'throw'}, 'GeneratorType': {'throw'}, + 'FrameLocalsProxyType': {'setdefault', 'pop'} } self._test_module_has_signatures(types, unsupported_signature=unsupported_signature, From 70cc4db81c0417dcc491832956e8832be3dd1256 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 11:12:36 -0400 Subject: [PATCH 11/27] Somewhat fix the tests. --- Lib/test/test_inspect/test_inspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 2ce7e15a10210a..9d15a982b36e8c 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -5786,7 +5786,7 @@ def test_types_module_has_signatures(self): 'AsyncGeneratorType': {'athrow'}, 'CoroutineType': {'throw'}, 'GeneratorType': {'throw'}, - 'FrameLocalsProxyType': {'setdefault', 'pop'} + 'FrameLocalsProxyType': {'setdefault', 'pop', 'get'} } self._test_module_has_signatures(types, unsupported_signature=unsupported_signature, From fee5256998e7a5cd6fca80fc0b3c354d16e34d9f Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 11:12:54 -0400 Subject: [PATCH 12/27] Reduce the diff. --- Lib/test/test_types.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index bfa23899521251..3dd753b0e67400 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -53,12 +53,12 @@ def test_names(self): 'AsyncGeneratorType', 'BuiltinFunctionType', 'BuiltinMethodType', 'CapsuleType', 'CellType', 'ClassMethodDescriptorType', 'CodeType', 'CoroutineType', 'EllipsisType', 'FrameType', 'FunctionType', - 'FrameLocalsProxyType', 'GeneratorType', 'GenericAlias', - 'GetSetDescriptorType', 'LambdaType', 'MappingProxyType', - 'MemberDescriptorType', 'MethodDescriptorType', 'MethodType', - 'MethodWrapperType', 'ModuleType', 'NoneType', 'NotImplementedType', - 'SimpleNamespace', 'TracebackType', 'UnionType', - 'WrapperDescriptorType', + 'GeneratorType', 'GenericAlias', 'GetSetDescriptorType', + 'LambdaType', 'MappingProxyType', 'MemberDescriptorType', + 'MethodDescriptorType', 'MethodType', 'MethodWrapperType', + 'ModuleType', 'NoneType', 'NotImplementedType', 'SimpleNamespace', + 'TracebackType', 'UnionType', 'WrapperDescriptorType', + 'FrameLocalsProxyType' } self.assertEqual(all_names, set(c_types.__all__)) self.assertEqual(all_names - c_only_names, set(py_types.__all__)) From a110148c9c93efa9d9f56cc8df48714c9c7281c5 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 11:21:50 -0400 Subject: [PATCH 13/27] Use a workaround for the tests. --- Lib/test/test_inspect/test_inspect.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 9d15a982b36e8c..a4c9f474a39891 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -5788,9 +5788,11 @@ def test_types_module_has_signatures(self): 'GeneratorType': {'throw'}, 'FrameLocalsProxyType': {'setdefault', 'pop', 'get'} } + no_signature = {'FrameLocalsProxyType'} self._test_module_has_signatures(types, unsupported_signature=unsupported_signature, - methods_no_signature=methods_no_signature) + methods_no_signature=methods_no_signature, + no_signature=no_signature) def test_sys_module_has_signatures(self): no_signature = {'getsizeof', 'set_asyncgen_hooks'} From 929f81e4f36c9ed42b909e2450d76c5d0df317fe Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 11 Jul 2025 15:40:08 -0400 Subject: [PATCH 14/27] Move PEP note and remove locals() reference. --- Doc/library/types.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 927ea5b044f897..772a2ae88da75c 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -335,11 +335,14 @@ Standard names are defined for the following types: .. data:: FrameLocalsProxyType - The type of frame :func:`locals` proxy objects, as found on the - :attr:`frame.f_locals` attribute. See :pep:`667` for more information. + The type of frame locals proxy objects, as found on the + :attr:`frame.f_locals` attribute. .. versionadded:: next + .. seealso:: + :pep:`667` + .. data:: GetSetDescriptorType From fb710ebe45f971080d2485fc2106d4d25bf15697 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sat, 12 Jul 2025 13:57:30 -0400 Subject: [PATCH 15/27] Update Doc/whatsnew/3.15.rst Co-authored-by: Jelle Zijlstra --- Doc/whatsnew/3.15.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index c086dd85d14174..4680791571b577 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -282,7 +282,7 @@ types ------ * Added :data:`types.FrameLocalsProxyType` for representing the type of - the :attr:`frame.f_locals` attribute, as determined in :pep:`667`. + the :attr:`frame.f_locals` attribute, as described in :pep:`667`. zlib From 592326356282c4b2b75162f3ce2b896fc03b4c39 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sat, 12 Jul 2025 16:58:04 -0400 Subject: [PATCH 16/27] Add a signature for FrameLocalsProxy() --- Lib/test/test_inspect/test_inspect.py | 4 +--- Objects/frameobject.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index a4c9f474a39891..9d15a982b36e8c 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -5788,11 +5788,9 @@ def test_types_module_has_signatures(self): 'GeneratorType': {'throw'}, 'FrameLocalsProxyType': {'setdefault', 'pop', 'get'} } - no_signature = {'FrameLocalsProxyType'} self._test_module_has_signatures(types, unsupported_signature=unsupported_signature, - methods_no_signature=methods_no_signature, - no_signature=no_signature) + methods_no_signature=methods_no_signature) def test_sys_module_has_signatures(self): no_signature = {'getsizeof', 'set_asyncgen_hooks'} diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 601fc69c4b1f60..b1f07b78d28a35 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -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 * From 22c2bbe470507bac63b5812db6f285d7bb4796bd Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 15 Jul 2025 03:54:01 -0400 Subject: [PATCH 17/27] Change the tp_name to types.FrameLocalsProxyType. --- Objects/frameobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index b1f07b78d28a35..7f7b18771500a9 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -914,7 +914,7 @@ static PyMethodDef framelocalsproxy_methods[] = { }; PyDoc_STRVAR(framelocalsproxy_doc, -"FrameLocalsProxy($frame)\n" +"FrameLocalsProxyType($frame)\n" "--\n" "\n" "Create a write-through view of the locals dictionary for a frame.\n" @@ -924,7 +924,7 @@ PyDoc_STRVAR(framelocalsproxy_doc, PyTypeObject PyFrameLocalsProxy_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - .tp_name = "FrameLocalsProxy", + .tp_name = "types.FrameLocalsProxyType", .tp_basicsize = sizeof(PyFrameLocalsProxyObject), .tp_dealloc = framelocalsproxy_dealloc, .tp_repr = &framelocalsproxy_repr, From 58e8577a85f88be2b39d7ae5818596252d5e9974 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 15 Jul 2025 04:26:51 -0400 Subject: [PATCH 18/27] Fix type name in test_frame. --- Lib/test/test_frame.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 18ade18d1a1708..4e4a3a53f2656d 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -577,9 +577,8 @@ class ObjectSubclass: proxy[obj] = 0 def test_constructor(self): - FrameLocalsProxy = type([sys._getframe().f_locals - for x in range(1)][0]) - self.assertEqual(FrameLocalsProxy.__name__, 'FrameLocalsProxy') + from types import FrameLocalsProxyType as FrameLocalsProxy + self.assertEqual(FrameLocalsProxy.__name__, 'FrameLocalsProxyType') def make_frame(): x = 1 From 7a649c2ac89bbeaee80bc0c2ce9a066a4cc099a5 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 15 Jul 2025 04:38:46 -0400 Subject: [PATCH 19/27] Apply suggestions from code review Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/types.rst | 3 +-- Doc/whatsnew/3.15.rst | 6 ++++-- Lib/test/test_types.py | 6 +++++- .../Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 772a2ae88da75c..207024a7619902 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -340,8 +340,7 @@ Standard names are defined for the following types: .. versionadded:: next - .. seealso:: - :pep:`667` + .. seealso:: :pep:`667` .. data:: GetSetDescriptorType diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index a073c0923df521..21b99e9aa05e5b 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -281,8 +281,10 @@ tarfile types ------ -* Added :data:`types.FrameLocalsProxyType` for representing the type of - the :attr:`frame.f_locals` attribute, as described in :pep:`667`. +* 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 diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 3dd753b0e67400..a1f7ab9710801c 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -712,7 +712,11 @@ def call(part): """ assert_python_ok("-c", code) - def test_frame_locals_proxy(self): + def test_frame_locals_proxy_type(self): + self.assertIsInstance(types.FrameLocalsProxyType, type) + self.assertIsInstance(types.FrameLocalsProxyType.__doc__, str) + self.assertEqual(types.FrameLocalsProxyType.__module__, 'types') + frame = inspect.currentframe() self.assertIsNotNone(frame) self.assertIsInstance(frame.f_locals, types.FrameLocalsProxyType) diff --git a/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst b/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst index 41114c781b2193..7ab5b068a7f691 100644 --- a/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst +++ b/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst @@ -1 +1 @@ -Add :data:`~types.FrameLocalsProxyType` to the :mod:`types` module. +Expose :pep:`667`'s :data:`~types.FrameLocalsProxyType` in the :mod:`types` module. From e0f674d3e4e628448b3c9a8892f4c111ddb8104e Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 15 Jul 2025 04:40:14 -0400 Subject: [PATCH 20/27] Revert "Fix type name in test_frame." This reverts commit 58e8577a85f88be2b39d7ae5818596252d5e9974. --- Lib/test/test_frame.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 4e4a3a53f2656d..18ade18d1a1708 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -577,8 +577,9 @@ class ObjectSubclass: proxy[obj] = 0 def test_constructor(self): - from types import FrameLocalsProxyType as FrameLocalsProxy - self.assertEqual(FrameLocalsProxy.__name__, 'FrameLocalsProxyType') + FrameLocalsProxy = type([sys._getframe().f_locals + for x in range(1)][0]) + self.assertEqual(FrameLocalsProxy.__name__, 'FrameLocalsProxy') def make_frame(): x = 1 From faa4cf435ea9c0b501db9a43c4321fe378f43b96 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 15 Jul 2025 04:40:33 -0400 Subject: [PATCH 21/27] Revert "Change the tp_name to types.FrameLocalsProxyType." This reverts commit 22c2bbe470507bac63b5812db6f285d7bb4796bd. --- Objects/frameobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 7f7b18771500a9..b1f07b78d28a35 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -914,7 +914,7 @@ static PyMethodDef framelocalsproxy_methods[] = { }; PyDoc_STRVAR(framelocalsproxy_doc, -"FrameLocalsProxyType($frame)\n" +"FrameLocalsProxy($frame)\n" "--\n" "\n" "Create a write-through view of the locals dictionary for a frame.\n" @@ -924,7 +924,7 @@ PyDoc_STRVAR(framelocalsproxy_doc, PyTypeObject PyFrameLocalsProxy_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - .tp_name = "types.FrameLocalsProxyType", + .tp_name = "FrameLocalsProxy", .tp_basicsize = sizeof(PyFrameLocalsProxyObject), .tp_dealloc = framelocalsproxy_dealloc, .tp_repr = &framelocalsproxy_repr, From 0463c3064ccef01c364d6b95de597f688b395a8a Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 15 Jul 2025 04:43:25 -0400 Subject: [PATCH 22/27] Revert "Reduce the diff." This reverts commit fee5256998e7a5cd6fca80fc0b3c354d16e34d9f. --- Lib/test/test_types.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index a1f7ab9710801c..0cab7e77c885dc 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -53,12 +53,12 @@ def test_names(self): 'AsyncGeneratorType', 'BuiltinFunctionType', 'BuiltinMethodType', 'CapsuleType', 'CellType', 'ClassMethodDescriptorType', 'CodeType', 'CoroutineType', 'EllipsisType', 'FrameType', 'FunctionType', - 'GeneratorType', 'GenericAlias', 'GetSetDescriptorType', - 'LambdaType', 'MappingProxyType', 'MemberDescriptorType', - 'MethodDescriptorType', 'MethodType', 'MethodWrapperType', - 'ModuleType', 'NoneType', 'NotImplementedType', 'SimpleNamespace', - 'TracebackType', 'UnionType', 'WrapperDescriptorType', - 'FrameLocalsProxyType' + 'FrameLocalsProxyType', 'GeneratorType', 'GenericAlias', + 'GetSetDescriptorType', 'LambdaType', 'MappingProxyType', + 'MemberDescriptorType', 'MethodDescriptorType', 'MethodType', + 'MethodWrapperType', 'ModuleType', 'NoneType', 'NotImplementedType', + 'SimpleNamespace', 'TracebackType', 'UnionType', + 'WrapperDescriptorType', } self.assertEqual(all_names, set(c_types.__all__)) self.assertEqual(all_names - c_only_names, set(py_types.__all__)) From 59daace5e2ca105e652f4400a2811b6c2c766e56 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 15 Jul 2025 04:56:44 -0400 Subject: [PATCH 23/27] Fix tests that were broken by the tp_name revert. Should I test before I push my changes? Yes. Will I ever do it? No. --- Lib/test/test_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 0cab7e77c885dc..5bdee343dd9572 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -715,7 +715,8 @@ def call(part): def test_frame_locals_proxy_type(self): self.assertIsInstance(types.FrameLocalsProxyType, type) self.assertIsInstance(types.FrameLocalsProxyType.__doc__, str) - self.assertEqual(types.FrameLocalsProxyType.__module__, 'types') + self.assertEqual(types.FrameLocalsProxyType.__module__, 'builtins') + self.assertEqual(types.FrameLocalsProxyType.__name__, 'FrameLocalsProxy') frame = inspect.currentframe() self.assertIsNotNone(frame) From 349374dbca3418efe2986ff4aaaf24eaeaed4502 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 15 Jul 2025 05:54:57 -0400 Subject: [PATCH 24/27] Unify how FrameType and FrameLocalsProxyType are created. Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Lib/types.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/types.py b/Lib/types.py index 7fc4db13eeaa54..f96c75b46daba7 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -58,7 +58,10 @@ def _m(self): pass 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__) @@ -69,7 +72,6 @@ def _m(self): pass EllipsisType = type(Ellipsis) NoneType = type(None) NotImplementedType = type(NotImplemented) - FrameLocalsProxyType = (lambda: type(sys._getframe().f_locals))() # CapsuleType cannot be accessed from pure Python, # so there is no fallback definition. From 287c99302c4f272f277339b1e715b93672c47a47 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 20 Jul 2025 11:17:42 -0400 Subject: [PATCH 25/27] Keep it sorted but with a smaller diff. --- Lib/test/test_types.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 5bdee343dd9572..9b0ae709d7968d 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -53,12 +53,12 @@ def test_names(self): 'AsyncGeneratorType', 'BuiltinFunctionType', 'BuiltinMethodType', 'CapsuleType', 'CellType', 'ClassMethodDescriptorType', 'CodeType', 'CoroutineType', 'EllipsisType', 'FrameType', 'FunctionType', - 'FrameLocalsProxyType', 'GeneratorType', 'GenericAlias', - 'GetSetDescriptorType', 'LambdaType', 'MappingProxyType', - 'MemberDescriptorType', 'MethodDescriptorType', 'MethodType', - 'MethodWrapperType', 'ModuleType', 'NoneType', 'NotImplementedType', - 'SimpleNamespace', 'TracebackType', 'UnionType', - 'WrapperDescriptorType', + 'FrameLocalsProxyType', + 'GeneratorType', 'GenericAlias', 'GetSetDescriptorType', + 'LambdaType', 'MappingProxyType', 'MemberDescriptorType', + 'MethodDescriptorType', 'MethodType', 'MethodWrapperType', + 'ModuleType', 'NoneType', 'NotImplementedType', 'SimpleNamespace', + 'TracebackType', 'UnionType', 'WrapperDescriptorType', } self.assertEqual(all_names, set(c_types.__all__)) self.assertEqual(all_names - c_only_names, set(py_types.__all__)) From 047f59eec675d44ea3eef834db21f6ae6d1c79bd Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 20 Jul 2025 16:58:44 +0100 Subject: [PATCH 26/27] trailing comma --- Lib/test/test_inspect/test_inspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 4c3ec825734b91..30e01b8cd87a75 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -5786,7 +5786,7 @@ def test_types_module_has_signatures(self): 'AsyncGeneratorType': {'athrow'}, 'CoroutineType': {'throw'}, 'GeneratorType': {'throw'}, - 'FrameLocalsProxyType': {'setdefault', 'pop', 'get'} + 'FrameLocalsProxyType': {'setdefault', 'pop', 'get'}, } self._test_module_has_signatures(types, unsupported_signature=unsupported_signature, From 63e263e578bb7a46a8b996a0e21c848907454b54 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 20 Jul 2025 18:44:08 +0200 Subject: [PATCH 27/27] Update frameobject.c Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Objects/frameobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index b1f07b78d28a35..97de1e06efe1b2 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -942,7 +942,7 @@ PyTypeObject PyFrameLocalsProxy_Type = { .tp_alloc = PyType_GenericAlloc, .tp_new = framelocalsproxy_new, .tp_free = PyObject_GC_Del, - .tp_doc = framelocalsproxy_doc + .tp_doc = framelocalsproxy_doc, }; PyObject * pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy