bpo-44015: dataclasses should allow KW_ONLY to be specified only once per class (GH-25841)

bpo-44015: Raise a TypeError if KW_ONLY is specified more than once.
This commit is contained in:
Eric V. Smith 2021-05-03 03:24:53 -04:00 committed by GitHub
parent 72720a2639
commit 99ad742ea9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 0 deletions

View file

@ -930,6 +930,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
# we can.
cls_fields = []
# Get a reference to this module for the _is_kw_only() test.
KW_ONLY_seen = False
dataclasses = sys.modules[__name__]
for name, type in cls_annotations.items():
# See if this is a marker to change the value of kw_only.
@ -939,6 +940,10 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
_is_kw_only))):
# Switch the default to kw_only=True, and ignore this
# annotation: it's not a real field.
if KW_ONLY_seen:
raise TypeError(f'{name!r} is KW_ONLY, but KW_ONLY '
'has already been specified')
KW_ONLY_seen = True
kw_only = True
else:
# Otherwise it's a field of some type.

View file

@ -3699,6 +3699,83 @@ class C:
self.assertEqual(c.b, 3)
self.assertEqual(c.c, 2)
def test_KW_ONLY_as_string(self):
@dataclass
class A:
a: int
_: 'dataclasses.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)
def test_KW_ONLY_twice(self):
msg = "'Y' is KW_ONLY, but KW_ONLY has already been specified"
with self.assertRaisesRegex(TypeError, msg):
@dataclass
class A:
a: int
X: KW_ONLY
Y: KW_ONLY
b: int
c: int
with self.assertRaisesRegex(TypeError, msg):
@dataclass
class A:
a: int
X: KW_ONLY
b: int
Y: KW_ONLY
c: int
with self.assertRaisesRegex(TypeError, msg):
@dataclass
class A:
a: int
X: KW_ONLY
b: int
c: int
Y: KW_ONLY
# But this usage is okay, since it's not using KW_ONLY.
@dataclass
class A:
a: int
_: KW_ONLY
b: int
c: int = field(kw_only=True)
# And if inheriting, it's okay.
@dataclass
class A:
a: int
_: KW_ONLY
b: int
c: int
@dataclass
class B(A):
_: KW_ONLY
d: int
# Make sure the error is raised in a derived class.
with self.assertRaisesRegex(TypeError, msg):
@dataclass
class A:
a: int
_: KW_ONLY
b: int
c: int
@dataclass
class B(A):
X: KW_ONLY
d: int
Y: KW_ONLY
def test_post_init(self):
@dataclass
class A:

View file

@ -0,0 +1 @@
In @dataclass(), raise a TypeError if KW_ONLY is specified more than once.