[3.11] gh-96151: Use a private name for passing builtins to dataclass. 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 29f98b46b7)

Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>

Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot) 2022-10-31 07:59:00 -07:00 committed by GitHub
parent 57dd11038f
commit ca24e496ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 13 additions and 5 deletions

View file

@ -412,13 +412,11 @@ def _recursive_repr(user_function):
def _create_fn(name, args, body, *, globals=None, locals=None, def _create_fn(name, args, body, *, globals=None, locals=None,
return_type=MISSING): return_type=MISSING):
# Note that we mutate locals when exec() is called. Caller # Note that we may mutate locals. Callers beware!
# beware! The only callers are internal to this module, so no # The only callers are internal to this module, so no
# worries about external callers. # worries about external callers.
if locals is None: if locals is None:
locals = {} locals = {}
if 'BUILTINS' not in locals:
locals['BUILTINS'] = builtins
return_annotation = '' return_annotation = ''
if return_type is not MISSING: if return_type is not MISSING:
locals['_return_type'] = return_type locals['_return_type'] = return_type
@ -444,7 +442,7 @@ def _field_assign(frozen, name, value, self_name):
# self_name is what "self" is called in this function: don't # self_name is what "self" is called in this function: don't
# hard-code "self", since that might be a field name. # hard-code "self", since that might be a field name.
if frozen: if frozen:
return f'BUILTINS.object.__setattr__({self_name},{name!r},{value})' return f'__dataclass_builtins_object__.__setattr__({self_name},{name!r},{value})'
return f'{self_name}.{name}={value}' return f'{self_name}.{name}={value}'
@ -551,6 +549,7 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init,
locals.update({ locals.update({
'MISSING': MISSING, 'MISSING': MISSING,
'_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY, '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY,
'__dataclass_builtins_object__': object,
}) })
body_lines = [] body_lines = []

View file

@ -231,6 +231,14 @@ class TestCase(unittest.TestCase):
c = C('foo') c = C('foo')
self.assertEqual(c.object, 'foo') self.assertEqual(c.object, 'foo')
def test_field_named_BUILTINS_frozen(self):
# gh-96151
@dataclass(frozen=True)
class C:
BUILTINS: int
c = C(5)
self.assertEqual(c.BUILTINS, 5)
def test_field_named_like_builtin(self): def test_field_named_like_builtin(self):
# Attribute names can shadow built-in names # Attribute names can shadow built-in names
# since code generation is used. # since code generation is used.

View file

@ -0,0 +1 @@
Allow ``BUILTINS`` to be a valid field name for frozen dataclasses.