Skip to content

Commit 534939e

Browse files
committed
gh-145633: deprecate float.__getformat__() class method
1 parent 68c7fad commit 534939e

File tree

8 files changed

+46
-27
lines changed

8 files changed

+46
-27
lines changed

Doc/deprecations/pending-removal-in-3.20.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,8 @@ Pending removal in Python 3.20
3838
- :mod:`zlib`
3939

4040
(Contributed by Hugo van Kemenade and Stan Ulbrych in :gh:`76007`.)
41+
42+
* The ``__getformat__()`` class method of the :class:`float` is deprecated
43+
and will be removed in Python 3.20.
44+
45+
(Contributed by Sergey B Kirpichev in :gh:`145633`.)

Lib/test/pythoninfo.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,6 @@ def collect_locale(info_add):
195195
info_add('locale.getencoding', locale.getencoding())
196196

197197

198-
def collect_builtins(info_add):
199-
info_add('builtins.float.float_format', float.__getformat__("float"))
200-
info_add('builtins.float.double_format', float.__getformat__("double"))
201-
202-
203198
def collect_urandom(info_add):
204199
import os
205200

@@ -1050,7 +1045,6 @@ def collect_info(info):
10501045
# its state.
10511046
collect_urandom,
10521047

1053-
collect_builtins,
10541048
collect_cc,
10551049
collect_curses,
10561050
collect_datetime,

Lib/test/support/__init__.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,9 +518,37 @@ def dec(*args, **kwargs):
518518
# for a discussion of this number.
519519
SOCK_MAX_SIZE = 16 * 1024 * 1024 + 1
520520

521+
def _have_ieee_doubles():
522+
import ctypes
523+
import math
524+
# Check parameters for encoding of floats; a quick exit
525+
# if they aren't same as for IEC 60559 doubles. Check
526+
# also that subnormals are present.
527+
if (ctypes.sizeof(ctypes.c_double) != 8
528+
or sys.float_info.radix != 2
529+
or sys.float_info.mant_dig != 53
530+
or sys.float_info.dig != 15
531+
or sys.float_info.min_exp != -1021
532+
or sys.float_info.min_10_exp != -307
533+
or sys.float_info.max_exp != 1024
534+
or sys.float_info.max_10_exp != 308
535+
or not math.issubnormal(math.nextafter(0, 1))):
536+
return False
537+
# We attempt to determine if this machine is using IEC
538+
# floating-point formats by peering at the bits of some
539+
# carefully chosen value. Assume that integer and
540+
# floating-point types have same endianness.
541+
d = 9006104071832581.0
542+
be_d = int.from_bytes(b"\x43\x3f\xff\x01\x02\x03\x04\x05")
543+
dp = ctypes.pointer(ctypes.c_double(d))
544+
lp = ctypes.cast(dp, ctypes.POINTER(ctypes.c_uint64))
545+
return lp[0] == be_d
546+
547+
HAVE_IEEE_754 = _have_ieee_doubles()
548+
521549
# decorator for skipping tests on non-IEEE 754 platforms
522550
requires_IEEE_754 = unittest.skipUnless(
523-
float.__getformat__("double").startswith("IEEE"),
551+
HAVE_IEEE_754,
524552
"test requires IEEE 754 doubles")
525553

526554
def requires_zlib(reason='requires zlib'):

Lib/test/test_capi/test_float.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from test.test_capi.test_getargs import (Float, FloatSubclass, FloatSubclass2,
88
BadIndex2, BadFloat2, Index, BadIndex,
99
BadFloat)
10+
from test import support
1011
from test.support import import_helper
1112

1213
_testcapi = import_helper.import_module('_testcapi')
@@ -23,7 +24,6 @@
2324
8: 2.0 ** -53, # binary64
2425
}
2526

26-
HAVE_IEEE_754 = float.__getformat__("double").startswith("IEEE")
2727
INF = float("inf")
2828
NAN = float("nan")
2929

@@ -170,14 +170,13 @@ def test_unpack(self):
170170
self.assertEqual(unpack(b'\x00\x00\x00\x00\x00\x00\xf8?', LITTLE_ENDIAN),
171171
1.5)
172172

173+
@support.requires_IEEE_754
173174
def test_pack_unpack_roundtrip(self):
174175
pack = _testcapi.float_pack
175176
unpack = _testcapi.float_unpack
176177

177178
large = 2.0 ** 100
178-
values = [1.0, 1.5, large, 1.0/7, math.pi]
179-
if HAVE_IEEE_754:
180-
values.extend((INF, NAN))
179+
values = [1.0, 1.5, large, 1.0/7, math.pi, INF, NAN]
181180
for value in values:
182181
for size in (2, 4, 8,):
183182
if size == 2 and value == large:
@@ -196,7 +195,7 @@ def test_pack_unpack_roundtrip(self):
196195
else:
197196
self.assertEqual(value2, value)
198197

199-
@unittest.skipUnless(HAVE_IEEE_754, "requires IEEE 754")
198+
@support.requires_IEEE_754
200199
def test_pack_unpack_roundtrip_for_nans(self):
201200
pack = _testcapi.float_pack
202201
unpack = _testcapi.float_unpack
@@ -228,7 +227,7 @@ def test_pack_unpack_roundtrip_for_nans(self):
228227
self.assertTrue(math.isnan(value))
229228
self.assertEqual(data1, data2)
230229

231-
@unittest.skipUnless(HAVE_IEEE_754, "requires IEEE 754")
230+
@support.requires_IEEE_754
232231
@unittest.skipUnless(sys.maxsize != 2147483647, "requires 64-bit mode")
233232
def test_pack_unpack_nans_for_different_formats(self):
234233
pack = _testcapi.float_pack

Lib/test/test_float.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -670,17 +670,6 @@ def __neg__(self):
670670
self.assertFalse(f >= i)
671671

672672

673-
@unittest.skipUnless(hasattr(float, "__getformat__"), "requires __getformat__")
674-
class FormatFunctionsTestCase(unittest.TestCase):
675-
def test_getformat(self):
676-
self.assertIn(float.__getformat__('double'),
677-
['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
678-
self.assertIn(float.__getformat__('float'),
679-
['unknown', 'IEEE, big-endian', 'IEEE, little-endian'])
680-
self.assertRaises(ValueError, float.__getformat__, 'chicken')
681-
self.assertRaises(TypeError, float.__getformat__, 1)
682-
683-
684673
BE_DOUBLE_INF = b'\x7f\xf0\x00\x00\x00\x00\x00\x00'
685674
LE_DOUBLE_INF = bytes(reversed(BE_DOUBLE_INF))
686675
BE_DOUBLE_NAN = b'\x7f\xf8\x00\x00\x00\x00\x00\x00'

Lib/test/test_funcattrs.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -486,8 +486,6 @@ def test_builtin__qualname__(self):
486486

487487
# builtin classmethod:
488488
self.assertEqual(dict.fromkeys.__qualname__, 'dict.fromkeys')
489-
self.assertEqual(float.__getformat__.__qualname__,
490-
'float.__getformat__')
491489

492490
# builtin staticmethod:
493491
self.assertEqual(str.maketrans.__qualname__, 'str.maketrans')
@@ -509,7 +507,6 @@ def test_builtin__self__(self):
509507

510508
# builtin classmethod:
511509
self.assertIs(dict.fromkeys.__self__, dict)
512-
self.assertIs(float.__getformat__.__self__, float)
513510

514511
# builtin staticmethod:
515512
self.assertIsNone(str.maketrans.__self__)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The ``__getformat__()`` class method of the :class:`float` is deprecated.
2+
Patch by Sergey B Kirpichev.

Objects/floatobject.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,11 @@ static PyObject *
16961696
float___getformat___impl(PyTypeObject *type, const char *typestr)
16971697
/*[clinic end generated code: output=2bfb987228cc9628 input=0ae1ba35d192f704]*/
16981698
{
1699+
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
1700+
"float.__getformat__() is deprecated"))
1701+
{
1702+
return NULL;
1703+
}
16991704
if (strcmp(typestr, "double") != 0 && strcmp(typestr, "float") != 0) {
17001705
PyErr_SetString(PyExc_ValueError,
17011706
"__getformat__() argument 1 must be "

0 commit comments

Comments
 (0)