diff options
author | Eric V. Smith <ericvsmith@users.noreply.github.com> | 2021-12-11 21:12:17 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-11 21:12:17 (GMT) |
commit | e029c53e1a408b89a4e3edf30a9b38b094f9c880 (patch) | |
tree | a439835a4dd477b67b500e5d09ff82b739973791 /Lib/test/test_dataclasses.py | |
parent | bfc59ed0a00106f5ba4a32a0c5b3dbe71d12665d (diff) | |
download | cpython-e029c53e1a408b89a4e3edf30a9b38b094f9c880.zip cpython-e029c53e1a408b89a4e3edf30a9b38b094f9c880.tar.gz cpython-e029c53e1a408b89a4e3edf30a9b38b094f9c880.tar.bz2 |
bpo-44674: Use unhashability as a proxy for mutability for default dataclass __init__ arguments. (GH-29867)
`@dataclass` in 3.10 prohibits using list, dict, or set as default values. It does this to avoid the mutable default problem. This test is both too strict, and not strict enough. Too strict, because some immutable subclasses should be safe, and not strict enough, because other mutable types should be prohibited. With this change applied, `@dataclass` now uses unhashability as a proxy for mutability: if objects aren't hashable, they're assumed to be mutable.
Diffstat (limited to 'Lib/test/test_dataclasses.py')
-rw-r--r-- | Lib/test/test_dataclasses.py | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index ef5009a..69e7685 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -501,6 +501,32 @@ class TestCase(unittest.TestCase): self.assertNotEqual(C(3), C(4, 10)) self.assertNotEqual(C(3, 10), C(4, 10)) + def test_no_unhashable_default(self): + # See bpo-44674. + class Unhashable: + __hash__ = None + + unhashable_re = 'mutable default .* for field a is not allowed' + with self.assertRaisesRegex(ValueError, unhashable_re): + @dataclass + class A: + a: dict = {} + + with self.assertRaisesRegex(ValueError, unhashable_re): + @dataclass + class A: + a: Any = Unhashable() + + # Make sure that the machinery looking for hashability is using the + # class's __hash__, not the instance's __hash__. + with self.assertRaisesRegex(ValueError, unhashable_re): + unhashable = Unhashable() + # This shouldn't make the variable hashable. + unhashable.__hash__ = lambda: 0 + @dataclass + class A: + a: Any = unhashable + def test_hash_field_rules(self): # Test all 6 cases of: # hash=True/False/None |