From: Ethan Furman Date: Sun, 12 Jan 2014 07:20:58 +0000 (-0800) Subject: Issue19995: issue deprecation warning for non-integer values to %c, %o, %x, %X X-Git-Tag: v3.4.0b3~174 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f9bba9c67f7928be185bd81614881ae88a46aaab;p=python Issue19995: issue deprecation warning for non-integer values to %c, %o, %x, %X --- diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 4b1fdf9171..29330f9171 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -142,6 +142,7 @@ class FormatTest(unittest.TestCase): testformat("%#+027.23X", big, "+0X0001234567890ABCDEF12345") # same, except no 0 flag testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345") + testformat("%x", float(big), "123456_______________", 6) big = 0o12345670123456701234567012345670 # 32 octal digits testformat("%o", big, "12345670123456701234567012345670") testformat("%o", -big, "-12345670123456701234567012345670") @@ -181,6 +182,7 @@ class FormatTest(unittest.TestCase): testformat("%034.33o", big, "0012345670123456701234567012345670") # base marker shouldn't change that testformat("%0#34.33o", big, "0o012345670123456701234567012345670") + testformat("%o", float(big), "123456__________________________", 6) # Some small ints, in both Python int and flavors). testformat("%d", 42, "42") testformat("%d", -42, "-42") @@ -191,6 +193,7 @@ class FormatTest(unittest.TestCase): testformat("%#x", 1, "0x1") testformat("%#X", 1, "0X1") testformat("%#X", 1, "0X1") + testformat("%#x", 1.0, "0x1") testformat("%#o", 1, "0o1") testformat("%#o", 1, "0o1") testformat("%#o", 0, "0o0") @@ -207,10 +210,12 @@ class FormatTest(unittest.TestCase): testformat("%x", -0x42, "-42") testformat("%x", 0x42, "42") testformat("%x", -0x42, "-42") + testformat("%x", float(0x42), "42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") + testformat("%o", float(0o42), "42") testformat("%r", "\u0378", "'\\u0378'") # non printable testformat("%a", "\u0378", "'\\u0378'") # non printable testformat("%r", "\u0374", "'\u0374'") # printable diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 63883a591c..d31838c6c4 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -1139,6 +1139,13 @@ class UnicodeTest(string_tests.CommonTest, self.value = float(value) def __int__(self): return int(self.value) + def check_depr(modifier, value): + with support.check_warnings( + ("", DeprecationWarning), + quiet=False, + ): + warnings.simplefilter('always') + modifier % value pi = PsuedoFloat(3.1415) letter_m = PsuedoInt(109) self.assertEqual('%x' % 42, '2a') @@ -1149,11 +1156,14 @@ class UnicodeTest(string_tests.CommonTest, self.assertEqual('%X' % letter_m, '6D') self.assertEqual('%o' % letter_m, '155') self.assertEqual('%c' % letter_m, 'm') - self.assertRaises(TypeError, '%x'.__mod__, pi) - self.assertRaises(TypeError, '%x'.__mod__, 3.14) - self.assertRaises(TypeError, '%X'.__mod__, 2.11) - self.assertRaises(TypeError, '%o'.__mod__, 1.79) - self.assertRaises(TypeError, '%c'.__mod__, pi) + for mod, value in ( + ('%x', pi), + ('%x', 3.14), + ('%X', 2.11), + ('%o', 1.79), + ('%c', pi), + ): + check_depr(mod, value) def test_formatting_with_enum(self): # issue18780 diff --git a/Misc/NEWS b/Misc/NEWS index 01c48cb2bc..aff3c96c05 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -117,8 +117,8 @@ Core and Builtins - Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c" argument is not in range [0; 255]. -- Issue #19995: %c, %o, %x, and %X now raise TypeError on non-integer input; - reworded docs to clarify that an integer type should define both __int__ +- Issue #19995: %c, %o, %x, and %X now issue a DeprecationWarning on non-integer + input; reworded docs to clarify that an integer type should define both __int__ and __index__. - Issue #19787: PyThread_set_key_value() now always set the value. In Python diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 48eccf7cbb..c8370bd8ac 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14004,11 +14004,24 @@ mainformatlong(PyObject *v, if (!PyNumber_Check(v)) goto wrongtype; + /* make sure number is a type of integer */ + /* if not, issue depracation warning for now */ if (!PyLong_Check(v)) { if (type == 'o' || type == 'x' || type == 'X') { iobj = PyNumber_Index(v); if (iobj == NULL) { - return -1; + PyErr_Clear(); + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "automatic int conversions have been deprecated", + 1)) { + return -1; + } + iobj = PyNumber_Long(v); + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto wrongtype; + return -1; + } } } else { @@ -14090,10 +14103,22 @@ formatchar(PyObject *v) PyObject *iobj; long x; /* make sure number is a type of integer */ + /* if not, issue depracation warning for now */ if (!PyLong_Check(v)) { iobj = PyNumber_Index(v); if (iobj == NULL) { - goto onError; + PyErr_Clear(); + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "automatic int conversions have been deprecated", + 1)) { + return -1; + } + iobj = PyNumber_Long(v); + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto onError; + return -1; + } } v = iobj; Py_DECREF(iobj);