[Python-checkins] Exhaustively test dataclass hashing when no hash= value is provided. This is in anticipation of changing how non-default hashing is handled. (GH-5834) (GH-5889)

Eric V. Smith webhook-mailer at python.org
Sun Feb 25 11:56:33 EST 2018


https://github.com/python/cpython/commit/b6b6669cfd186f3ed1706c6d65ed83c31759a0ea
commit: b6b6669cfd186f3ed1706c6d65ed83c31759a0ea
branch: 3.7
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: Eric V. Smith <ericvsmith at users.noreply.github.com>
date: 2018-02-25T11:56:30-05:00
summary:

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

(cherry picked from commit 718070db26b35da4aedc03088c58558a833ccf6e)

Co-authored-by: Eric V. Smith <ericvsmith at users.noreply.github.com>

files:
M Lib/test/test_dataclasses.py

diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index 736bc490867b..9752f5502c7d 100755
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -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()



More information about the Python-checkins mailing list