Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4d12e4d

Browse files
VadimPushtaevericvsmith
authored andcommitted
bpo-34213: Allow dataclasses to work with a field named 'object'. (GH-8452)
1 parent 65b5ef0 commit 4d12e4d

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

Lib/dataclasses.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import types
55
import inspect
66
import keyword
7+
import builtins
78

89
__all__ = ['dataclass',
910
'field',
@@ -343,6 +344,11 @@ def _create_fn(name, args, body, *, globals=None, locals=None,
343344
# worries about external callers.
344345
if locals is None:
345346
locals = {}
347+
# __builtins__ may be the "builtins" module or
348+
# the value of its "__dict__",
349+
# so make sure "__builtins__" is the module.
350+
if globals is not None and '__builtins__' not in globals:
351+
globals['__builtins__'] = builtins
346352
return_annotation = ''
347353
if return_type is not MISSING:
348354
locals['_return_type'] = return_type
@@ -365,7 +371,7 @@ def _field_assign(frozen, name, value, self_name):
365371
# self_name is what "self" is called in this function: don't
366372
# hard-code "self", since that might be a field name.
367373
if frozen:
368-
return f'object.__setattr__({self_name},{name!r},{value})'
374+
return f'__builtins__.object.__setattr__({self_name},{name!r},{value})'
369375
return f'{self_name}.{name}={value}'
370376

371377

Lib/test/test_dataclasses.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import pickle
88
import inspect
9+
import builtins
910
import unittest
1011
from unittest.mock import Mock
1112
from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional
@@ -192,6 +193,55 @@ class C:
192193
first = next(iter(sig.parameters))
193194
self.assertEqual('self', first)
194195

196+
def test_field_named_object(self):
197+
@dataclass
198+
class C:
199+
object: str
200+
c = C('foo')
201+
self.assertEqual(c.object, 'foo')
202+
203+
def test_field_named_object_frozen(self):
204+
@dataclass(frozen=True)
205+
class C:
206+
object: str
207+
c = C('foo')
208+
self.assertEqual(c.object, 'foo')
209+
210+
def test_field_named_like_builtin(self):
211+
# Attribute names can shadow built-in names
212+
# since code generation is used.
213+
# Ensure that this is not happening.
214+
exclusions = {'None', 'True', 'False'}
215+
builtins_names = sorted(
216+
b for b in builtins.__dict__.keys()
217+
if not b.startswith('__') and b not in exclusions
218+
)
219+
attributes = [(name, str) for name in builtins_names]
220+
C = make_dataclass('C', attributes)
221+
222+
c = C(*[name for name in builtins_names])
223+
224+
for name in builtins_names:
225+
self.assertEqual(getattr(c, name), name)
226+
227+
def test_field_named_like_builtin_frozen(self):
228+
# Attribute names can shadow built-in names
229+
# since code generation is used.
230+
# Ensure that this is not happening
231+
# for frozen data classes.
232+
exclusions = {'None', 'True', 'False'}
233+
builtins_names = sorted(
234+
b for b in builtins.__dict__.keys()
235+
if not b.startswith('__') and b not in exclusions
236+
)
237+
attributes = [(name, str) for name in builtins_names]
238+
C = make_dataclass('C', attributes, frozen=True)
239+
240+
c = C(*[name for name in builtins_names])
241+
242+
for name in builtins_names:
243+
self.assertEqual(getattr(c, name), name)
244+
195245
def test_0_field_compare(self):
196246
# Ensure that order=False is the default.
197247
@dataclass
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Allow frozen dataclasses to have a field named "object". Previously this conflicted with an internal use of "object".

0 commit comments

Comments
 (0)