Skip to content

Minor fixes to dataclass tests. Also, re-enable a test for ClassVars with default_factory. #6243

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

Merged
merged 1 commit into from
Mar 26, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 41 additions & 42 deletions Lib/test/test_dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ def __eq__(self):
self.assertEqual(hash(C(10)), hash((10,)))

# Creating this class should generate an exception, because
# __hash__ exists and is not None, which it would be if it had
# been auto-generated do due __eq__ being defined.
# __hash__ exists and is not None, which it would be if it
# had been auto-generated due to __eq__ being defined.
with self.assertRaisesRegex(TypeError,
'Cannot overwrite attribute __hash__'):
@dataclass(unsafe_hash=True)
Expand All @@ -145,7 +145,6 @@ def __eq__(self):
def __hash__(self):
pass


def test_overwrite_fields_in_derived_class(self):
# Note that x from C1 replaces x in Base, but the order remains
# the same as defined in Base.
Expand Down Expand Up @@ -624,7 +623,7 @@ class C:
self.assertIs(o1.x, o2.x)

def test_no_options(self):
# call with dataclass()
# Call with dataclass().
@dataclass()
class C:
x: int
Expand All @@ -639,7 +638,7 @@ class Point:
y: int
self.assertNotEqual(Point(1, 2), (1, 2))

# And that we can't compare to another unrelated dataclass
# And that we can't compare to another unrelated dataclass.
@dataclass
class C:
x: int
Expand All @@ -664,7 +663,7 @@ class Date:
self.assertNotEqual(Point3D(2017, 6, 3), Date(2017, 6, 3))
self.assertNotEqual(Point3D(1, 2, 3), (1, 2, 3))

# Make sure we can't unpack
# Make sure we can't unpack.
with self.assertRaisesRegex(TypeError, 'unpack'):
x, y, z = Point3D(4, 5, 6)

Expand Down Expand Up @@ -695,7 +694,7 @@ def validate_class(cls):
# Verify __init__.

signature = inspect.signature(cls.__init__)
# Check the return type, should be None
# Check the return type, should be None.
self.assertIs(signature.return_annotation, None)

# Check each parameter.
Expand All @@ -716,12 +715,12 @@ def validate_class(cls):
param = next(params)
self.assertEqual(param.name, 'k')
self.assertIs (param.annotation, F)
# Don't test for the default, since it's set to MISSING
# Don't test for the default, since it's set to MISSING.
self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_OR_KEYWORD)
param = next(params)
self.assertEqual(param.name, 'l')
self.assertIs (param.annotation, float)
# Don't test for the default, since it's set to MISSING
# Don't test for the default, since it's set to MISSING.
self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_OR_KEYWORD)
self.assertRaises(StopIteration, next, params)

Expand Down Expand Up @@ -867,7 +866,7 @@ def __post_init__(self):

self.assertEqual(C().x, 5)

# Now call super(), and it will raise
# Now call super(), and it will raise.
@dataclass
class C(B):
def __post_init__(self):
Expand Down Expand Up @@ -928,8 +927,8 @@ class C:

c = C(5)
self.assertEqual(repr(c), 'TestCase.test_class_var.<locals>.C(x=5, y=10)')
self.assertEqual(len(fields(C)), 2) # We have 2 fields
self.assertEqual(len(C.__annotations__), 5) # And 3 ClassVars
self.assertEqual(len(fields(C)), 2) # We have 2 fields.
self.assertEqual(len(C.__annotations__), 5) # And 3 ClassVars.
self.assertEqual(c.z, 1000)
self.assertEqual(c.w, 2000)
self.assertEqual(c.t, 3000)
Expand Down Expand Up @@ -1205,14 +1204,13 @@ class D(C):
d = D(4, 5)
self.assertEqual((d.x, d.z), (4, 5))


def x_test_classvar_default_factory(self):
# XXX: it's an error for a ClassVar to have a factory function
@dataclass
class C:
x: ClassVar[int] = field(default_factory=int)

self.assertIs(C().x, int)
def test_classvar_default_factory(self):
# It's an error for a ClassVar to have a factory function.
with self.assertRaisesRegex(TypeError,
'cannot have a default factory'):
@dataclass
class C:
x: ClassVar[int] = field(default_factory=int)

def test_is_dataclass(self):
class NotDataClass:
Expand Down Expand Up @@ -1264,7 +1262,7 @@ class C: pass
fields(C())

def test_helper_asdict(self):
# Basic tests for asdict(), it should return a new dictionary
# Basic tests for asdict(), it should return a new dictionary.
@dataclass
class C:
x: int
Expand All @@ -1279,7 +1277,7 @@ class C:
self.assertIs(type(asdict(c)), dict)

def test_helper_asdict_raises_on_classes(self):
# asdict() should raise on a class object
# asdict() should raise on a class object.
@dataclass
class C:
x: int
Expand Down Expand Up @@ -1377,7 +1375,7 @@ class C:
self.assertIs(type(d), OrderedDict)

def test_helper_astuple(self):
# Basic tests for astuple(), it should return a new tuple
# Basic tests for astuple(), it should return a new tuple.
@dataclass
class C:
x: int
Expand All @@ -1392,7 +1390,7 @@ class C:
self.assertIs(type(astuple(c)), tuple)

def test_helper_astuple_raises_on_classes(self):
# astuple() should raise on a class object
# astuple() should raise on a class object.
@dataclass
class C:
x: int
Expand Down Expand Up @@ -1489,7 +1487,7 @@ def nt(lst):
self.assertIs(type(t), NT)

def test_dynamic_class_creation(self):
cls_dict = {'__annotations__': {'x':int, 'y':int},
cls_dict = {'__annotations__': {'x': int, 'y': int},
}

# Create the class.
Expand All @@ -1502,7 +1500,7 @@ def test_dynamic_class_creation(self):
self.assertEqual(asdict(cls(1, 2)), {'x': 1, 'y': 2})

def test_dynamic_class_creation_using_field(self):
cls_dict = {'__annotations__': {'x':int, 'y':int},
cls_dict = {'__annotations__': {'x': int, 'y': int},
'y': field(default=5),
}

Expand Down Expand Up @@ -1569,8 +1567,8 @@ class C:

def test_alternate_classmethod_constructor(self):
# Since __post_init__ can't take params, use a classmethod
# alternate constructor. This is mostly an example to show how
# to use this technique.
# alternate constructor. This is mostly an example to show
# how to use this technique.
@dataclass
class C:
x: int
Expand Down Expand Up @@ -1604,7 +1602,7 @@ def test_field_metadata_mapping(self):
class C:
i: int = field(metadata=0)

# Make sure an empty dict works
# Make sure an empty dict works.
@dataclass
class C:
i: int = field(metadata={})
Expand Down Expand Up @@ -1666,7 +1664,7 @@ class LabeledBox(Generic[T]):
self.assertEqual(box.content, 42)
self.assertEqual(box.label, '<unknown>')

# subscripting the resulting class should work, etc.
# Subscripting the resulting class should work, etc.
Alias = List[LabeledBox[int]]

def test_generic_extending(self):
Expand Down Expand Up @@ -1931,7 +1929,7 @@ class B:
with self.assertRaisesRegex(TypeError,
"'f' is a field but has no type annotation"):
# This is still an error: make sure we don't pick up the
# type annotation in the base class.
# type annotation in the base class.
@dataclass
class C(B):
f = field()
Expand All @@ -1944,7 +1942,7 @@ class B:
with self.assertRaisesRegex(TypeError,
"'f' is a field but has no type annotation"):
# This is still an error: make sure we don't pick up the
# type annotation in the base class.
# type annotation in the base class.
@dataclass
class C(B):
f = field()
Expand Down Expand Up @@ -2178,7 +2176,7 @@ def __repr__(self):

class TestFrozen(unittest.TestCase):
def test_overwriting_frozen(self):
# frozen uses __setattr__ and __delattr__
# frozen uses __setattr__ and __delattr__.
with self.assertRaisesRegex(TypeError,
'Cannot overwrite attribute __setattr__'):
@dataclass(frozen=True)
Expand Down Expand Up @@ -2473,16 +2471,16 @@ class C:

def test_hash_no_args(self):
# Test dataclasses with no hash= argument. This exists to
# make sure that if the @dataclass parameter name is changed
# or the non-default hashing behavior changes, the default
# hashability keeps working the same way.
# make sure that if the @dataclass parameter name is changed
# or the non-default hashing behavior changes, the default
# hashability keeps working the same way.

class Base:
def __hash__(self):
return 301

# If frozen or eq is None, then use the default value (do not
# specify any value in the decorator).
# specify any value in the decorator).
for frozen, eq, base, expected in [
(None, None, object, 'unhashable'),
(None, None, Base, 'unhashable'),
Expand Down Expand Up @@ -2534,9 +2532,9 @@ class C(base):

elif expected == 'object':
# I'm not sure what test to use here. object's
# hash isn't based on id(), so calling hash()
# won't tell us much. So, just check the function
# used is object's.
# hash isn't based on id(), so calling hash()
# won't tell us much. So, just check the
# function used is object's.
self.assertIs(C.__hash__, object.__hash__)

elif expected == 'tuple':
Expand Down Expand Up @@ -2665,8 +2663,9 @@ class C:
__slots__ = ('x',)
x: Any

# There was a bug where a variable in a slot was assumed
# to also have a default value (of type types.MemberDescriptorType).
# There was a bug where a variable in a slot was assumed to
# also have a default value (of type
# types.MemberDescriptorType).
with self.assertRaisesRegex(TypeError,
r"__init__\(\) missing 1 required positional argument: 'x'"):
C()
Expand Down