summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_dataclasses.py
diff options
context:
space:
mode:
authorEric V. Smith <ericvsmith@users.noreply.github.com>2018-03-19 00:40:34 (GMT)
committerGitHub <noreply@github.com>2018-03-19 00:40:34 (GMT)
commitf199bc655eb50c28e94010714629b376bbbd077b (patch)
tree2f6d64470055592c9b7d1e27bda7cd4cc3804916 /Lib/test/test_dataclasses.py
parent3fe33043ee83d19e15551094fc1e0984617ded3c (diff)
downloadcpython-f199bc655eb50c28e94010714629b376bbbd077b.zip
cpython-f199bc655eb50c28e94010714629b376bbbd077b.tar.gz
cpython-f199bc655eb50c28e94010714629b376bbbd077b.tar.bz2
bpo-32953: Dataclasses: frozen should not be inherited for non-dataclass derived classes (#6147)
If a non-dataclass derives from a frozen dataclass, allow attributes to be set. Require either all of the dataclasses in a class hierarchy to be frozen, or all non-frozen. Store `@dataclass` parameters on the class object under `__dataclass_params__`. This is needed to detect frozen base classes.
Diffstat (limited to 'Lib/test/test_dataclasses.py')
-rwxr-xr-xLib/test/test_dataclasses.py99
1 files changed, 75 insertions, 24 deletions
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index 46d485c..3e67263 100755
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -2476,41 +2476,92 @@ class TestFrozen(unittest.TestCase):
d = D(0, 10)
with self.assertRaises(FrozenInstanceError):
d.i = 5
+ with self.assertRaises(FrozenInstanceError):
+ d.j = 6
self.assertEqual(d.i, 0)
+ self.assertEqual(d.j, 10)
+
+ # Test both ways: with an intermediate normal (non-dataclass)
+ # class and without an intermediate class.
+ def test_inherit_nonfrozen_from_frozen(self):
+ for intermediate_class in [True, False]:
+ with self.subTest(intermediate_class=intermediate_class):
+ @dataclass(frozen=True)
+ class C:
+ i: int
- def test_inherit_from_nonfrozen_from_frozen(self):
- @dataclass(frozen=True)
- class C:
- i: int
+ if intermediate_class:
+ class I(C): pass
+ else:
+ I = C
- with self.assertRaisesRegex(TypeError,
- 'cannot inherit non-frozen dataclass from a frozen one'):
- @dataclass
- class D(C):
- pass
+ with self.assertRaisesRegex(TypeError,
+ 'cannot inherit non-frozen dataclass from a frozen one'):
+ @dataclass
+ class D(I):
+ pass
- def test_inherit_from_frozen_from_nonfrozen(self):
- @dataclass
- class C:
- i: int
+ def test_inherit_frozen_from_nonfrozen(self):
+ for intermediate_class in [True, False]:
+ with self.subTest(intermediate_class=intermediate_class):
+ @dataclass
+ class C:
+ i: int
- with self.assertRaisesRegex(TypeError,
- 'cannot inherit frozen dataclass from a non-frozen one'):
- @dataclass(frozen=True)
- class D(C):
- pass
+ if intermediate_class:
+ class I(C): pass
+ else:
+ I = C
+
+ with self.assertRaisesRegex(TypeError,
+ 'cannot inherit frozen dataclass from a non-frozen one'):
+ @dataclass(frozen=True)
+ class D(I):
+ pass
def test_inherit_from_normal_class(self):
- class C:
- pass
+ for intermediate_class in [True, False]:
+ with self.subTest(intermediate_class=intermediate_class):
+ class C:
+ pass
+
+ if intermediate_class:
+ class I(C): pass
+ else:
+ I = C
+
+ @dataclass(frozen=True)
+ class D(I):
+ i: int
+
+ d = D(10)
+ with self.assertRaises(FrozenInstanceError):
+ d.i = 5
+
+ def test_non_frozen_normal_derived(self):
+ # See bpo-32953.
@dataclass(frozen=True)
- class D(C):
- i: int
+ class D:
+ x: int
+ y: int = 10
- d = D(10)
+ class S(D):
+ pass
+
+ s = S(3)
+ self.assertEqual(s.x, 3)
+ self.assertEqual(s.y, 10)
+ s.cached = True
+
+ # But can't change the frozen attributes.
with self.assertRaises(FrozenInstanceError):
- d.i = 5
+ s.x = 5
+ with self.assertRaises(FrozenInstanceError):
+ s.y = 5
+ self.assertEqual(s.x, 3)
+ self.assertEqual(s.y, 10)
+ self.assertEqual(s.cached, True)
if __name__ == '__main__':