mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +00:00
Add keyword-only fields to dataclasses. (GH=25608)
This commit is contained in:
parent
7f8e072c6d
commit
c0280532dc
4 changed files with 298 additions and 38 deletions
|
@ -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()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue