summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_dataclasses.py
diff options
context:
space:
mode:
authorEric V. Smith <ericvsmith@users.noreply.github.com>2021-04-26 00:42:39 (GMT)
committerGitHub <noreply@github.com>2021-04-26 00:42:39 (GMT)
commitc0280532dc8cab184a48c97e03e41cc8807f383d (patch)
treedaa3489cc4080666b4cb4eb1ffc6d815edbd61ae /Lib/test/test_dataclasses.py
parent7f8e072c6dc88d6973d81f8fd572c04c88e7e3d7 (diff)
downloadcpython-c0280532dc8cab184a48c97e03e41cc8807f383d.zip
cpython-c0280532dc8cab184a48c97e03e41cc8807f383d.tar.gz
cpython-c0280532dc8cab184a48c97e03e41cc8807f383d.tar.bz2
Add keyword-only fields to dataclasses. (GH=25608)
Diffstat (limited to 'Lib/test/test_dataclasses.py')
-rw-r--r--Lib/test/test_dataclasses.py159
1 files changed, 159 insertions, 0 deletions
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index f35f466..edb0848 100644
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -61,6 +61,7 @@ class TestCase(unittest.TestCase):
f"default=1,default_factory={MISSING!r}," \
"init=True,repr=False,hash=None," \
"compare=True,metadata=mappingproxy({})," \
+ f"kw_only={MISSING!r}," \
"_field_type=None)"
self.assertEqual(repr_output, expected_output)
@@ -3501,5 +3502,163 @@ class TestMatchArgs(unittest.TestCase):
self.assertEqual(C.__match_args__, ('z',))
+class TestKwArgs(unittest.TestCase):
+ def test_no_classvar_kwarg(self):
+ msg = 'field a is a ClassVar but specifies kw_only'
+ with self.assertRaisesRegex(TypeError, msg):
+ @dataclass
+ class A:
+ a: ClassVar[int] = field(kw_only=True)
+
+ with self.assertRaisesRegex(TypeError, msg):
+ @dataclass
+ class A:
+ a: ClassVar[int] = field(kw_only=False)
+
+ with self.assertRaisesRegex(TypeError, msg):
+ @dataclass(kw_only=True)
+ class A:
+ a: ClassVar[int] = field(kw_only=False)
+
+ def test_field_marked_as_kwonly(self):
+ #######################
+ # Using dataclass(kw_only=True)
+ @dataclass(kw_only=True)
+ class A:
+ a: int
+ self.assertTrue(fields(A)[0].kw_only)
+
+ @dataclass(kw_only=True)
+ class A:
+ a: int = field(kw_only=True)
+ self.assertTrue(fields(A)[0].kw_only)
+
+ @dataclass(kw_only=True)
+ class A:
+ a: int = field(kw_only=False)
+ self.assertFalse(fields(A)[0].kw_only)
+
+ #######################
+ # Using dataclass(kw_only=False)
+ @dataclass(kw_only=False)
+ class A:
+ a: int
+ self.assertFalse(fields(A)[0].kw_only)
+
+ @dataclass(kw_only=False)
+ class A:
+ a: int = field(kw_only=True)
+ self.assertTrue(fields(A)[0].kw_only)
+
+ @dataclass(kw_only=False)
+ class A:
+ a: int = field(kw_only=False)
+ self.assertFalse(fields(A)[0].kw_only)
+
+ #######################
+ # Not specifying dataclass(kw_only)
+ @dataclass
+ class A:
+ a: int
+ self.assertFalse(fields(A)[0].kw_only)
+
+ @dataclass
+ class A:
+ a: int = field(kw_only=True)
+ self.assertTrue(fields(A)[0].kw_only)
+
+ @dataclass
+ class A:
+ a: int = field(kw_only=False)
+ self.assertFalse(fields(A)[0].kw_only)
+
+ def test_match_args(self):
+ # kw fields don't show up in __match_args__.
+ @dataclass(kw_only=True)
+ class C:
+ a: int
+ self.assertEqual(C(a=42).__match_args__, ())
+
+ @dataclass
+ class C:
+ a: int
+ b: int = field(kw_only=True)
+ self.assertEqual(C(42, b=10).__match_args__, ('a',))
+
+ def test_KW_ONLY(self):
+ @dataclass
+ class A:
+ a: int
+ _: KW_ONLY
+ b: int
+ c: int
+ A(3, c=5, b=4)
+ msg = "takes 2 positional arguments but 4 were given"
+ with self.assertRaisesRegex(TypeError, msg):
+ A(3, 4, 5)
+
+
+ @dataclass(kw_only=True)
+ class B:
+ a: int
+ _: KW_ONLY
+ b: int
+ c: int
+ B(a=3, b=4, c=5)
+ msg = "takes 1 positional argument but 4 were given"
+ with self.assertRaisesRegex(TypeError, msg):
+ B(3, 4, 5)
+
+ # Explicitely make a field that follows KW_ONLY be non-keyword-only.
+ @dataclass
+ class C:
+ a: int
+ _: KW_ONLY
+ b: int
+ c: int = field(kw_only=False)
+ c = C(1, 2, b=3)
+ self.assertEqual(c.a, 1)
+ self.assertEqual(c.b, 3)
+ self.assertEqual(c.c, 2)
+ c = C(1, b=3, c=2)
+ self.assertEqual(c.a, 1)
+ self.assertEqual(c.b, 3)
+ self.assertEqual(c.c, 2)
+ c = C(1, b=3, c=2)
+ self.assertEqual(c.a, 1)
+ self.assertEqual(c.b, 3)
+ self.assertEqual(c.c, 2)
+ c = C(c=2, b=3, a=1)
+ self.assertEqual(c.a, 1)
+ self.assertEqual(c.b, 3)
+ self.assertEqual(c.c, 2)
+
+ def test_post_init(self):
+ @dataclass
+ class A:
+ a: int
+ _: KW_ONLY
+ b: InitVar[int]
+ c: int
+ d: InitVar[int]
+ def __post_init__(self, b, d):
+ raise CustomError(f'{b=} {d=}')
+ with self.assertRaisesRegex(CustomError, 'b=3 d=4'):
+ A(1, c=2, b=3, d=4)
+
+ @dataclass
+ class B:
+ a: int
+ _: KW_ONLY
+ b: InitVar[int]
+ c: int
+ d: InitVar[int]
+ def __post_init__(self, b, d):
+ self.a = b
+ self.c = d
+ b = B(1, c=2, b=3, d=4)
+ self.assertEqual(asdict(b), {'a': 3, 'c': 4})
+
+
if __name__ == '__main__':
unittest.main()