Turns out it is correctly registered as a subclass of Mapping of Python 3.13.2 (at least) - which was the original report - but then it should be exposed in types.
Bug description:
Although the FrameLocalsProxy object created when retrieving the .f_locals attribute
from a frame is a complete mutable mapping, and created so it could be a drop-in,
backwards compatible replacement for the plain dict that was retrieved from
there prior to Python 3.13, it can't be tested as a Mapping in either
dynamic or static checking.
In practical terms, if I have a function that will support receiving a mapping, and into which I would pass a FrameLocalsProxy, static checkers would fail.
Admittedly, it can't conform with MutableMapping since it doesn't make sense to try to delete items from such a proxy - although values can be replaced and added. In accord, it lacks clear and popitem methods -
Therefore one trying to accurately trying to static type a method that could receive a FrameLocalsProxy one intends to modify will have to resort to protocols. But that doesn't need to be the case for Mapping, since it is fully conformant.
Also, otherwise code which wants to test in runtime if an object is a mapping should be able to know that with an isinstance check.
I am willing to contribute this change if it is judged correct.
I agree that this should probably be a Mapping. On a side note, we should probably also expose the type in types? So we don't have to do FrameLocalsProxy = (lambda: type(sys._getframe().f_locals)().
On a side note, we should probably also expose the type in types?
When exposing something, it means that it would be really hard to remove. I thought that localsproxy for now is an implementation detail, not a documented contract 🤔
I think as long as we document it as "the type of f_locals", we can expose it without worrying too much. If we change the type of f_locals someday, we can just alias FrameLocalsProxy to whatever that type is.
Okay so I just took a look at the code. Which 3.13 did you use? This should be fixed in #120101 and backported to 3.13 prior to it's first official release. In theory this should work on 3.13.0. I confirmed that it works properly on 3.13.4 and main.
I'll keep this issue open because we probably still want to expose the type, but FrameLocalsProxy is already a Mapping.
Indeed - I think I ran the test in an old virtualenv with a beta 3.13 build around here.
So, it is resolved for FrameLocalsMapping being a correct mapping - and the PEP itself explicitly lays the difference towards a MutableMapping.
Exposing it to types should be up to consideration, then -
I've updated the description - but I am not sure if this should be moved from "bug" to "feature request" (or if one could just add the feature in the main branch and close the issue :-) )
Activity
gaogaotiantian commented on Jul 10, 2025
I agree that this should probably be a Mapping. On a side note, we should probably also expose the type in types? So we don't have to do FrameLocalsProxy = (lambda: type(sys._getframe().f_locals)().
jsbueno commented on Jul 10, 2025
Given that types does exactly this kind of thing for other seldom needed types, it would certainly be handy.
sobolevn commented on Jul 10, 2025
When exposing something, it means that it would be really hard to remove. I thought that localsproxy for now is an implementation detail, not a documented contract 🤔
gaogaotiantian commented on Jul 10, 2025
Well it's already part of the C-API - https://docs.python.org/3/c-api/frame.html#c.PyFrameLocalsProxy_Type
ZeroIntensity commented on Jul 11, 2025
I think as long as we document it as "the type of f_locals", we can expose it without worrying too much. If we change the type of f_locals someday, we can just alias FrameLocalsProxy to whatever that type is.
gaogaotiantian commented on Jul 12, 2025
Okay so I just took a look at the code. Which 3.13 did you use? This should be fixed in #120101 and backported to 3.13 prior to it's first official release. In theory this should work on 3.13.0. I confirmed that it works properly on 3.13.4 and main.
I'll keep this issue open because we probably still want to expose the type, but FrameLocalsProxy is already a Mapping.
jsbueno commented on Jul 15, 2025
Indeed - I think I ran the test in an old virtualenv with a beta 3.13 build around here.
So, it is resolved for FrameLocalsMapping being a correct mapping - and the PEP itself explicitly lays the difference towards a MutableMapping.
Exposing it to types should be up to consideration, then -
I've updated the description - but I am not sure if this should be moved from "bug" to "feature request" (or if one could just add the feature in the main branch and close the issue :-) )
gh-136492: Add `FrameLocalsProxyType` to `types` (GH-136546)
pythongh-136492: Add `FrameLocalsProxyType` to `types` (pythonGH-136546)
pythongh-136492: Add `FrameLocalsProxyType` to `types` (pythonGH-136546)