]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-43475: Fix the Python implementation of hash of Decimal NaN (GH-26679)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sun, 13 Jun 2021 14:05:28 +0000 (07:05 -0700)
committerGitHub <noreply@github.com>
Sun, 13 Jun 2021 14:05:28 +0000 (07:05 -0700)
(cherry picked from commit 9f1c5f6e8af6ba3f659b2aea1e221ac9695828ba)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Doc/library/stdtypes.rst
Lib/_pydecimal.py
Lib/test/test_decimal.py
Lib/test/test_float.py

index e34a888639c189b95b05db162c5a1d607ad1098f..3b2ff8090ced35e3186aff4a2656fd0e8a836676 100644 (file)
@@ -739,7 +739,7 @@ number, :class:`float`, or :class:`complex`::
        """Compute the hash of a float x."""
 
        if math.isnan(x):
-           return super().__hash__()
+           return object.__hash__(x)
        elif math.isinf(x):
            return sys.hash_info.inf if x > 0 else -sys.hash_info.inf
        else:
index ff23322ed5603e37a137c90d5af3246c91093f73..3d6cece9676c93d84482331bdb0ecebd4bdb9534 100644 (file)
@@ -951,7 +951,7 @@ class Decimal(object):
             if self.is_snan():
                 raise TypeError('Cannot hash a signaling NaN value.')
             elif self.is_nan():
-                return super().__hash__()
+                return object.__hash__(self)
             else:
                 if self._sign:
                     return -_PyHASH_INF
index 179a9ea7042fbf34f4f5643fe016ff97fba3a89a..058829b03a3deeb273a2d69e94275fcd5f96e256 100644 (file)
@@ -1814,13 +1814,7 @@ class UsabilityTest(unittest.TestCase):
 
         # check that hash(d) == hash(int(d)) for integral values
         for value in test_values:
-            self.assertEqual(hashit(value), hashit(int(value)))
-
-        #the same hash that to an int
-        self.assertEqual(hashit(Decimal(23)), hashit(23))
-        self.assertRaises(TypeError, hash, Decimal('sNaN'))
-        self.assertTrue(hashit(Decimal('Inf')))
-        self.assertTrue(hashit(Decimal('-Inf')))
+            self.assertEqual(hashit(value), hash(int(value)))
 
         # check that the hashes of a Decimal float match when they
         # represent exactly the same values
@@ -1829,7 +1823,7 @@ class UsabilityTest(unittest.TestCase):
         for s in test_strings:
             f = float(s)
             d = Decimal(s)
-            self.assertEqual(hashit(f), hashit(d))
+            self.assertEqual(hashit(d), hash(f))
 
         with localcontext() as c:
             # check that the value of the hash doesn't depend on the
@@ -1850,6 +1844,19 @@ class UsabilityTest(unittest.TestCase):
             x = 1100 ** 1248
             self.assertEqual(hashit(Decimal(x)), hashit(x))
 
+    def test_hash_method_nan(self):
+        Decimal = self.decimal.Decimal
+        self.assertRaises(TypeError, hash, Decimal('sNaN'))
+        value = Decimal('NaN')
+        self.assertEqual(hash(value), object.__hash__(value))
+        class H:
+            def __hash__(self):
+                return 42
+        class D(Decimal, H):
+            pass
+        value = D('NaN')
+        self.assertEqual(hash(value), object.__hash__(value))
+
     def test_min_and_max_methods(self):
         Decimal = self.decimal.Decimal
 
index ff4f3876be5cd31fce2e64f2a919a1bda81e3d48..f0ed40f7c94a7ec0f6e20c0a2cfaca36388d4738 100644 (file)
@@ -564,6 +564,25 @@ class GeneralFloatCases(unittest.TestCase):
             #self.assertTrue(0.0 < pow_op(2.0, -1047) < 1e-315)
             #self.assertTrue(0.0 > pow_op(-2.0, -1047) > -1e-315)
 
+    def test_hash(self):
+        for x in range(-30, 30):
+            self.assertEqual(hash(float(x)), hash(x))
+        self.assertEqual(hash(float(sys.float_info.max)),
+                         hash(int(sys.float_info.max)))
+        self.assertEqual(hash(float('inf')), sys.hash_info.inf)
+        self.assertEqual(hash(float('-inf')), -sys.hash_info.inf)
+
+    def test_hash_nan(self):
+        value = float('nan')
+        self.assertEqual(hash(value), object.__hash__(value))
+        class H:
+            def __hash__(self):
+                return 42
+        class F(float, H):
+            pass
+        value = F('nan')
+        self.assertEqual(hash(value), object.__hash__(value))
+
 
 @requires_setformat
 class FormatFunctionsTestCase(unittest.TestCase):