mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
bpo-34213: Allow dataclasses to work with a field named 'object'. (GH-8452)
This commit is contained in:
parent
65b5ef02ec
commit
4d12e4dc28
3 changed files with 58 additions and 1 deletions
|
@ -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,
|
||||||
# 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):
|
||||||
# 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 *
|
||||||
|
|
||||||
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):
|
||||||
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
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Allow frozen dataclasses to have a field named "object". Previously this conflicted with an internal use of "object".
|
Loading…
Add table
Add a link
Reference in a new issue