summaryrefslogtreecommitdiff
path: root/Lib/test/test_dataclasses.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_dataclasses.py')
-rw-r--r--Lib/test/test_dataclasses.py116
1 files changed, 67 insertions, 49 deletions
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index b20103bdce..7c1d9c568f 100644
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -4,10 +4,12 @@
from dataclasses import *
+import abc
import pickle
import inspect
import builtins
import unittest
+from textwrap import dedent
from unittest.mock import Mock
from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional
from typing import get_type_hints
@@ -561,17 +563,17 @@ class TestCase(unittest.TestCase):
self.assertEqual(len(the_fields), 3)
self.assertEqual(the_fields[0].name, 'x')
- self.assertEqual(the_fields[0].type, int)
+ self.assertEqual(the_fields[0].type, 'int')
self.assertFalse(hasattr(C, 'x'))
self.assertTrue (the_fields[0].init)
self.assertTrue (the_fields[0].repr)
self.assertEqual(the_fields[1].name, 'y')
- self.assertEqual(the_fields[1].type, str)
+ self.assertEqual(the_fields[1].type, 'str')
self.assertIsNone(getattr(C, 'y'))
self.assertFalse(the_fields[1].init)
self.assertTrue (the_fields[1].repr)
self.assertEqual(the_fields[2].name, 'z')
- self.assertEqual(the_fields[2].type, str)
+ self.assertEqual(the_fields[2].type, 'str')
self.assertFalse(hasattr(C, 'z'))
self.assertTrue (the_fields[2].init)
self.assertFalse(the_fields[2].repr)
@@ -757,11 +759,11 @@ class TestCase(unittest.TestCase):
def validate_class(cls):
# First, check __annotations__, even though they're not
# function annotations.
- self.assertEqual(cls.__annotations__['i'], int)
- self.assertEqual(cls.__annotations__['j'], str)
- self.assertEqual(cls.__annotations__['k'], F)
- self.assertEqual(cls.__annotations__['l'], float)
- self.assertEqual(cls.__annotations__['z'], complex)
+ self.assertEqual(cls.__annotations__['i'], 'int')
+ self.assertEqual(cls.__annotations__['j'], 'str')
+ self.assertEqual(cls.__annotations__['k'], 'F')
+ self.assertEqual(cls.__annotations__['l'], 'float')
+ self.assertEqual(cls.__annotations__['z'], 'complex')
# Verify __init__.
@@ -776,22 +778,22 @@ class TestCase(unittest.TestCase):
self.assertEqual(param.name, 'self')
param = next(params)
self.assertEqual(param.name, 'i')
- self.assertIs (param.annotation, int)
+ self.assertIs (param.annotation, 'int')
self.assertEqual(param.default, inspect.Parameter.empty)
self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_OR_KEYWORD)
param = next(params)
self.assertEqual(param.name, 'j')
- self.assertIs (param.annotation, str)
+ self.assertIs (param.annotation, 'str')
self.assertEqual(param.default, inspect.Parameter.empty)
self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_OR_KEYWORD)
param = next(params)
self.assertEqual(param.name, 'k')
- self.assertIs (param.annotation, F)
+ self.assertIs (param.annotation, 'F')
# 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)
+ self.assertIs (param.annotation, 'float')
# 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)
@@ -2805,13 +2807,10 @@ class TestDescriptors(unittest.TestCase):
class TestStringAnnotations(unittest.TestCase):
def test_classvar(self):
- # Some expressions recognized as ClassVar really aren't. But
- # if you're using string annotations, it's not an exact
- # science.
# These tests assume that both "import typing" and "from
# typing import *" have been run in this file.
for typestr in ('ClassVar[int]',
- 'ClassVar [int]'
+ 'ClassVar [int]',
' ClassVar [int]',
'ClassVar',
' ClassVar ',
@@ -2822,17 +2821,15 @@ class TestStringAnnotations(unittest.TestCase):
'typing. ClassVar[str]',
'typing.ClassVar [str]',
'typing.ClassVar [ str]',
-
+ # Double stringified
+ '"typing.ClassVar[int]"',
# Not syntactically valid, but these will
- # be treated as ClassVars.
+ # be treated as ClassVars.
'typing.ClassVar.[int]',
'typing.ClassVar+',
):
with self.subTest(typestr=typestr):
- @dataclass
- class C:
- x: typestr
-
+ C = dataclass(type("C", (), {"__annotations__": {"x": typestr}}))
# x is a ClassVar, so C() takes no args.
C()
@@ -2853,9 +2850,7 @@ class TestStringAnnotations(unittest.TestCase):
'typingxClassVar[str]',
):
with self.subTest(typestr=typestr):
- @dataclass
- class C:
- x: typestr
+ C = dataclass(type("C", (), {"__annotations__": {"x": typestr}}))
# x is not a ClassVar, so C() takes one arg.
self.assertEqual(C(10).x, 10)
@@ -2875,16 +2870,16 @@ class TestStringAnnotations(unittest.TestCase):
'dataclasses. InitVar[str]',
'dataclasses.InitVar [str]',
'dataclasses.InitVar [ str]',
-
+ # Double stringified
+ '"dataclasses.InitVar[int]"',
# Not syntactically valid, but these will
# be treated as InitVars.
'dataclasses.InitVar.[int]',
'dataclasses.InitVar+',
):
with self.subTest(typestr=typestr):
- @dataclass
- class C:
- x: typestr
+ C = dataclass(type("C", (), {"__annotations__": {"x": typestr}}))
+
# x is an InitVar, so doesn't create a member.
with self.assertRaisesRegex(AttributeError,
@@ -2898,30 +2893,22 @@ class TestStringAnnotations(unittest.TestCase):
'typing.xInitVar[int]',
):
with self.subTest(typestr=typestr):
- @dataclass
- class C:
- x: typestr
+ C = dataclass(type("C", (), {"__annotations__": {"x": typestr}}))
# x is not an InitVar, so there will be a member x.
self.assertEqual(C(10).x, 10)
def test_classvar_module_level_import(self):
from test import dataclass_module_1
- from test import dataclass_module_1_str
from test import dataclass_module_2
- from test import dataclass_module_2_str
- for m in (dataclass_module_1, dataclass_module_1_str,
- dataclass_module_2, dataclass_module_2_str,
- ):
+ for m in (dataclass_module_1,
+ dataclass_module_2):
with self.subTest(m=m):
# There's a difference in how the ClassVars are
# interpreted when using string annotations or
# not. See the imported modules for details.
- if m.USING_STRINGS:
- c = m.CV(10)
- else:
- c = m.CV()
+ c = m.CV(10)
self.assertEqual(c.cv0, 20)
@@ -2937,14 +2924,9 @@ class TestStringAnnotations(unittest.TestCase):
# not an instance field.
getattr(c, field_name)
- if m.USING_STRINGS:
- # iv4 is interpreted as a normal field.
- self.assertIn('not_iv4', c.__dict__)
- self.assertEqual(c.not_iv4, 4)
- else:
- # iv4 is interpreted as an InitVar, so it
- # won't exist on the instance.
- self.assertNotIn('not_iv4', c.__dict__)
+ # iv4 is interpreted as a normal field.
+ self.assertIn('not_iv4', c.__dict__)
+ self.assertEqual(c.not_iv4, 4)
def test_text_annotations(self):
from test import dataclass_textanno
@@ -3332,6 +3314,42 @@ class TestReplace(unittest.TestCase):
## replace(c, x=5)
+class TestAbstract(unittest.TestCase):
+ def test_abc_implementation(self):
+ class Ordered(abc.ABC):
+ @abc.abstractmethod
+ def __lt__(self, other):
+ pass
+
+ @abc.abstractmethod
+ def __le__(self, other):
+ pass
+
+ @dataclass(order=True)
+ class Date(Ordered):
+ year: int
+ month: 'Month'
+ day: 'int'
+
+ self.assertFalse(inspect.isabstract(Date))
+ self.assertGreater(Date(2020,12,25), Date(2020,8,31))
+
+ def test_maintain_abc(self):
+ class A(abc.ABC):
+ @abc.abstractmethod
+ def foo(self):
+ pass
+
+ @dataclass
+ class Date(A):
+ year: int
+ month: 'Month'
+ day: 'int'
+
+ self.assertTrue(inspect.isabstract(Date))
+ msg = 'class Date with abstract method foo'
+ self.assertRaisesRegex(TypeError, msg, Date)
+
if __name__ == '__main__':
unittest.main()