Exhaustively test dataclass hashing when no hash= value is provided. This is in anticipation of changing how non-default hashing is handled. (#5834)

This commit is contained in:
Eric V. Smith 2018-02-23 13:01:31 -05:00 committed by GitHub
parent 98f42aac23
commit 718070db26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 73 additions and 0 deletions

View File

@ -2393,6 +2393,79 @@ def __eq__(self, other):
self.assertNotEqual(C(1), C(1))
self.assertEqual(hash(C(1)), hash(C(1.0)))
def test_hash_no_args(self):
# Test dataclasses with no hash= argument. This exists to
# make sure that when hash is changed, the default hashability
# keeps working.
class Base:
def __hash__(self):
return 301
# If frozen or eq is None, then use the default value (do not
# specify any value in the deecorator).
for frozen, eq, base, expected in [
(None, None, object, 'unhashable'),
(None, None, Base, 'unhashable'),
(None, False, object, 'object'),
(None, False, Base, 'base'),
(None, True, object, 'unhashable'),
(None, True, Base, 'unhashable'),
(False, None, object, 'unhashable'),
(False, None, Base, 'unhashable'),
(False, False, object, 'object'),
(False, False, Base, 'base'),
(False, True, object, 'unhashable'),
(False, True, Base, 'unhashable'),
(True, None, object, 'tuple'),
(True, None, Base, 'tuple'),
(True, False, object, 'object'),
(True, False, Base, 'base'),
(True, True, object, 'tuple'),
(True, True, Base, 'tuple'),
]:
with self.subTest(frozen=frozen, eq=eq, base=base, expected=expected):
# First, create the class.
if frozen is None and eq is None:
@dataclass
class C(base):
i: int
elif frozen is None:
@dataclass(eq=eq)
class C(base):
i: int
elif eq is None:
@dataclass(frozen=frozen)
class C(base):
i: int
else:
@dataclass(frozen=frozen, eq=eq)
class C(base):
i: int
# Now, make sure it hashes as expected.
if expected == 'unhashable':
c = C(10)
with self.assertRaisesRegex(TypeError, 'unhashable type'):
hash(c)
elif expected == 'base':
self.assertEqual(hash(C(10)), 301)
elif expected == 'object':
# I'm not sure what test to use here. object's
# hash isn't based on id(), so calling hash()
# won't tell us much. So, just check the function
# used is object's.
self.assertIs(C.__hash__, object.__hash__)
elif expected == 'tuple':
self.assertEqual(hash(C(42)), hash((42,)))
else:
assert False, f'unknown value for expected={expected!r}'
if __name__ == '__main__':
unittest.main()