[Python-checkins] cpython: Issue #23466: %c, %o, %x, and %X in bytes formatting now raise TypeError on

serhiy.storchaka python-checkins at python.org
Mon Mar 30 08:22:02 CEST 2015


https://hg.python.org/cpython/rev/cb96fd376baa
changeset: 95276:cb96fd376baa
user: Serhiy Storchaka <storchaka at gmail.com>
date: Mon Mar 30 09:19:08 2015 +0300
summary:
 Issue #23466: %c, %o, %x, and %X in bytes formatting now raise TypeError on
non-integer input.
files:
 Lib/test/test_format.py | 19 ++++++-
 Misc/NEWS | 3 +
 Objects/bytesobject.c | 81 +++++++++++++++++++---------
 3 files changed, 76 insertions(+), 27 deletions(-)
diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -272,9 +272,18 @@
 #test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError,
 # "unsupported format character '?' (0x3000) at index 5")
 test_exc('%d', '1', TypeError, "%d format: a number is required, not str")
+ test_exc('%x', '1', TypeError, "%x format: a number is required, not str")
+ test_exc('%x', 3.14, TypeError, "%x format: an integer is required, not float")
 test_exc('%g', '1', TypeError, "a float is required")
 test_exc('no format', '1', TypeError,
 "not all arguments converted during string formatting")
+ test_exc('%c', -1, OverflowError, "%c arg not in range(0x110000)")
+ test_exc('%c', sys.maxunicode+1, OverflowError,
+ "%c arg not in range(0x110000)")
+ #test_exc('%c', 2**128, OverflowError, "%c arg not in range(0x110000)")
+ test_exc('%c', 3.14, TypeError, "%c requires int or char")
+ test_exc('%c', 'ab', TypeError, "%c requires int or char")
+ test_exc('%c', b'x', TypeError, "%c requires int or char")
 
 if maxsize == 2**31-1:
 # crashes 2.2.1 and earlier:
@@ -339,6 +348,8 @@
 "%d format: a number is required, not str")
 test_exc(b'%d', b'1', TypeError,
 "%d format: a number is required, not bytes")
+ test_exc(b'%x', 3.14, TypeError,
+ "%x format: an integer is required, not float")
 test_exc(b'%g', '1', TypeError, "float argument required, not str")
 test_exc(b'%g', b'1', TypeError, "float argument required, not bytes")
 test_exc(b'no format', 7, TypeError,
@@ -347,11 +358,17 @@
 "not all arguments converted during bytes formatting")
 test_exc(b'no format', bytearray(b'1'), TypeError,
 "not all arguments converted during bytes formatting")
+ test_exc(b"%c", -1, TypeError,
+ "%c requires an integer in range(256) or a single byte")
 test_exc(b"%c", 256, TypeError,
 "%c requires an integer in range(256) or a single byte")
+ test_exc(b"%c", 2**128, TypeError,
+ "%c requires an integer in range(256) or a single byte")
 test_exc(b"%c", b"Za", TypeError,
 "%c requires an integer in range(256) or a single byte")
- test_exc(b"%c", "Yb", TypeError,
+ test_exc(b"%c", "Y", TypeError,
+ "%c requires an integer in range(256) or a single byte")
+ test_exc(b"%c", 3.14, TypeError,
 "%c requires an integer in range(256) or a single byte")
 test_exc(b"%b", "Xc", TypeError,
 "%b requires bytes, or an object that implements __bytes__, not 'str'")
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -36,6 +36,9 @@
 Core and Builtins
 -----------------
 
+- Issue #23466: %c, %o, %x, and %X in bytes formatting now raise TypeError on
+ non-integer input.
+
 - Issue #23573: Increased performance of string search operations (str.find,
 str.index, str.count, the in operator, str.split, str.partition) with
 arguments of different kinds (UCS1, UCS2, UCS4).
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -433,7 +433,41 @@
 return result;
 }
 
-Py_LOCAL_INLINE(int)
+static PyObject *
+formatlong(PyObject *v, int flags, int prec, int type)
+{
+ PyObject *result, *iobj;
+ if (type == 'i')
+ type = 'd';
+ if (PyLong_Check(v))
+ return _PyUnicode_FormatLong(v, flags & F_ALT, prec, type);
+ if (PyNumber_Check(v)) {
+ /* make sure number is a type of integer for o, x, and X */
+ if (type == 'o' || type == 'x' || type == 'X')
+ iobj = PyNumber_Index(v);
+ else
+ iobj = PyNumber_Long(v);
+ if (iobj == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_TypeError))
+ return NULL;
+ }
+ else if (!PyLong_Check(iobj))
+ Py_CLEAR(iobj);
+ if (iobj != NULL) {
+ result = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, type);
+ Py_DECREF(iobj);
+ return result;
+ }
+ }
+ PyErr_Format(PyExc_TypeError,
+ "%%%c format: %s is required, not %.200s", type,
+ (type == 'o' || type == 'x' || type == 'X') ? "an integer"
+ : "a number",
+ Py_TYPE(v)->tp_name);
+ return NULL;
+}
+
+static int
 byte_converter(PyObject *arg, char *p)
 {
 if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) {
@@ -445,12 +479,29 @@
 return 1;
 }
 else {
- long ival = PyLong_AsLong(arg);
- if (0 <= ival && ival <= 255) {
+ PyObject *iobj;
+ long ival;
+ int overflow;
+ /* make sure number is a type of integer */
+ if (PyLong_Check(arg)) {
+ ival = PyLong_AsLongAndOverflow(arg, &overflow);
+ }
+ else {
+ iobj = PyNumber_Index(arg);
+ if (iobj == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_TypeError))
+ return 0;
+ goto onError;
+ }
+ ival = PyLong_AsLongAndOverflow(iobj, &overflow);
+ Py_DECREF(iobj);
+ }
+ if (!overflow && 0 <= ival && ival <= 255) {
 *p = (char)ival;
 return 1;
 }
 }
+ onError:
 PyErr_SetString(PyExc_TypeError,
 "%c requires an integer in range(256) or a single byte");
 return 0;
@@ -561,7 +612,6 @@
 int prec = -1;
 int c = '0円';
 int fill;
- PyObject *iobj;
 PyObject *v = NULL;
 PyObject *temp = NULL;
 const char *pbuf = NULL;
@@ -747,28 +797,7 @@
 case 'o':
 case 'x':
 case 'X':
- if (c == 'i')
- c = 'd';
- iobj = NULL;
- if (PyNumber_Check(v)) {
- if ((PyLong_Check(v))) {
- iobj = v;
- Py_INCREF(iobj);
- }
- else {
- iobj = PyNumber_Long(v);
- if (iobj != NULL && !PyLong_Check(iobj))
- Py_CLEAR(iobj);
- }
- }
- if (iobj == NULL) {
- PyErr_Format(PyExc_TypeError,
- "%%%c format: a number is required, "
- "not %.200s", c, Py_TYPE(v)->tp_name);
- goto error;
- }
- temp = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, c);
- Py_DECREF(iobj);
+ temp = formatlong(v, flags, prec, c);
 if (!temp)
 goto error;
 assert(PyUnicode_IS_ASCII(temp));
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /