-
-
Notifications
You must be signed in to change notification settings - Fork 32k
gh-96151: Use a private name for passing builtins to dataclass #98143
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
Conversation
There's no indication that BUILTINS is a special name. Other names that are special to dataclass are all prefixed by an underscore. As mentioned in the issue, we can also avoid this locals dance altogether by using `().__class__.__base__` instead of `BUILTINS.object`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think such subtile change needs a test case :)
self.assertEqual(c.object, 'foo') | ||
self.assertEqual(c.BUILTINS, 5) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please create a separate function for this, and don't mix it in with existing tests. Maybe test_field_named_BUILTINS
or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review, made the change :-)
@@ -431,8 +431,8 @@ def _create_fn(name, args, body, *, globals=None, locals=None, | |||
# worries about external callers. | |||
if locals is None: | |||
locals = {} | |||
if 'BUILTINS' not in locals: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest using __BUILTINS__
because dunder names are supposed to be reserved for use by the stdlib.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before I commit this, I'd like to spend some time researching why this test is even present, instead of just unconditionally assigning to locals
. At the very least it could use a comment.
Also, I'm not sure that exposing all of builtins
in locals
is a good idea, versus just exposing builtins.object
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, looks like the relevant history is:
- https://github.com/python/cpython/pull/9518/files#diff-44ce2dc1c4922b2f5cf7631d8f86cc569a4c25eb003aaecdc2bc22eb9163d5f5L371-L375
- bpo-34213: frozen dataclass with "object" attr bug #8452
That is, I think this check was made dead in #9518, but wasn't noticed in that PR
(Also note that the comment at the top of _create_fn
is out of date: we do mutate locals, but not via exec)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do some double checking (locals
should all be created within dataclasses.py) and clean that up + change the PR to only pass along object
.
(I'll also note that there's still the inscrutable ().__class__.__base__
option on the table, in case we don't want to expose anything at all)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I audited all the call sites, it looks like there is one case where this check is not dead, but it's accidental.
Over here we reuse the same locals dict for two different _create_fn
calls:
Line 619 in 87b5fd9
locals = {'cls': cls, |
so the second time round we already have the entry for builtins in the dict. shrug
So my conclusion is:
a) It's safe to remove the check.
b) We should actually go a little further. Since we only need builtins for the frozen init, we should pass that in explicitly when creating __init__
and remove this from _create_fn
I've gone ahead and pushed this change to the PR
@JelleZijlstra I made the change, but note that if single underscore names are considered fair game for users, you can elicit all kinds of bad behaviour from dataclass. For example:
I'm happy to open an issue and fix all of these as well, if you think it's worth doing. |
If we’re only actually using setattr, since |
Maybe? I heard a rumour that |
About single underscores:
That's worth opening an issue for. |
This all looks great. I'm not sure if this will backport cleanly, but I've added the tags for 3.10 and 3.11 backports I see this as a bug fix that should be backported, at least to 3.11. |
Thanks @hauntsaninja for the PR, and @ericvsmith for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10. |
Thanks @hauntsaninja for the PR, and @ericvsmith for merging it 🌮🎉.. I'm working now to backport this PR to: 3.11. |
… This now allows for a field named BUILTIN (pythongh-98143) (cherry picked from commit 29f98b4) Co-authored-by: Shantanu <[email protected]>
GH-98899 is a backport of this pull request to the 3.10 branch. |
… This now allows for a field named BUILTIN (pythongh-98143) (cherry picked from commit 29f98b4) Co-authored-by: Shantanu <[email protected]>
GH-98900 is a backport of this pull request to the 3.11 branch. |
…. This now allows for a field named BUILTIN (gh-98143) (gh-98899) gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) (cherry picked from commit 29f98b4) Co-authored-by: Shantanu <[email protected]> Co-authored-by: Shantanu <[email protected]>
…. This now allows for a field named BUILTIN (gh-98143) (gh-98900) gh-96151: Use a private name for passing builtins to dataclass. This now allows for a field named BUILTIN (gh-98143) (cherry picked from commit 29f98b4) Co-authored-by: Shantanu <[email protected]> Co-authored-by: Shantanu <[email protected]>
This commit prefixes `__dataclass` to several things in the locals dict: - Names like _dflt_ (which cause trouble, see first test) - Names like _type_ (not known to be able to cause trouble) - _return_type (not known to able to cause trouble) - _HAS_DEFAULT_FACTORY (which causes trouble, see second test) In addition, this removes `MISSING` from the locals dict. As far as I can tell, this wasn't needed even in the initial implementation of dataclasses.py (and tests on that version passed with it removed). This is basically a continuation of python#96151, where fixing this was welcomed in python#98143 (comment)
…mes (#102032) This commit prefixes `__dataclass` to several things in the locals dict: - Names like `_dflt_` (which cause trouble, see first test) - Names like `_type_` (not known to be able to cause trouble) - `_return_type` (not known to able to cause trouble) - `_HAS_DEFAULT_FACTORY` (which causes trouble, see second test) In addition, this removes `MISSING` from the locals dict. As far as I can tell, this wasn't needed even in the initial implementation of dataclasses.py (and tests on that version passed with it removed). This makes me wary :-) This is basically a continuation of #96151, where fixing this was welcomed in #98143 (comment)
…ore names (python#102032) This commit prefixes `__dataclass` to several things in the locals dict: - Names like `_dflt_` (which cause trouble, see first test) - Names like `_type_` (not known to be able to cause trouble) - `_return_type` (not known to able to cause trouble) - `_HAS_DEFAULT_FACTORY` (which causes trouble, see second test) In addition, this removes `MISSING` from the locals dict. As far as I can tell, this wasn't needed even in the initial implementation of dataclasses.py (and tests on that version passed with it removed). This makes me wary :-) This is basically a continuation of python#96151, where fixing this was welcomed in python#98143 (comment)
…ore names (python#102032) This commit prefixes `__dataclass` to several things in the locals dict: - Names like `_dflt_` (which cause trouble, see first test) - Names like `_type_` (not known to be able to cause trouble) - `_return_type` (not known to able to cause trouble) - `_HAS_DEFAULT_FACTORY` (which causes trouble, see second test) In addition, this removes `MISSING` from the locals dict. As far as I can tell, this wasn't needed even in the initial implementation of dataclasses.py (and tests on that version passed with it removed). This makes me wary :-) This is basically a continuation of python#96151, where fixing this was welcomed in python#98143 (comment)
There's no indication that BUILTINS is a special name. Other names that are special to dataclass are all prefixed by an underscore.
As mentioned in the issue, we can also avoid this locals dance altogether by using
().__class__.__base__
instead ofBUILTINS.object
.BUILTINS
is not a valid field name for a frozen dataclass #96151