Skip to content

Commit 29584b7

Browse files
serhiy-storchakajdevries3133
authored andcommitted
bpo-43475: Fix the Python implementation of hash of Decimal NaN (pythonGH-26679)
1 parent 869f2fa commit 29584b7

File tree

4 files changed

+36
-10
lines changed

4 files changed

+36
-10
lines changed

Doc/library/stdtypes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ number, :class:`float`, or :class:`complex`::
739739
"""Compute the hash of a float x."""
740740

741741
if math.isnan(x):
742-
return super().__hash__()
742+
return object.__hash__(x)
743743
elif math.isinf(x):
744744
return sys.hash_info.inf if x > 0 else -sys.hash_info.inf
745745
else:

Lib/_pydecimal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ def __hash__(self):
951951
if self.is_snan():
952952
raise TypeError('Cannot hash a signaling NaN value.')
953953
elif self.is_nan():
954-
return super().__hash__()
954+
return object.__hash__(self)
955955
else:
956956
if self._sign:
957957
return -_PyHASH_INF

Lib/test/test_decimal.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,13 +1814,7 @@ def hashit(d):
18141814

18151815
# check that hash(d) == hash(int(d)) for integral values
18161816
for value in test_values:
1817-
self.assertEqual(hashit(value), hashit(int(value)))
1818-
1819-
#the same hash that to an int
1820-
self.assertEqual(hashit(Decimal(23)), hashit(23))
1821-
self.assertRaises(TypeError, hash, Decimal('sNaN'))
1822-
self.assertTrue(hashit(Decimal('Inf')))
1823-
self.assertTrue(hashit(Decimal('-Inf')))
1817+
self.assertEqual(hashit(value), hash(int(value)))
18241818

18251819
# check that the hashes of a Decimal float match when they
18261820
# represent exactly the same values
@@ -1829,7 +1823,7 @@ def hashit(d):
18291823
for s in test_strings:
18301824
f = float(s)
18311825
d = Decimal(s)
1832-
self.assertEqual(hashit(f), hashit(d))
1826+
self.assertEqual(hashit(d), hash(f))
18331827

18341828
with localcontext() as c:
18351829
# check that the value of the hash doesn't depend on the
@@ -1850,6 +1844,19 @@ def hashit(d):
18501844
x = 1100 ** 1248
18511845
self.assertEqual(hashit(Decimal(x)), hashit(x))
18521846

1847+
def test_hash_method_nan(self):
1848+
Decimal = self.decimal.Decimal
1849+
self.assertRaises(TypeError, hash, Decimal('sNaN'))
1850+
value = Decimal('NaN')
1851+
self.assertEqual(hash(value), object.__hash__(value))
1852+
class H:
1853+
def __hash__(self):
1854+
return 42
1855+
class D(Decimal, H):
1856+
pass
1857+
value = D('NaN')
1858+
self.assertEqual(hash(value), object.__hash__(value))
1859+
18531860
def test_min_and_max_methods(self):
18541861
Decimal = self.decimal.Decimal
18551862

Lib/test/test_float.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,25 @@ def test_float_pow(self):
564564
#self.assertTrue(0.0 < pow_op(2.0, -1047) < 1e-315)
565565
#self.assertTrue(0.0 > pow_op(-2.0, -1047) > -1e-315)
566566

567+
def test_hash(self):
568+
for x in range(-30, 30):
569+
self.assertEqual(hash(float(x)), hash(x))
570+
self.assertEqual(hash(float(sys.float_info.max)),
571+
hash(int(sys.float_info.max)))
572+
self.assertEqual(hash(float('inf')), sys.hash_info.inf)
573+
self.assertEqual(hash(float('-inf')), -sys.hash_info.inf)
574+
575+
def test_hash_nan(self):
576+
value = float('nan')
577+
self.assertEqual(hash(value), object.__hash__(value))
578+
class H:
579+
def __hash__(self):
580+
return 42
581+
class F(float, H):
582+
pass
583+
value = F('nan')
584+
self.assertEqual(hash(value), object.__hash__(value))
585+
567586

568587
@requires_setformat
569588
class FormatFunctionsTestCase(unittest.TestCase):

0 commit comments

Comments
 (0)