-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
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 :)
| BUILTINS: int # gh-96151 | ||
| c = C('foo', 5) | ||
| 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 :-)
| # 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 <12621235+hauntsaninja@users.noreply.github.com>
|
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 <12621235+hauntsaninja@users.noreply.github.com>
|
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 <12621235+hauntsaninja@users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
…. 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 <12621235+hauntsaninja@users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
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.BUILTINSis not a valid field name for a frozen dataclass #96151