-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
namedtuple's __new__.__globals__['__builtins__'] is None #87268
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
Comments
When creating a namedtuple such as this one: from collections import namedtuple
class C(namedtuple('C', ('hello', 'world'))):
pass
print(C.__new__.__globals__) The globals' dict of __new__ contains a "__builtins__" key which is set to None in collections/init.py: namespace = {
'_tuple_new': tuple_new,
'__builtins__': None,
'__name__': f'namedtuple_{typename}',
} When such globals are used with eval(), it will raise a TypeError such as: >>> eval('X', {'__builtins__': None})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
TypeError: 'NoneType' object is not subscriptable If an empty dict was used instead, we get the expected exception: >>> eval('X', {'__builtins__': {}})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'X' is not defined Given that both ways allow preventing references to any builtin, please consider switching to an empty dict. Also, even though this is documented as implementation detail, this would agree more with the current documentation stating:
|
Thanks for the report. I'll look at it in detail this evening. Off-hand the suggest sounds reasonable. |
Out of curiosity, how did you find this? Did it arise in the course of trying to solve a real problem or were you just reading the code and and thought you might do it differently? Unless there's a real problem, I prefer None because it is immutable (safer), because it doesn't incur the time and memory cost of creating a new object, and because it does a good job of indicating that builtins are shut-off and not intended to be accessed. The primary reason the line is there at all is to make eval() as safe as possible. There is no public named tuple functionality that depends on it, so no user should ever encounter it unless they are just investigating implementation details. In particular, they should never see the error message in your post. |
I did hit the issue while porting a tool to Python 3.9: It basically infers valid Python expressions from type annotations (some sort
It implements PEP-563 to evaluate the annotions, which describes how to get the Maybe an alternative would be to use a module-level types.MappingProxyType |
Wow, your project looks super interesting. |
Okay, it's done. Thanks for the motivating use case. |
Thanks for looking into this issue |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: