summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2021-06-12 12:15:17 (GMT)
committerGitHub <noreply@github.com>2021-06-12 12:15:17 (GMT)
commit9f1c5f6e8af6ba3f659b2aea1e221ac9695828ba (patch)
tree178272613398d4b75696f439134094b135a08f2a
parent4a42cebf6dd769e2fa4e234a9e91093b3ad1cb63 (diff)
downloadcpython-9f1c5f6e8af6ba3f659b2aea1e221ac9695828ba.zip
cpython-9f1c5f6e8af6ba3f659b2aea1e221ac9695828ba.tar.gz
cpython-9f1c5f6e8af6ba3f659b2aea1e221ac9695828ba.tar.bz2
bpo-43475: Fix the Python implementation of hash of Decimal NaN (GH-26679)
-rw-r--r--Doc/library/stdtypes.rst2
-rw-r--r--Lib/_pydecimal.py2
-rw-r--r--Lib/test/test_decimal.py23
-rw-r--r--Lib/test/test_float.py19
4 files changed, 36 insertions, 10 deletions
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index e34a888..3b2ff80 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -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:
diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py
index ff23322..3d6cece 100644
--- a/Lib/_pydecimal.py
+++ b/Lib/_pydecimal.py
@@ -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
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 179a9ea..058829b 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -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
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
index ff4f387..f0ed40f 100644
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -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):