cpython: 050e5f803999 (original) (raw)
Mercurial > cpython
changeset 101661:050e5f803999
Issue #26983: float() now always return an instance of exact float. The deprecation warning is emitted if __float__ returns an instance of a strict subclass of float. In a future versions of Python this can be an error. [#26983]
Serhiy Storchaka storchaka@gmail.com | |
---|---|
date | Fri, 03 Jun 2016 21:42:55 +0300 |
parents | 19488e23dcdb |
children | 365b5e6163a6 |
files | Lib/test/test_float.py Lib/test/test_getargs2.py Misc/NEWS Objects/abstract.c Objects/floatobject.c |
diffstat | 5 files changed, 76 insertions(+), 32 deletions(-)[+] [-] Lib/test/test_float.py 21 Lib/test/test_getargs2.py 6 Misc/NEWS 5 Objects/abstract.c 30 Objects/floatobject.c 46 |
line wrap: on
line diff
--- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -161,11 +161,12 @@ class GeneralFloatCases(unittest.TestCas def float(self): return float(str(self)) + 1
self.assertAlmostEqual(float(Foo1()), 42.)[](#l1.7)
self.assertAlmostEqual(float(Foo2()), 42.)[](#l1.8)
self.assertAlmostEqual(float(Foo3(21)), 42.)[](#l1.9)
self.assertEqual(float(Foo1()), 42.)[](#l1.10)
self.assertEqual(float(Foo2()), 42.)[](#l1.11)
with self.assertWarns(DeprecationWarning):[](#l1.12)
self.assertEqual(float(Foo3(21)), 42.)[](#l1.13) self.assertRaises(TypeError, float, Foo4(42))[](#l1.14)
self.assertAlmostEqual(float(FooStr('8')), 9.)[](#l1.15)
self.assertEqual(float(FooStr('8')), 9.)[](#l1.16)
class Foo5: def float(self): @@ -176,10 +177,14 @@ class GeneralFloatCases(unittest.TestCas class F: def float(self): return OtherFloatSubclass(42.)
self.assertAlmostEqual(float(F()), 42.)[](#l1.24)
self.assertIs(type(float(F())), OtherFloatSubclass)[](#l1.25)
self.assertAlmostEqual(FloatSubclass(F()), 42.)[](#l1.26)
self.assertIs(type(FloatSubclass(F())), FloatSubclass)[](#l1.27)
with self.assertWarns(DeprecationWarning):[](#l1.28)
self.assertEqual(float(F()), 42.)[](#l1.29)
with self.assertWarns(DeprecationWarning):[](#l1.30)
self.assertIs(type(float(F())), float)[](#l1.31)
with self.assertWarns(DeprecationWarning):[](#l1.32)
self.assertEqual(FloatSubclass(F()), 42.)[](#l1.33)
with self.assertWarns(DeprecationWarning):[](#l1.34)
self.assertIs(type(FloatSubclass(F())), FloatSubclass)[](#l1.35)
def test_is_integer(self): self.assertFalse((1.1).is_integer())
--- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -365,7 +365,8 @@ class Float_TestCase(unittest.TestCase): self.assertEqual(getargs_f(FloatSubclass(7.5)), 7.5) self.assertEqual(getargs_f(FloatSubclass2(7.5)), 7.5) self.assertRaises(TypeError, getargs_f, BadFloat())
self.assertEqual(getargs_f(BadFloat2()), 4.25)[](#l2.7)
with self.assertWarns(DeprecationWarning):[](#l2.8)
self.assertEqual(getargs_f(BadFloat2()), 4.25)[](#l2.9) self.assertEqual(getargs_f(BadFloat3(7.5)), 7.5)[](#l2.10)
for x in (FLT_MIN, -FLT_MIN, FLT_MAX, -FLT_MAX, INF, -INF): @@ -390,7 +391,8 @@ class Float_TestCase(unittest.TestCase): self.assertEqual(getargs_d(FloatSubclass(7.5)), 7.5) self.assertEqual(getargs_d(FloatSubclass2(7.5)), 7.5) self.assertRaises(TypeError, getargs_d, BadFloat())
self.assertEqual(getargs_d(BadFloat2()), 4.25)[](#l2.17)
with self.assertWarns(DeprecationWarning):[](#l2.18)
self.assertEqual(getargs_d(BadFloat2()), 4.25)[](#l2.19) self.assertEqual(getargs_d(BadFloat3(7.5)), 7.5)[](#l2.20)
for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF):
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ What's New in Python 3.6.0 alpha 2 Core and Builtins ----------------- +- Issue #26983: float() now always return an instance of exact float.
- The deprecation warning is emitted if float returns an instance of
- a strict subclass of float. In a future versions of Python this can
- be an error. +
- Issue #27097: Python interpreter is now about 7% faster due to optimized instruction decoding. Based on patch by Demur Rumed.
--- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1351,21 +1351,39 @@ PyNumber_Float(PyObject *o) if (o == NULL) return null_error();
- if (PyFloat_CheckExact(o)) {
Py_INCREF(o);[](#l4.8)
return o;[](#l4.9)
- } m = o->ob_type->tp_as_number; if (m && m->nb_float) { /* This should include subclasses of float */ PyObject *res = m->nb_float(o);
if (res && !PyFloat_Check(res)) {[](#l4.14)
double val;[](#l4.15)
if (!res || PyFloat_CheckExact(res)) {[](#l4.16)
return res;[](#l4.17)
}[](#l4.18)
if (!PyFloat_Check(res)) {[](#l4.19) PyErr_Format(PyExc_TypeError,[](#l4.20)
"__float__ returned non-float (type %.200s)",[](#l4.21)
res->ob_type->tp_name);[](#l4.22)
"%.50s.__float__ returned non-float (type %.50s)",[](#l4.23)
o->ob_type->tp_name, res->ob_type->tp_name);[](#l4.24) Py_DECREF(res);[](#l4.25) return NULL;[](#l4.26) }[](#l4.27)
return res;[](#l4.28)
/* Issue #26983: warn if 'res' not of exact type float. */[](#l4.29)
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,[](#l4.30)
"%.50s.__float__ returned non-float (type %.50s). "[](#l4.31)
"The ability to return an instance of a strict subclass of float "[](#l4.32)
"is deprecated, and may be removed in a future version of Python.",[](#l4.33)
o->ob_type->tp_name, res->ob_type->tp_name)) {[](#l4.34)
Py_DECREF(res);[](#l4.35)
return NULL;[](#l4.36)
}[](#l4.37)
val = PyFloat_AS_DOUBLE(res);[](#l4.38)
Py_DECREF(res);[](#l4.39)
} if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */return PyFloat_FromDouble(val);[](#l4.40)
PyFloatObject *po = (PyFloatObject *)o;[](#l4.43)
return PyFloat_FromDouble(po->ob_fval);[](#l4.44)
--- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -215,35 +215,49 @@ double PyFloat_AsDouble(PyObject *op) { PyNumberMethods *nb;
- if (op == NULL) { PyErr_BadArgument(); return -1; }
- if ((nb = Py_TYPE(op)->tp_as_number) == NULL || nb->nb_float == NULL) {
PyErr_SetString(PyExc_TypeError, "a float is required");[](#l5.20)
- nb = Py_TYPE(op)->tp_as_number;
- if (nb == NULL || nb->nb_float == NULL) {
PyErr_Format(PyExc_TypeError, "must be real number, not %.50s",[](#l5.27)
}op->ob_type->tp_name);[](#l5.28) return -1;[](#l5.29)
- fo = (PyFloatObject*) (*nb->nb_float) (op);
- if (fo == NULL)
return -1;[](#l5.34)
- if (!PyFloat_Check(fo)) {
Py_DECREF(fo);[](#l5.36)
PyErr_SetString(PyExc_TypeError,[](#l5.37)
"nb_float should return float object");[](#l5.38)
- res = (*nb->nb_float) (op);
- if (res == NULL) { return -1; }
- if (!PyFloat_CheckExact(res)) {
if (!PyFloat_Check(res)) {[](#l5.44)
PyErr_Format(PyExc_TypeError,[](#l5.45)
"%.50s.__float__ returned non-float (type %.50s)",[](#l5.46)
op->ob_type->tp_name, res->ob_type->tp_name);[](#l5.47)
Py_DECREF(res);[](#l5.48)
return -1;[](#l5.49)
}[](#l5.50)
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,[](#l5.51)
"%.50s.__float__ returned non-float (type %.50s). "[](#l5.52)
"The ability to return an instance of a strict subclass of float "[](#l5.53)
"is deprecated, and may be removed in a future version of Python.",[](#l5.54)
op->ob_type->tp_name, res->ob_type->tp_name)) {[](#l5.55)
Py_DECREF(res);[](#l5.56)
return -1;[](#l5.57)
}[](#l5.58)
- }