Kaydet (Commit) 4d12e4dc authored tarafından Vadim Pushtaev's avatar Vadim Pushtaev Kaydeden (comit) Eric V. Smith

bpo-34213: Allow dataclasses to work with a field named 'object'. (GH-8452)

üst 65b5ef02
...@@ -4,6 +4,7 @@ import copy ...@@ -4,6 +4,7 @@ import copy
import types import types
import inspect import inspect
import keyword import keyword
import builtins
__all__ = ['dataclass', __all__ = ['dataclass',
'field', 'field',
...@@ -343,6 +344,11 @@ def _create_fn(name, args, body, *, globals=None, locals=None, ...@@ -343,6 +344,11 @@ def _create_fn(name, args, body, *, globals=None, locals=None,
# worries about external callers. # worries about external callers.
if locals is None: if locals is None:
locals = {} locals = {}
# __builtins__ may be the "builtins" module or
# the value of its "__dict__",
# so make sure "__builtins__" is the module.
if globals is not None and '__builtins__' not in globals:
globals['__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
...@@ -365,7 +371,7 @@ def _field_assign(frozen, name, value, self_name): ...@@ -365,7 +371,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'object.__setattr__({self_name},{name!r},{value})' return f'__builtins__.object.__setattr__({self_name},{name!r},{value})'
return f'{self_name}.{name}={value}' return f'{self_name}.{name}={value}'
......
...@@ -6,6 +6,7 @@ from dataclasses import * ...@@ -6,6 +6,7 @@ from dataclasses import *
import pickle import pickle
import inspect import inspect
import builtins
import unittest import unittest
from unittest.mock import Mock from unittest.mock import Mock
from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional
...@@ -192,6 +193,55 @@ class TestCase(unittest.TestCase): ...@@ -192,6 +193,55 @@ class TestCase(unittest.TestCase):
first = next(iter(sig.parameters)) first = next(iter(sig.parameters))
self.assertEqual('self', first) self.assertEqual('self', first)
def test_field_named_object(self):
@dataclass
class C:
object: str
c = C('foo')
self.assertEqual(c.object, 'foo')
def test_field_named_object_frozen(self):
@dataclass(frozen=True)
class C:
object: str
c = C('foo')
self.assertEqual(c.object, 'foo')
def test_field_named_like_builtin(self):
# Attribute names can shadow built-in names
# since code generation is used.
# Ensure that this is not happening.
exclusions = {'None', 'True', 'False'}
builtins_names = sorted(
b for b in builtins.__dict__.keys()
if not b.startswith('__') and b not in exclusions
)
attributes = [(name, str) for name in builtins_names]
C = make_dataclass('C', attributes)
c = C(*[name for name in builtins_names])
for name in builtins_names:
self.assertEqual(getattr(c, name), name)
def test_field_named_like_builtin_frozen(self):
# Attribute names can shadow built-in names
# since code generation is used.
# Ensure that this is not happening
# for frozen data classes.
exclusions = {'None', 'True', 'False'}
builtins_names = sorted(
b for b in builtins.__dict__.keys()
if not b.startswith('__') and b not in exclusions
)
attributes = [(name, str) for name in builtins_names]
C = make_dataclass('C', attributes, frozen=True)
c = C(*[name for name in builtins_names])
for name in builtins_names:
self.assertEqual(getattr(c, name), name)
def test_0_field_compare(self): def test_0_field_compare(self):
# Ensure that order=False is the default. # Ensure that order=False is the default.
@dataclass @dataclass
......
Allow frozen dataclasses to have a field named "object". Previously this conflicted with an internal use of "object".
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment