Kaydet (Commit) 1b34d255 authored tarafından Mark Dickinson's avatar Mark Dickinson

Issue #5080: turn the DeprecationWarning from float arguments passed

to integer PyArg_Parse* format codes into a TypeError.  Add a
DeprecationWarning for floats passed with the 'L' format code, which
didn't previously have a warning.
üst edfe72f6
...@@ -752,7 +752,7 @@ if not _exists("urandom"): ...@@ -752,7 +752,7 @@ if not _exists("urandom"):
raise NotImplementedError("/dev/urandom (or equivalent) not found") raise NotImplementedError("/dev/urandom (or equivalent) not found")
try: try:
bs = b"" bs = b""
while n - len(bs) >= 1: while n > len(bs):
bs += read(_urandomfd, n - len(bs)) bs += read(_urandomfd, n - len(bs))
finally: finally:
close(_urandomfd) close(_urandomfd)
......
import unittest import unittest
from test import test_support from test import test_support
from _testcapi import getargs_keywords from _testcapi import getargs_keywords
import warnings import warnings
warnings.filterwarnings("ignore",
category=DeprecationWarning,
message=".*integer argument expected, got float",
module=__name__)
warnings.filterwarnings("ignore",
category=DeprecationWarning,
message=".*integer argument expected, got float",
module="unittest")
""" """
> How about the following counterproposal. This also changes some of > How about the following counterproposal. This also changes some of
...@@ -68,7 +59,7 @@ class Unsigned_TestCase(unittest.TestCase): ...@@ -68,7 +59,7 @@ class Unsigned_TestCase(unittest.TestCase):
def test_b(self): def test_b(self):
from _testcapi import getargs_b from _testcapi import getargs_b
# b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX) # b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX)
self.assertEqual(3, getargs_b(3.14)) self.assertRaises(TypeError, getargs_b, 3.14)
self.assertEqual(99, getargs_b(Long())) self.assertEqual(99, getargs_b(Long()))
self.assertEqual(99, getargs_b(Int())) self.assertEqual(99, getargs_b(Int()))
...@@ -84,7 +75,7 @@ class Unsigned_TestCase(unittest.TestCase): ...@@ -84,7 +75,7 @@ class Unsigned_TestCase(unittest.TestCase):
def test_B(self): def test_B(self):
from _testcapi import getargs_B from _testcapi import getargs_B
# B returns 'unsigned char', no range checking # B returns 'unsigned char', no range checking
self.assertEqual(3, getargs_B(3.14)) self.assertRaises(TypeError, getargs_B, 3.14)
self.assertEqual(99, getargs_B(Long())) self.assertEqual(99, getargs_B(Long()))
self.assertEqual(99, getargs_B(Int())) self.assertEqual(99, getargs_B(Int()))
...@@ -101,7 +92,7 @@ class Unsigned_TestCase(unittest.TestCase): ...@@ -101,7 +92,7 @@ class Unsigned_TestCase(unittest.TestCase):
def test_H(self): def test_H(self):
from _testcapi import getargs_H from _testcapi import getargs_H
# H returns 'unsigned short', no range checking # H returns 'unsigned short', no range checking
self.assertEqual(3, getargs_H(3.14)) self.assertRaises(TypeError, getargs_H, 3.14)
self.assertEqual(99, getargs_H(Long())) self.assertEqual(99, getargs_H(Long()))
self.assertEqual(99, getargs_H(Int())) self.assertEqual(99, getargs_H(Int()))
...@@ -118,7 +109,7 @@ class Unsigned_TestCase(unittest.TestCase): ...@@ -118,7 +109,7 @@ class Unsigned_TestCase(unittest.TestCase):
def test_I(self): def test_I(self):
from _testcapi import getargs_I from _testcapi import getargs_I
# I returns 'unsigned int', no range checking # I returns 'unsigned int', no range checking
self.assertEqual(3, getargs_I(3.14)) self.assertRaises(TypeError, getargs_I, 3.14)
self.assertEqual(99, getargs_I(Long())) self.assertEqual(99, getargs_I(Long()))
self.assertEqual(99, getargs_I(Int())) self.assertEqual(99, getargs_I(Int()))
...@@ -154,7 +145,7 @@ class Signed_TestCase(unittest.TestCase): ...@@ -154,7 +145,7 @@ class Signed_TestCase(unittest.TestCase):
def test_h(self): def test_h(self):
from _testcapi import getargs_h from _testcapi import getargs_h
# h returns 'short', and does range checking (SHRT_MIN ... SHRT_MAX) # h returns 'short', and does range checking (SHRT_MIN ... SHRT_MAX)
self.assertEqual(3, getargs_h(3.14)) self.assertRaises(TypeError, getargs_h, 3.14)
self.assertEqual(99, getargs_h(Long())) self.assertEqual(99, getargs_h(Long()))
self.assertEqual(99, getargs_h(Int())) self.assertEqual(99, getargs_h(Int()))
...@@ -170,7 +161,7 @@ class Signed_TestCase(unittest.TestCase): ...@@ -170,7 +161,7 @@ class Signed_TestCase(unittest.TestCase):
def test_i(self): def test_i(self):
from _testcapi import getargs_i from _testcapi import getargs_i
# i returns 'int', and does range checking (INT_MIN ... INT_MAX) # i returns 'int', and does range checking (INT_MIN ... INT_MAX)
self.assertEqual(3, getargs_i(3.14)) self.assertRaises(TypeError, getargs_i, 3.14)
self.assertEqual(99, getargs_i(Long())) self.assertEqual(99, getargs_i(Long()))
self.assertEqual(99, getargs_i(Int())) self.assertEqual(99, getargs_i(Int()))
...@@ -186,7 +177,7 @@ class Signed_TestCase(unittest.TestCase): ...@@ -186,7 +177,7 @@ class Signed_TestCase(unittest.TestCase):
def test_l(self): def test_l(self):
from _testcapi import getargs_l from _testcapi import getargs_l
# l returns 'long', and does range checking (LONG_MIN ... LONG_MAX) # l returns 'long', and does range checking (LONG_MIN ... LONG_MAX)
self.assertEqual(3, getargs_l(3.14)) self.assertRaises(TypeError, getargs_l, 3.14)
self.assertEqual(99, getargs_l(Long())) self.assertEqual(99, getargs_l(Long()))
self.assertEqual(99, getargs_l(Int())) self.assertEqual(99, getargs_l(Int()))
...@@ -203,7 +194,7 @@ class Signed_TestCase(unittest.TestCase): ...@@ -203,7 +194,7 @@ class Signed_TestCase(unittest.TestCase):
from _testcapi import getargs_n from _testcapi import getargs_n
# n returns 'Py_ssize_t', and does range checking # n returns 'Py_ssize_t', and does range checking
# (PY_SSIZE_T_MIN ... PY_SSIZE_T_MAX) # (PY_SSIZE_T_MIN ... PY_SSIZE_T_MAX)
self.assertEqual(3, getargs_n(3.14)) self.assertRaises(TypeError, getargs_n, 3.14)
self.assertEqual(99, getargs_n(Long())) self.assertEqual(99, getargs_n(Long()))
self.assertEqual(99, getargs_n(Int())) self.assertEqual(99, getargs_n(Int()))
...@@ -220,9 +211,24 @@ class Signed_TestCase(unittest.TestCase): ...@@ -220,9 +211,24 @@ class Signed_TestCase(unittest.TestCase):
class LongLong_TestCase(unittest.TestCase): class LongLong_TestCase(unittest.TestCase):
def test_L(self): def test_L(self):
from _testcapi import getargs_L from _testcapi import getargs_L
# L returns 'long long', and does range checking (LLONG_MIN ... LLONG_MAX) # L returns 'long long', and does range checking (LLONG_MIN
self.assertRaises(TypeError, getargs_L, "Hello") # ... LLONG_MAX)
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
category=DeprecationWarning,
message=".*integer argument expected, got float",
module=__name__)
self.assertEqual(3, getargs_L(3.14)) self.assertEqual(3, getargs_L(3.14))
with warnings.catch_warnings():
warnings.filterwarnings(
"error",
category=DeprecationWarning,
message=".*integer argument expected, got float",
module="unittest")
self.assertRaises(DeprecationWarning, getargs_L, 3.14)
self.assertRaises(TypeError, getargs_L, "Hello")
self.assertEqual(99, getargs_L(Long())) self.assertEqual(99, getargs_L(Long()))
self.assertEqual(99, getargs_L(Int())) self.assertEqual(99, getargs_L(Int()))
......
...@@ -502,11 +502,9 @@ class URandomTests (unittest.TestCase): ...@@ -502,11 +502,9 @@ class URandomTests (unittest.TestCase):
self.assertEqual(len(os.urandom(100)), 100) self.assertEqual(len(os.urandom(100)), 100)
self.assertEqual(len(os.urandom(1000)), 1000) self.assertEqual(len(os.urandom(1000)), 1000)
# see http://bugs.python.org/issue3708 # see http://bugs.python.org/issue3708
with test_support.check_warnings(): self.assertRaises(TypeError, os.urandom, 0.9)
# silence deprecation warnings about float arguments self.assertRaises(TypeError, os.urandom, 1.1)
self.assertEqual(len(os.urandom(0.9)), 0) self.assertRaises(TypeError, os.urandom, 2.0)
self.assertEqual(len(os.urandom(1.1)), 1)
self.assertEqual(len(os.urandom(2.0)), 2)
except NotImplementedError: except NotImplementedError:
pass pass
......
...@@ -81,7 +81,7 @@ class XrangeTest(unittest.TestCase): ...@@ -81,7 +81,7 @@ class XrangeTest(unittest.TestCase):
self.assertRaises(TypeError, xrange, 1, 2, 3, 4) self.assertRaises(TypeError, xrange, 1, 2, 3, 4)
self.assertRaises(ValueError, xrange, 1, 2, 0) self.assertRaises(ValueError, xrange, 1, 2, 0)
self.assertRaises(OverflowError, xrange, 1e100, 1e101, 1e101) self.assertRaises(OverflowError, xrange, 10**100, 10**101, 10**101)
self.assertRaises(TypeError, xrange, 0, "spam") self.assertRaises(TypeError, xrange, 0, "spam")
self.assertRaises(TypeError, xrange, 0, 42, "spam") self.assertRaises(TypeError, xrange, 0, 42, "spam")
......
...@@ -12,6 +12,14 @@ What's New in Python 2.7 alpha 2? ...@@ -12,6 +12,14 @@ What's New in Python 2.7 alpha 2?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #5080: A number of functions and methods previously produced a
DeprecationWarning when passed a float argument where an integer was
expected. These functions and methods now raise TypeError instead.
The majority of the effects of this change are in the extension
modules, but some core functions and methods are affected: notably
the 'chr', 'range' and 'xrange' builtins, and many unicode/str
methods.
- Issue #7604: Deleting an unset slotted attribute did not raise an - Issue #7604: Deleting an unset slotted attribute did not raise an
AttributeError. AttributeError.
...@@ -88,6 +96,14 @@ Library ...@@ -88,6 +96,14 @@ Library
C-API C-API
----- -----
- Issue #5080: The argument parsing functions PyArg_ParseTuple,
PyArg_ParseTupleAndKeywords, PyArg_VaParse,
PyArg_VaParseTupleAndKeywords and PyArg_Parse no longer accept float
arguments for integer format codes (other than 'L'): previously an
attempt to pass a float resulted in a DeprecationWarning; now it
gives a TypeError. For the 'L' format code (which previously had no
warning) there is now a DeprecationWarning.
- Issue #7033: function ``PyErr_NewExceptionWithDoc()`` added. - Issue #7033: function ``PyErr_NewExceptionWithDoc()`` added.
Build Build
......
...@@ -526,7 +526,7 @@ converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize) ...@@ -526,7 +526,7 @@ converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)
/* explicitly check for float arguments when integers are expected. For now /* explicitly check for float arguments when integers are expected. For now
* signal a warning. Returns true if an exception was raised. */ * signal a warning. Returns true if an exception was raised. */
static int static int
float_argument_error(PyObject *arg) float_argument_warning(PyObject *arg)
{ {
if (PyFloat_Check(arg) && if (PyFloat_Check(arg) &&
PyErr_Warn(PyExc_DeprecationWarning, PyErr_Warn(PyExc_DeprecationWarning,
...@@ -536,6 +536,20 @@ float_argument_error(PyObject *arg) ...@@ -536,6 +536,20 @@ float_argument_error(PyObject *arg)
return 0; return 0;
} }
/* explicitly check for float arguments when integers are expected. Raises
TypeError and returns true for float arguments. */
static int
float_argument_error(PyObject *arg)
{
if (PyFloat_Check(arg)) {
PyErr_SetString(PyExc_TypeError,
"integer argument expected, got float");
return 1;
}
else
return 0;
}
/* Convert a non-tuple argument. Return NULL if conversion went OK, /* Convert a non-tuple argument. Return NULL if conversion went OK,
or a string with a message describing the failure. The message is or a string with a message describing the failure. The message is
formatted as "must be <desired type>, not <actual type>". formatted as "must be <desired type>, not <actual type>".
...@@ -719,7 +733,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, ...@@ -719,7 +733,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
#ifdef HAVE_LONG_LONG #ifdef HAVE_LONG_LONG
case 'L': {/* PY_LONG_LONG */ case 'L': {/* PY_LONG_LONG */
PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * ); PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * );
PY_LONG_LONG ival = PyLong_AsLongLong( arg ); PY_LONG_LONG ival;
if (float_argument_warning(arg))
return converterr("long<L>", arg, msgbuf, bufsize);
ival = PyLong_AsLongLong(arg);
if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred() ) { if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred() ) {
return converterr("long<L>", arg, msgbuf, bufsize); return converterr("long<L>", arg, msgbuf, bufsize);
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment