◐ Shell
clean mode source ↗

Update test_float.py from Cpython v3.11.2 by Masorubka1 · Pull Request #4823 · RustPython/RustPython

Expand Up @@ -8,18 +8,21 @@ import unittest
from test import support from test.support import import_helper from test.test_grammar import (VALID_UNDERSCORE_LITERALS, INVALID_UNDERSCORE_LITERALS) from math import isinf, isnan, copysign, ldexp import math
try: import _testcapi except ImportError: _testcapi = None
HAVE_IEEE_754 = float.__getformat__("double").startswith("IEEE") INF = float("inf") NAN = float("nan")
have_getformat = hasattr(float, "__getformat__") requires_getformat = unittest.skipUnless(have_getformat, "requires __getformat__") requires_setformat = unittest.skipUnless(hasattr(float, "__setformat__"), "requires __setformat__")
#locate file with float format test values test_dir = os.path.dirname(__file__) or os.curdir Expand Down Expand Up @@ -139,6 +142,10 @@ def check(s): check('123\xbd') check(' 123 456 ') check(b' 123 456 ') # all whitespace (cf. https://github.com/python/cpython/issues/95605) check('') check(' ') check('\t \n')
# non-ascii digits (error came from non-digit '!') check('\u0663\u0661\u0664!') Expand Down Expand Up @@ -249,6 +256,35 @@ def test_keyword_args(self): with self.assertRaisesRegex(TypeError, 'keyword argument'): float(x='3.14')
# TODO: RUSTPYTHON @unittest.expectedFailure def test_keywords_in_subclass(self): class subclass(float): pass u = subclass(2.5) self.assertIs(type(u), subclass) self.assertEqual(float(u), 2.5) with self.assertRaises(TypeError): subclass(x=0)
class subclass_with_init(float): def __init__(self, arg, newarg=None): self.newarg = newarg u = subclass_with_init(2.5, newarg=3) self.assertIs(type(u), subclass_with_init) self.assertEqual(float(u), 2.5) self.assertEqual(u.newarg, 3)
class subclass_with_new(float): def __new__(cls, arg, newarg=None): self = super().__new__(cls, arg) self.newarg = newarg return self u = subclass_with_new(2.5, newarg=3) self.assertIs(type(u), subclass_with_new) self.assertEqual(float(u), 2.5) self.assertEqual(u.newarg, 3)
def test_is_integer(self): self.assertFalse((1.1).is_integer()) self.assertTrue((1.).is_integer()) Expand Down Expand Up @@ -590,17 +626,8 @@ class F(float, H): self.assertEqual(hash(value), object.__hash__(value))

@requires_setformat @unittest.skipUnless(hasattr(float, "__getformat__"), "requires __getformat__") class FormatFunctionsTestCase(unittest.TestCase):
def setUp(self): self.save_formats = {'double':float.__getformat__('double'), 'float':float.__getformat__('float')}
def tearDown(self): float.__setformat__('double', self.save_formats['double']) float.__setformat__('float', self.save_formats['float'])
def test_getformat(self): self.assertIn(float.__getformat__('double'), ['unknown', 'IEEE, big-endian', 'IEEE, little-endian']) Expand All @@ -609,24 +636,6 @@ def test_getformat(self): self.assertRaises(ValueError, float.__getformat__, 'chicken') self.assertRaises(TypeError, float.__getformat__, 1)
def test_setformat(self): for t in 'double', 'float': float.__setformat__(t, 'unknown') if self.save_formats[t] == 'IEEE, big-endian': self.assertRaises(ValueError, float.__setformat__, t, 'IEEE, little-endian') elif self.save_formats[t] == 'IEEE, little-endian': self.assertRaises(ValueError, float.__setformat__, t, 'IEEE, big-endian') else: self.assertRaises(ValueError, float.__setformat__, t, 'IEEE, big-endian') self.assertRaises(ValueError, float.__setformat__, t, 'IEEE, little-endian') self.assertRaises(ValueError, float.__setformat__, t, 'chicken') self.assertRaises(ValueError, float.__setformat__, 'chicken', 'unknown')
BE_DOUBLE_INF = b'\x7f\xf0\x00\x00\x00\x00\x00\x00' LE_DOUBLE_INF = bytes(reversed(BE_DOUBLE_INF)) Expand All @@ -638,36 +647,6 @@ def test_setformat(self): BE_FLOAT_NAN = b'\x7f\xc0\x00\x00' LE_FLOAT_NAN = bytes(reversed(BE_FLOAT_NAN))
# on non-IEEE platforms, attempting to unpack a bit pattern # representing an infinity or a NaN should raise an exception.
@requires_setformat class UnknownFormatTestCase(unittest.TestCase): def setUp(self): self.save_formats = {'double':float.__getformat__('double'), 'float':float.__getformat__('float')} float.__setformat__('double', 'unknown') float.__setformat__('float', 'unknown')
def tearDown(self): float.__setformat__('double', self.save_formats['double']) float.__setformat__('float', self.save_formats['float'])
def test_double_specials_dont_unpack(self): for fmt, data in [('>d', BE_DOUBLE_INF), ('>d', BE_DOUBLE_NAN), ('<d', LE_DOUBLE_INF), ('<d', LE_DOUBLE_NAN)]: self.assertRaises(ValueError, struct.unpack, fmt, data)
def test_float_specials_dont_unpack(self): for fmt, data in [('>f', BE_FLOAT_INF), ('>f', BE_FLOAT_NAN), ('<f', LE_FLOAT_INF), ('<f', LE_FLOAT_NAN)]: self.assertRaises(ValueError, struct.unpack, fmt, data)

# on an IEEE platform, all we guarantee is that bit patterns # representing infinities or NaNs do not raise an exception; all else # is accident (today). Expand All @@ -694,8 +673,9 @@ def test_float_specials_do_unpack(self): # TODO: RUSTPYTHON @unittest.expectedFailure @support.requires_IEEE_754 @unittest.skipIf(_testcapi is None, 'needs _testcapi') def test_serialized_float_rounding(self): from _testcapi import FLT_MAX FLT_MAX = _testcapi.FLT_MAX self.assertEqual(struct.pack("<f", 3.40282356e38), struct.pack("<f", FLT_MAX)) self.assertEqual(struct.pack("<f", -3.40282356e38), struct.pack("<f", -FLT_MAX))
Expand Down Expand Up @@ -735,18 +715,16 @@ def test_format(self): # conversion to string should fail self.assertRaises(ValueError, format, 3.0, "s")
# other format specifiers shouldn't work on floats, # in particular int specifiers for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] + [chr(x) for x in range(ord('A'), ord('Z')+1)]): if not format_spec in 'eEfFgGn%': self.assertRaises(ValueError, format, 0.0, format_spec) self.assertRaises(ValueError, format, 1.0, format_spec) self.assertRaises(ValueError, format, -1.0, format_spec) self.assertRaises(ValueError, format, 1e100, format_spec) self.assertRaises(ValueError, format, -1e100, format_spec) self.assertRaises(ValueError, format, 1e-100, format_spec) self.assertRaises(ValueError, format, -1e-100, format_spec) # confirm format options expected to fail on floats, such as integer # presentation types for format_spec in 'sbcdoxX': self.assertRaises(ValueError, format, 0.0, format_spec) self.assertRaises(ValueError, format, 1.0, format_spec) self.assertRaises(ValueError, format, -1.0, format_spec) self.assertRaises(ValueError, format, 1e100, format_spec) self.assertRaises(ValueError, format, -1e100, format_spec) self.assertRaises(ValueError, format, 1e-100, format_spec) self.assertRaises(ValueError, format, -1e-100, format_spec)
# issue 3382 self.assertEqual(format(NAN, 'f'), 'nan') Expand Down Expand Up @@ -868,6 +846,11 @@ def test_inf_nan(self): self.assertRaises(TypeError, round, NAN, "ceci n'est pas un integer") self.assertRaises(TypeError, round, -0.0, 1j)
def test_inf_nan_ndigits(self): self.assertEqual(round(INF, 0), INF) self.assertEqual(round(-INF, 0), -INF) self.assertTrue(math.isnan(round(NAN, 0)))
def test_large_n(self): for n in [324, 325, 400, 2**31-1, 2**31, 2**32, 2**100]: self.assertEqual(round(123.456, n), 123.456) Expand Down Expand Up @@ -1538,5 +1521,69 @@ def __init__(self, value): self.assertEqual(getattr(f, 'foo', 'none'), 'bar')

# Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8() # Test PyFloat_Unpack2(), PyFloat_Unpack4() and PyFloat_Unpack8() BIG_ENDIAN = 0 LITTLE_ENDIAN = 1 EPSILON = { 2: 2.0 ** -11, # binary16 4: 2.0 ** -24, # binary32 8: 2.0 ** -53, # binary64 }
@unittest.skipIf(_testcapi is None, 'needs _testcapi') class PackTests(unittest.TestCase): def test_pack(self): self.assertEqual(_testcapi.float_pack(2, 1.5, BIG_ENDIAN), b'>\x00') self.assertEqual(_testcapi.float_pack(4, 1.5, BIG_ENDIAN), b'?\xc0\x00\x00') self.assertEqual(_testcapi.float_pack(8, 1.5, BIG_ENDIAN), b'?\xf8\x00\x00\x00\x00\x00\x00') self.assertEqual(_testcapi.float_pack(2, 1.5, LITTLE_ENDIAN), b'\x00>') self.assertEqual(_testcapi.float_pack(4, 1.5, LITTLE_ENDIAN), b'\x00\x00\xc0?') self.assertEqual(_testcapi.float_pack(8, 1.5, LITTLE_ENDIAN), b'\x00\x00\x00\x00\x00\x00\xf8?')
def test_unpack(self): self.assertEqual(_testcapi.float_unpack(b'>\x00', BIG_ENDIAN), 1.5) self.assertEqual(_testcapi.float_unpack(b'?\xc0\x00\x00', BIG_ENDIAN), 1.5) self.assertEqual(_testcapi.float_unpack(b'?\xf8\x00\x00\x00\x00\x00\x00', BIG_ENDIAN), 1.5) self.assertEqual(_testcapi.float_unpack(b'\x00>', LITTLE_ENDIAN), 1.5) self.assertEqual(_testcapi.float_unpack(b'\x00\x00\xc0?', LITTLE_ENDIAN), 1.5) self.assertEqual(_testcapi.float_unpack(b'\x00\x00\x00\x00\x00\x00\xf8?', LITTLE_ENDIAN), 1.5)
def test_roundtrip(self): large = 2.0 ** 100 values = [1.0, 1.5, large, 1.0/7, math.pi] if HAVE_IEEE_754: values.extend((INF, NAN)) for value in values: for size in (2, 4, 8,): if size == 2 and value == large: # too large for 16-bit float continue rel_tol = EPSILON[size] for endian in (BIG_ENDIAN, LITTLE_ENDIAN): with self.subTest(value=value, size=size, endian=endian): data = _testcapi.float_pack(size, value, endian) value2 = _testcapi.float_unpack(data, endian) if isnan(value): self.assertTrue(isnan(value2), (value, value2)) elif size < 8: self.assertTrue(math.isclose(value2, value, rel_tol=rel_tol), (value, value2)) else: self.assertEqual(value2, value)

if __name__ == '__main__': unittest.main()