Index: Objects/unicodeobject.c =================================================================== --- Objects/unicodeobject.c (revision 60872) +++ Objects/unicodeobject.c (working copy) @@ -8328,6 +8328,7 @@ int prec = -1; Py_UNICODE c = '\0'; Py_UNICODE fill; + int isnumok; PyObject *v = NULL; PyObject *temp = NULL; Py_UNICODE *pbuf; @@ -8540,21 +8541,49 @@ case 'X': if (c == 'i') c = 'd'; - if (PyLong_Check(v)) { - temp = formatlong(v, flags, prec, c); - if (!temp) - goto onError; - pbuf = PyUnicode_AS_UNICODE(temp); - len = PyUnicode_GET_SIZE(temp); - sign = 1; + isnumok = 0; + if (PyNumber_Check(v)) { + PyObject *iobj=NULL; + + if (PyInt_Check(v) || (PyLong_Check(v))) { + iobj = v; + Py_INCREF(iobj); + } + else { + iobj = PyNumber_Int(v); + if (iobj==NULL) iobj = PyNumber_Long(v); + } + if (iobj!=NULL) { + if (PyInt_Check(iobj)) { + isnumok = 1; + pbuf = formatbuf; + len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), + flags, prec, c, iobj); + Py_DECREF(iobj); + if (len < 0) + goto onError; + sign = 1; + } + else if (PyLong_Check(iobj)) { + isnumok = 1; + temp = formatlong(iobj, flags, prec, c); + Py_DECREF(iobj); + if (!temp) + goto onError; + pbuf = PyUnicode_AS_UNICODE(temp); + len = PyUnicode_GET_SIZE(temp); + sign = 1; + } + else { + Py_DECREF(iobj); + } + } } - else { - pbuf = formatbuf; - len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), - flags, prec, c, v); - if (len < 0) + if (!isnumok) { + PyErr_Format(PyExc_TypeError, + "%%%c format: a number is required, " + "not %.200s", c, Py_TYPE(v)->tp_name); goto onError; - sign = 1; } if (flags & F_ZERO) fill = '0'; Index: Objects/stringobject.c =================================================================== --- Objects/stringobject.c (revision 60872) +++ Objects/stringobject.c (working copy) @@ -4574,6 +4574,7 @@ int prec = -1; int c = '\0'; int fill; + int isnumok; PyObject *v = NULL; PyObject *temp = NULL; char *pbuf; @@ -4775,23 +4776,52 @@ case 'X': if (c == 'i') c = 'd'; - if (PyLong_Check(v)) { - int ilen; - temp = _PyString_FormatLong(v, flags, - prec, c, &pbuf, &ilen); - len = ilen; - if (!temp) - goto error; - sign = 1; + isnumok = 0; + if (PyNumber_Check(v)) { + PyObject *iobj=NULL; + + if (PyInt_Check(v) || (PyLong_Check(v))) { + iobj = v; + Py_INCREF(iobj); + } + else { + iobj = PyNumber_Int(v); + if (iobj==NULL) iobj = PyNumber_Long(v); + } + if (iobj!=NULL) { + if (PyInt_Check(iobj)) { + isnumok = 1; + pbuf = formatbuf; + len = formatint(pbuf, + sizeof(formatbuf), + flags, prec, c, iobj); + Py_DECREF(iobj); + if (len < 0) + goto error; + sign = 1; + } + else if (PyLong_Check(iobj)) { + int ilen; + + isnumok = 1; + temp = _PyString_FormatLong(iobj, flags, + prec, c, &pbuf, &ilen); + Py_DECREF(iobj); + len = ilen; + if (!temp) + goto error; + sign = 1; + } + else { + Py_DECREF(iobj); + } + } } - else { - pbuf = formatbuf; - len = formatint(pbuf, - sizeof(formatbuf), - flags, prec, c, v); - if (len < 0) - goto error; - sign = 1; + if (!isnumok) { + PyErr_Format(PyExc_TypeError, + "%%%c format: a number is required, " + "not %.200s", c, Py_TYPE(v)->tp_name); + goto error; } if (flags & F_ZERO) fill = '0'; Index: Lib/test/string_tests.py =================================================================== --- Lib/test/string_tests.py (revision 60872) +++ Lib/test/string_tests.py (working copy) @@ -1033,7 +1033,14 @@ # unicode raises ValueError, str raises OverflowError self.checkraises((ValueError, OverflowError), '%c', '__mod__', ordinal) + longvalue = sys.maxint + 10L + slongvalue = str(longvalue) + if slongvalue[-1] in ("L","l"): slongvalue = slongvalue[:-1] self.checkequal(' 42', '%3ld', '__mod__', 42) + self.checkequal('42', '%d', '__mod__', 42L) + self.checkequal('42', '%d', '__mod__', 42.0) + self.checkequal(slongvalue, '%d', '__mod__', longvalue) + self.checkcall('%d', '__mod__', float(longvalue)) self.checkequal('0042.00', '%07.2f', '__mod__', 42) self.checkequal('0042.00', '%07.2F', '__mod__', 42) @@ -1043,6 +1050,8 @@ self.checkraises(TypeError, '%c', '__mod__', (None,)) self.checkraises(ValueError, '%(foo', '__mod__', {}) self.checkraises(TypeError, '%(foo)s %(bar)s', '__mod__', ('foo', 42)) + self.checkraises(TypeError, '%d', '__mod__', "42") # not numeric + self.checkraises(TypeError, '%d', '__mod__', (42+0j)) # no int/long conversion provided # argument names with properly nested brackets are supported self.checkequal('bar', '%((foo))s', '__mod__', {'(foo)': 'bar'}) Index: Lib/test/test_format.py =================================================================== --- Lib/test/test_format.py (revision 60872) +++ Lib/test/test_format.py (working copy) @@ -11,7 +11,7 @@ overflowok = 1 overflowrequired = 0 -def testformat(formatstr, args, output=None): +def testformat(formatstr, args, output=None, limit=None): if verbose: if output: print "%s %% %s =? %s ..." %\ @@ -31,11 +31,22 @@ print 'no' print "overflow expected on %s %% %s" % \ (repr(formatstr), repr(args)) - elif output and result != output: + elif output and limit is None and result != output: if verbose: print 'no' print "%s %% %s == %s != %s" % \ (repr(formatstr), repr(args), repr(result), repr(output)) + # when 'limit' is specified, it determines how many characters + # must match exactly; lengths must always match. + # ex: limit=5, '12345678' matches '12345___' + # (mainly for floating point format tests for which an exact match + # can't be guaranteed due to rounding and representation errors) + elif output and limit is not None and ( + len(result)!=len(output) or result[:limit]!=output[:limit]): + if verbose: + print 'no' + print "%s %% %s == %s != %s" % \ + (repr(formatstr), repr(args), repr(result), repr(output)) else: if verbose: print 'yes' @@ -98,6 +109,7 @@ testboth("%.30d", big, "123456789012345678901234567890") testboth("%.31d", big, "0123456789012345678901234567890") testboth("%32.31d", big, " 0123456789012345678901234567890") +testboth("%d", float(big), "123456________________________", 6) big = 0x1234567890abcdef12345L # 21 hex digits testboth("%x", big, "1234567890abcdef12345") @@ -135,6 +147,7 @@ testboth("%#+027.23X", big, "+0X0001234567890ABCDEF12345") # same, except no 0 flag testboth("%#+27.23X", big, " +0X001234567890ABCDEF12345") +testboth("%x", float(big), "123456_______________", 6) big = 012345670123456701234567012345670L # 32 octal digits testboth("%o", big, "12345670123456701234567012345670") @@ -175,16 +188,19 @@ testboth("%034.33o", big, "0012345670123456701234567012345670") # base marker shouldn't change that testboth("%0#34.33o", big, "0012345670123456701234567012345670") +testboth("%o", float(big), "123456__________________________", 6) # Some small ints, in both Python int and long flavors). testboth("%d", 42, "42") testboth("%d", -42, "-42") testboth("%d", 42L, "42") testboth("%d", -42L, "-42") +testboth("%d", 42.0, "42") testboth("%#x", 1, "0x1") testboth("%#x", 1L, "0x1") testboth("%#X", 1, "0X1") testboth("%#X", 1L, "0X1") +testboth("%#x", 1.0, "0x1") testboth("%#o", 1, "01") testboth("%#o", 1L, "01") testboth("%#o", 0, "0") @@ -202,11 +218,13 @@ testboth("%x", -0x42, "-42") testboth("%x", 0x42L, "42") testboth("%x", -0x42L, "-42") +testboth("%x", float(0x42), "42") testboth("%o", 042, "42") testboth("%o", -042, "-42") testboth("%o", 042L, "42") testboth("%o", -042L, "-42") +testboth("%o", float(042), "42") # Test exception for unknown format characters if verbose: @@ -235,7 +253,7 @@ test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError, "unsupported format character '?' (0x3000) at index 5") -test_exc('%d', '1', TypeError, "int argument required, not str") +test_exc('%d', '1', TypeError, "%d format: a number is required, not str") test_exc('%g', '1', TypeError, "float argument required, not str") test_exc('no format', '1', TypeError, "not all arguments converted during string formatting")