diff -r 82b58807f481 Lib/test/test_format.py --- a/Lib/test/test_format.py Sat Nov 16 19:10:57 2013 +0200 +++ b/Lib/test/test_format.py Fri Jan 17 03:29:05 2014 -0600 @@ -9,7 +9,7 @@ # test string formatting operator (I am not sure if this is being tested # elsewhere but, surely, some of the given cases are *not* tested because # they crash python) -# test on unicode strings as well +# test on bytes object as well def testformat(formatstr, args, output=None, limit=None, overflowok=False): if verbose: @@ -47,183 +47,190 @@ print('yes') +def testboth(formatstr, args, output=None, limit=None, overflowok=False): + testformat(formatstr, args, output, limit, overflowok) + if output is not None: + output = output.encode('ascii') + testformat(formatstr.encode('ascii'), args, output, limit, overflowok) + + class FormatTest(unittest.TestCase): def test_format(self): - testformat("%.1d", (1,), "1") - testformat("%.*d", (sys.maxsize,1), overflowok=True) # expect overflow - testformat("%.100d", (1,), '00000000000000000000000000000000000000' + testboth("%.1d", (1,), "1") + testboth("%.*d", (sys.maxsize+1,1), overflowok=True) # expect overflow + testboth("%.100d", (1,), '00000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000' '00000001', overflowok=True) - testformat("%#.117x", (1,), '0x00000000000000000000000000000000000' + testboth("%#.117x", (1,), '0x00000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000' '0000000000000000000000000001', overflowok=True) - testformat("%#.118x", (1,), '0x00000000000000000000000000000000000' + testboth("%#.118x", (1,), '0x00000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000' '00000000000000000000000000001', overflowok=True) - testformat("%f", (1.0,), "1.000000") + testboth("%f", (1.0,), "1.000000") # these are trying to test the limits of the internal magic-number-length # formatting buffer, if that number changes then these tests are less # effective - testformat("%#.*g", (109, -1.e+49/3.)) - testformat("%#.*g", (110, -1.e+49/3.)) - testformat("%#.*g", (110, -1.e+100/3.)) + testboth("%#.*g", (109, -1.e+49/3.)) + testboth("%#.*g", (110, -1.e+49/3.)) + testboth("%#.*g", (110, -1.e+100/3.)) # test some ridiculously large precision, expect overflow - testformat('%12.*f', (123456, 1.0)) + testboth('%12.*f', (123456, 1.0)) # check for internal overflow validation on length of precision # these tests should no longer cause overflow in Python # 2.7/3.1 and later. - testformat("%#.*g", (110, -1.e+100/3.)) - testformat("%#.*G", (110, -1.e+100/3.)) - testformat("%#.*f", (110, -1.e+100/3.)) - testformat("%#.*F", (110, -1.e+100/3.)) + testboth("%#.*g", (110, -1.e+100/3.)) + testboth("%#.*G", (110, -1.e+100/3.)) + testboth("%#.*f", (110, -1.e+100/3.)) + testboth("%#.*F", (110, -1.e+100/3.)) # Formatting of integers. Overflow is not ok - testformat("%x", 10, "a") - testformat("%x", 100000000000, "174876e800") - testformat("%o", 10, "12") - testformat("%o", 100000000000, "1351035564000") - testformat("%d", 10, "10") - testformat("%d", 100000000000, "100000000000") + testboth("%x", 10, "a") + testboth("%x", 100000000000, "174876e800") + testboth("%o", 10, "12") + testboth("%o", 100000000000, "1351035564000") + testboth("%d", 10, "10") + testboth("%d", 100000000000, "100000000000") big = 123456789012345678901234567890 - testformat("%d", big, "123456789012345678901234567890") - testformat("%d", -big, "-123456789012345678901234567890") - testformat("%5d", -big, "-123456789012345678901234567890") - testformat("%31d", -big, "-123456789012345678901234567890") - testformat("%32d", -big, " -123456789012345678901234567890") - testformat("%-32d", -big, "-123456789012345678901234567890 ") - testformat("%032d", -big, "-0123456789012345678901234567890") - testformat("%-032d", -big, "-123456789012345678901234567890 ") - testformat("%034d", -big, "-000123456789012345678901234567890") - testformat("%034d", big, "0000123456789012345678901234567890") - testformat("%0+34d", big, "+000123456789012345678901234567890") - testformat("%+34d", big, " +123456789012345678901234567890") - testformat("%34d", big, " 123456789012345678901234567890") - testformat("%.2d", big, "123456789012345678901234567890") - testformat("%.30d", big, "123456789012345678901234567890") - testformat("%.31d", big, "0123456789012345678901234567890") - testformat("%32.31d", big, " 0123456789012345678901234567890") - testformat("%d", float(big), "123456________________________", 6) + testboth("%d", big, "123456789012345678901234567890") + testboth("%d", -big, "-123456789012345678901234567890") + testboth("%5d", -big, "-123456789012345678901234567890") + testboth("%31d", -big, "-123456789012345678901234567890") + testboth("%32d", -big, " -123456789012345678901234567890") + testboth("%-32d", -big, "-123456789012345678901234567890 ") + testboth("%032d", -big, "-0123456789012345678901234567890") + testboth("%-032d", -big, "-123456789012345678901234567890 ") + testboth("%034d", -big, "-000123456789012345678901234567890") + testboth("%034d", big, "0000123456789012345678901234567890") + testboth("%0+34d", big, "+000123456789012345678901234567890") + testboth("%+34d", big, " +123456789012345678901234567890") + testboth("%34d", big, " 123456789012345678901234567890") + testboth("%.2d", big, "123456789012345678901234567890") + testboth("%.30d", big, "123456789012345678901234567890") + testboth("%.31d", big, "0123456789012345678901234567890") + testboth("%32.31d", big, " 0123456789012345678901234567890") + testboth("%d", float(big), "123456________________________", 6) big = 0x1234567890abcdef12345 # 21 hex digits - testformat("%x", big, "1234567890abcdef12345") - testformat("%x", -big, "-1234567890abcdef12345") - testformat("%5x", -big, "-1234567890abcdef12345") - testformat("%22x", -big, "-1234567890abcdef12345") - testformat("%23x", -big, " -1234567890abcdef12345") - testformat("%-23x", -big, "-1234567890abcdef12345 ") - testformat("%023x", -big, "-01234567890abcdef12345") - testformat("%-023x", -big, "-1234567890abcdef12345 ") - testformat("%025x", -big, "-0001234567890abcdef12345") - testformat("%025x", big, "00001234567890abcdef12345") - testformat("%0+25x", big, "+0001234567890abcdef12345") - testformat("%+25x", big, " +1234567890abcdef12345") - testformat("%25x", big, " 1234567890abcdef12345") - testformat("%.2x", big, "1234567890abcdef12345") - testformat("%.21x", big, "1234567890abcdef12345") - testformat("%.22x", big, "01234567890abcdef12345") - testformat("%23.22x", big, " 01234567890abcdef12345") - testformat("%-23.22x", big, "01234567890abcdef12345 ") - testformat("%X", big, "1234567890ABCDEF12345") - testformat("%#X", big, "0X1234567890ABCDEF12345") - testformat("%#x", big, "0x1234567890abcdef12345") - testformat("%#x", -big, "-0x1234567890abcdef12345") - testformat("%#.23x", -big, "-0x001234567890abcdef12345") - testformat("%#+.23x", big, "+0x001234567890abcdef12345") - testformat("%# .23x", big, " 0x001234567890abcdef12345") - testformat("%#+.23X", big, "+0X001234567890ABCDEF12345") - testformat("%#-+.23X", big, "+0X001234567890ABCDEF12345") - testformat("%#-+26.23X", big, "+0X001234567890ABCDEF12345") - testformat("%#-+27.23X", big, "+0X001234567890ABCDEF12345 ") - testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345") + testboth("%x", big, "1234567890abcdef12345") + testboth("%x", -big, "-1234567890abcdef12345") + testboth("%5x", -big, "-1234567890abcdef12345") + testboth("%22x", -big, "-1234567890abcdef12345") + testboth("%23x", -big, " -1234567890abcdef12345") + testboth("%-23x", -big, "-1234567890abcdef12345 ") + testboth("%023x", -big, "-01234567890abcdef12345") + testboth("%-023x", -big, "-1234567890abcdef12345 ") + testboth("%025x", -big, "-0001234567890abcdef12345") + testboth("%025x", big, "00001234567890abcdef12345") + testboth("%0+25x", big, "+0001234567890abcdef12345") + testboth("%+25x", big, " +1234567890abcdef12345") + testboth("%25x", big, " 1234567890abcdef12345") + testboth("%.2x", big, "1234567890abcdef12345") + testboth("%.21x", big, "1234567890abcdef12345") + testboth("%.22x", big, "01234567890abcdef12345") + testboth("%23.22x", big, " 01234567890abcdef12345") + testboth("%-23.22x", big, "01234567890abcdef12345 ") + testboth("%X", big, "1234567890ABCDEF12345") + testboth("%#X", big, "0X1234567890ABCDEF12345") + testboth("%#x", big, "0x1234567890abcdef12345") + testboth("%#x", -big, "-0x1234567890abcdef12345") + testboth("%#.23x", -big, "-0x001234567890abcdef12345") + testboth("%#+.23x", big, "+0x001234567890abcdef12345") + testboth("%# .23x", big, " 0x001234567890abcdef12345") + testboth("%#+.23X", big, "+0X001234567890ABCDEF12345") + testboth("%#-+.23X", big, "+0X001234567890ABCDEF12345") + testboth("%#-+26.23X", big, "+0X001234567890ABCDEF12345") + testboth("%#-+27.23X", big, "+0X001234567890ABCDEF12345 ") + testboth("%#+27.23X", big, " +0X001234567890ABCDEF12345") # next one gets two leading zeroes from precision, and another from the # 0 flag and the width - testformat("%#+027.23X", big, "+0X0001234567890ABCDEF12345") + testboth("%#+027.23X", big, "+0X0001234567890ABCDEF12345") # same, except no 0 flag - testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345") - testformat("%x", float(big), "123456_______________", 6) + testboth("%#+27.23X", big, " +0X001234567890ABCDEF12345") + testboth("%x", float(big), "123456_______________", 6) big = 0o12345670123456701234567012345670 # 32 octal digits - testformat("%o", big, "12345670123456701234567012345670") - testformat("%o", -big, "-12345670123456701234567012345670") - testformat("%5o", -big, "-12345670123456701234567012345670") - testformat("%33o", -big, "-12345670123456701234567012345670") - testformat("%34o", -big, " -12345670123456701234567012345670") - testformat("%-34o", -big, "-12345670123456701234567012345670 ") - testformat("%034o", -big, "-012345670123456701234567012345670") - testformat("%-034o", -big, "-12345670123456701234567012345670 ") - testformat("%036o", -big, "-00012345670123456701234567012345670") - testformat("%036o", big, "000012345670123456701234567012345670") - testformat("%0+36o", big, "+00012345670123456701234567012345670") - testformat("%+36o", big, " +12345670123456701234567012345670") - testformat("%36o", big, " 12345670123456701234567012345670") - testformat("%.2o", big, "12345670123456701234567012345670") - testformat("%.32o", big, "12345670123456701234567012345670") - testformat("%.33o", big, "012345670123456701234567012345670") - testformat("%34.33o", big, " 012345670123456701234567012345670") - testformat("%-34.33o", big, "012345670123456701234567012345670 ") - testformat("%o", big, "12345670123456701234567012345670") - testformat("%#o", big, "0o12345670123456701234567012345670") - testformat("%#o", -big, "-0o12345670123456701234567012345670") - testformat("%#.34o", -big, "-0o0012345670123456701234567012345670") - testformat("%#+.34o", big, "+0o0012345670123456701234567012345670") - testformat("%# .34o", big, " 0o0012345670123456701234567012345670") - testformat("%#+.34o", big, "+0o0012345670123456701234567012345670") - testformat("%#-+.34o", big, "+0o0012345670123456701234567012345670") - testformat("%#-+37.34o", big, "+0o0012345670123456701234567012345670") - testformat("%#+37.34o", big, "+0o0012345670123456701234567012345670") + testboth("%o", big, "12345670123456701234567012345670") + testboth("%o", -big, "-12345670123456701234567012345670") + testboth("%5o", -big, "-12345670123456701234567012345670") + testboth("%33o", -big, "-12345670123456701234567012345670") + testboth("%34o", -big, " -12345670123456701234567012345670") + testboth("%-34o", -big, "-12345670123456701234567012345670 ") + testboth("%034o", -big, "-012345670123456701234567012345670") + testboth("%-034o", -big, "-12345670123456701234567012345670 ") + testboth("%036o", -big, "-00012345670123456701234567012345670") + testboth("%036o", big, "000012345670123456701234567012345670") + testboth("%0+36o", big, "+00012345670123456701234567012345670") + testboth("%+36o", big, " +12345670123456701234567012345670") + testboth("%36o", big, " 12345670123456701234567012345670") + testboth("%.2o", big, "12345670123456701234567012345670") + testboth("%.32o", big, "12345670123456701234567012345670") + testboth("%.33o", big, "012345670123456701234567012345670") + testboth("%34.33o", big, " 012345670123456701234567012345670") + testboth("%-34.33o", big, "012345670123456701234567012345670 ") + testboth("%o", big, "12345670123456701234567012345670") + testboth("%#o", big, "0o12345670123456701234567012345670") + testboth("%#o", -big, "-0o12345670123456701234567012345670") + testboth("%#.34o", -big, "-0o0012345670123456701234567012345670") + testboth("%#+.34o", big, "+0o0012345670123456701234567012345670") + testboth("%# .34o", big, " 0o0012345670123456701234567012345670") + testboth("%#+.34o", big, "+0o0012345670123456701234567012345670") + testboth("%#-+.34o", big, "+0o0012345670123456701234567012345670") + testboth("%#-+37.34o", big, "+0o0012345670123456701234567012345670") + testboth("%#+37.34o", big, "+0o0012345670123456701234567012345670") # next one gets one leading zero from precision - testformat("%.33o", big, "012345670123456701234567012345670") + testboth("%.33o", big, "012345670123456701234567012345670") # base marker shouldn't change that, since "0" is redundant - testformat("%#.33o", big, "0o012345670123456701234567012345670") + testboth("%#.33o", big, "0o012345670123456701234567012345670") # but reduce precision, and base marker should add a zero - testformat("%#.32o", big, "0o12345670123456701234567012345670") + testboth("%#.32o", big, "0o12345670123456701234567012345670") # one leading zero from precision, and another from "0" flag & width - testformat("%034.33o", big, "0012345670123456701234567012345670") + testboth("%034.33o", big, "0012345670123456701234567012345670") # base marker shouldn't change that - testformat("%0#34.33o", big, "0o012345670123456701234567012345670") - testformat("%o", float(big), "123456__________________________", 6) + testboth("%0#34.33o", big, "0o012345670123456701234567012345670") + testboth("%o", float(big), "123456__________________________", 6) # Some small ints, in both Python int and flavors). - testformat("%d", 42, "42") - testformat("%d", -42, "-42") - testformat("%d", 42, "42") - testformat("%d", -42, "-42") - testformat("%d", 42.0, "42") - testformat("%#x", 1, "0x1") - 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") - testformat("%#o", 0, "0o0") - testformat("%o", 0, "0") - testformat("%o", 0, "0") - testformat("%d", 0, "0") - testformat("%d", 0, "0") - testformat("%#x", 0, "0x0") - testformat("%#x", 0, "0x0") - testformat("%#X", 0, "0X0") - testformat("%#X", 0, "0X0") - testformat("%x", 0x42, "42") - 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") + testboth("%d", 42, "42") + testboth("%d", -42, "-42") + testboth("%d", 42, "42") + testboth("%d", -42, "-42") + testboth("%d", 42.0, "42") + testboth("%#x", 1, "0x1") + testboth("%#x", 1, "0x1") + testboth("%#X", 1, "0X1") + testboth("%#X", 1, "0X1") + testboth("%#x", 1.0, "0x1") + testboth("%#o", 1, "0o1") + testboth("%#o", 1, "0o1") + testboth("%#o", 0, "0o0") + testboth("%#o", 0, "0o0") + testboth("%o", 0, "0") + testboth("%o", 0, "0") + testboth("%d", 0, "0") + testboth("%d", 0, "0") + testboth("%#x", 0, "0x0") + testboth("%#x", 0, "0x0") + testboth("%#X", 0, "0X0") + testboth("%#X", 0, "0X0") + testboth("%x", 0x42, "42") + testboth("%x", -0x42, "-42") + testboth("%x", 0x42, "42") + testboth("%x", -0x42, "-42") + testboth("%x", float(0x42), "42") + testboth("%o", 0o42, "42") + testboth("%o", -0o42, "-42") + testboth("%o", 0o42, "42") + testboth("%o", -0o42, "-42") + testboth("%o", float(0o42), "42") testformat("%r", "\u0378", "'\\u0378'") # non printable - testformat("%a", "\u0378", "'\\u0378'") # non printable + testboth("%a", "\u0378", "'\\u0378'") # non printable testformat("%r", "\u0374", "'\u0374'") # printable - testformat("%a", "\u0374", "'\\u0374'") # printable + testboth("%a", "\u0374", "'\\u0374'") # printable # alternate float formatting - testformat('%g', 1.1, '1.1') - testformat('%#g', 1.1, '1.10000') + testboth('%g', 1.1, '1.1') + testboth('%#g', 1.1, '1.10000') # Test exception for unknown format characters if verbose: diff -r 82b58807f481 Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c Sat Nov 16 19:10:57 2013 +0200 +++ b/Modules/_datetimemodule.c Fri Jan 17 03:29:05 2014 -0600 @@ -2843,6 +2843,9 @@ {"__format__", (PyCFunction)date_format, METH_VARARGS, PyDoc_STR("Formats self with strftime.")}, + {"__ascii__", (PyCFunction)date_str, METH_NOARGS, + PyDoc_STR("Formats self in ASCII format.")}, + {"timetuple", (PyCFunction)date_timetuple, METH_NOARGS, PyDoc_STR("Return time tuple, compatible with time.localtime().")}, @@ -3865,6 +3868,9 @@ {"__format__", (PyCFunction)date_format, METH_VARARGS, PyDoc_STR("Formats self with strftime.")}, + {"__ascii__", (PyCFunction)time_str, METH_NOARGS, + PyDoc_STR("Formats self in ASCII format.")}, + {"utcoffset", (PyCFunction)time_utcoffset, METH_NOARGS, PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, diff -r 82b58807f481 Objects/abstract.c --- a/Objects/abstract.c Sat Nov 16 19:10:57 2013 +0200 +++ b/Objects/abstract.c Fri Jan 17 03:29:05 2014 -0600 @@ -687,8 +687,9 @@ Py_DECREF(meth); if (result && !PyUnicode_Check(result)) { - PyErr_SetString(PyExc_TypeError, - "__format__ method did not return string"); + PyErr_Format(PyExc_TypeError, + "__format__ must return a str, not %.200s", + Py_TYPE(result)->tp_name); Py_DECREF(result); result = NULL; goto done; diff -r 82b58807f481 Objects/bytesobject.c --- a/Objects/bytesobject.c Sat Nov 16 19:10:57 2013 +0200 +++ b/Objects/bytesobject.c Fri Jan 17 03:29:05 2014 -0600 @@ -359,8 +359,629 @@ ret = PyBytes_FromFormatV(format, vargs); va_end(vargs); return ret; +} + +/* Helpers for formatstring */ + +Py_LOCAL_INLINE(PyObject *) +getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) +{ + Py_ssize_t argidx = *p_argidx; + if (argidx < arglen) { + (*p_argidx)++; + if (arglen < 0) + return args; + else + return PyTuple_GetItem(args, argidx); + } + PyErr_SetString(PyExc_TypeError, + "not enough arguments for format string"); + return NULL; } +/* Format codes + * F_LJUST '-' + * F_SIGN '+' + * F_BLANK ' ' + * F_ALT '#' + * F_ZERO '0' + */ +#define F_LJUST (1<<0) +#define F_SIGN (1<<1) +#define F_BLANK (1<<2) +#define F_ALT (1<<3) +#define F_ZERO (1<<4) + +/* Returns a new reference to a PyBytes object, or NULL on failure. */ + +static PyObject * +formatfloat(PyObject *v, int flags, int prec, int type) +{ + char *p; + PyObject *result; + double x; + + x = PyFloat_AsDouble(v); + if (x == -1.0 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "float argument required, " + "not %.200s", Py_TYPE(v)->tp_name); + return NULL; + } + + if (prec < 0) + prec = 6; + + p = PyOS_double_to_string(x, type, prec, + (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL); + + if (p == NULL) + return NULL; + result = PyBytes_FromStringAndSize(p, strlen(p)); + PyMem_Free(p); + return result; +} + +/* _PyBytes_FormatLong emulates the format codes d, u, o, x and X, and + * the F_ALT flag, for Python's long (unbounded) ints. It's not used for + * Python's regular ints. + * Return value: a new PyBytes*, or NULL if error. + * . *pbuf is set to point into it, + * *plen set to the # of chars following that. + * Caller must decref it when done using pbuf. + * The string starting at *pbuf is of the form + * "-"? ("0x" | "0X")? digit+ + * "0x"/"0X" are present only for x and X conversions, with F_ALT + * set in flags. The case of hex digits will be correct, + * There will be at least prec digits, zero-filled on the left if + * necessary to get that many. + * val object to be converted + * flags bitmask of format flags; only F_ALT is looked at + * prec minimum number of digits; 0-fill on left if needed + * type a character in [duoxX]; u acts the same as d + * + * CAUTION: o, x and X conversions on regular ints can never + * produce a '-' sign, but can for Python's unbounded ints. + */ + +PyObject *_PyUnicode_FormatLong(PyObject *, int, int, int); + +static PyObject * +_PyBytes_FormatLong(PyObject *val, int flags, int prec, int type, + char **pbuf, int *plen) +{ + PyObject *s; + PyObject *result = NULL; + + s = _PyUnicode_FormatLong(val, flags & F_ALT, prec, type); + if (!s) + return NULL; + result = _PyUnicode_AsASCIIString(s, "strict"); + Py_DECREF(s); + if (!result) + return NULL; + *pbuf = PyBytes_AS_STRING(result); + *plen = PyBytes_GET_SIZE(result); + return result; +} + +Py_LOCAL_INLINE(int) +formatchar(char *buf, size_t buflen, PyObject *v) +{ + /* presume that the buffer is at least 2 characters long */ + if (PyBytes_Check(v)) { + if (!PyArg_Parse(v, "c;%c requires int or single byte", &buf[0])) + return -1; + } + else { + long ival = PyLong_AsLong(v); + if (ival == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "%c requires int or length one bytes object"); + return -1; + } + if (ival < 0 || ival > 255) { + PyErr_SetString(PyExc_TypeError, + "%c requires an integer in the range 0 to 255"); + return -1; + } + buf[0] = ival; + } + buf[1] = '\0'; + return 1; +} + +/* call __ascii__ on an object, return bytes */ +static PyObject * +format_ascii(PyObject *v) +{ + PyObject *func; + PyObject *temp; + PyObject *r; + _Py_IDENTIFIER(__ascii__); + func = _PyObject_LookupSpecial(v, &PyId___ascii__); + if (func == NULL) { + PyErr_Format(PyExc_TypeError, + "Type %.100s doesn't define __ascii__", + Py_TYPE(v)->tp_name); + return NULL; + } + temp = PyObject_CallFunctionObjArgs(func, NULL); + Py_DECREF(func); + if (temp == NULL) + return NULL; + r = _PyUnicode_AsASCIIString(temp, "strict"); + Py_DECREF(temp); + return r; +} + +static PyObject * +format_obj(PyObject *v) +{ + PyObject *result = NULL; + PyObject *func; + _Py_IDENTIFIER(__bytes__); + + /* is it a bytes object? */ + if (PyBytes_Check(v)) { + result = v; + Py_INCREF(v); + return result; + } + + /* does it support __bytes__? */ + func = _PyObject_LookupSpecial(v, &PyId___bytes__); + if (func != NULL) { + result = PyObject_CallFunctionObjArgs(func, NULL); + Py_DECREF(func); + if (result == NULL) + return NULL; + if (!PyBytes_Check(result)) { + PyErr_Format(PyExc_TypeError, + "__bytes__ returned non-bytes (type %.200s)", + Py_TYPE(result)->tp_name); + Py_DECREF(result); + return NULL; + } + return result; + } + + /* does it support __ascii__? */ + return format_ascii(v); +} + +/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) + + FORMATBUFLEN is the length of the buffer in which the ints & + chars are formatted. XXX This is a magic number. Each formatting + routine does bounds checking to ensure no overflow, but a better + solution may be to malloc a buffer of appropriate size for each + format. For now, the current solution is sufficient. +*/ +#define FORMATBUFLEN (size_t)120 + +PyObject * +PyBytes_Format(PyObject *format, PyObject *args) +{ + char *fmt, *res; + Py_ssize_t arglen, argidx; + Py_ssize_t reslen, rescnt, fmtcnt; + int args_owned = 0; + PyObject *result; + PyObject *dict = NULL; + if (format == NULL || !PyBytes_Check(format) || args == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + fmt = PyBytes_AS_STRING(format); + fmtcnt = PyBytes_GET_SIZE(format); + reslen = rescnt = fmtcnt + 100; + result = PyBytes_FromStringAndSize((char *)NULL, reslen); + if (result == NULL) + return NULL; + res = PyBytes_AsString(result); + if (PyTuple_Check(args)) { + arglen = PyTuple_GET_SIZE(args); + argidx = 0; + } + else { + arglen = -1; + argidx = -2; + } + if (Py_TYPE(args)->tp_as_mapping && Py_TYPE(args)->tp_as_mapping->mp_subscript && + !PyTuple_Check(args) && !PyUnicode_Check(args)) + dict = args; + while (--fmtcnt >= 0) { + if (*fmt != '%') { + if (--rescnt < 0) { + rescnt = fmtcnt + 100; + reslen += rescnt; + if (_PyBytes_Resize(&result, reslen)) + return NULL; + res = PyBytes_AS_STRING(result) + + reslen - rescnt; + --rescnt; + } + *res++ = *fmt++; + } + else { + /* Got a format specifier */ + int flags = 0; + Py_ssize_t width = -1; + int prec = -1; + int c = '\0'; + int fill; + int isnumok; + PyObject *v = NULL; + PyObject *temp = NULL; + PyObject *temp2; + char *pbuf; + int sign; + Py_ssize_t len; + char formatbuf[FORMATBUFLEN]; + /* For format{int,char}() */ + + fmt++; + if (*fmt == '(') { + char *keystart; + Py_ssize_t keylen; + PyObject *key; + int pcount = 1; + + if (dict == NULL) { + PyErr_SetString(PyExc_TypeError, + "format requires a mapping"); + goto error; + } + ++fmt; + --fmtcnt; + keystart = fmt; + /* Skip over balanced parentheses */ + while (pcount > 0 && --fmtcnt >= 0) { + if (*fmt == ')') + --pcount; + else if (*fmt == '(') + ++pcount; + fmt++; + } + keylen = fmt - keystart - 1; + if (fmtcnt < 0 || pcount > 0) { + PyErr_SetString(PyExc_ValueError, + "incomplete format key"); + goto error; + } + key = PyBytes_FromStringAndSize(keystart, + keylen); + if (key == NULL) + goto error; + if (args_owned) { + Py_DECREF(args); + args_owned = 0; + } + args = PyObject_GetItem(dict, key); + Py_DECREF(key); + if (args == NULL) { + goto error; + } + args_owned = 1; + arglen = -1; + argidx = -2; + } + while (--fmtcnt >= 0) { + switch (c = *fmt++) { + case '-': flags |= F_LJUST; continue; + case '+': flags |= F_SIGN; continue; + case ' ': flags |= F_BLANK; continue; + case '#': flags |= F_ALT; continue; + case '0': flags |= F_ZERO; continue; + } + break; + } + if (c == '*') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto error; + if (!PyLong_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "* wants int"); + goto error; + } + width = PyLong_AsSsize_t(v); + if (width == -1 && PyErr_Occurred()) + goto error; + if (width < 0) { + flags |= F_LJUST; + width = -width; + } + if (--fmtcnt >= 0) + c = *fmt++; + } + else if (c >= 0 && isdigit(c)) { + width = c - '0'; + while (--fmtcnt >= 0) { + c = Py_CHARMASK(*fmt++); + if (!isdigit(c)) + break; + if (width > (PY_SSIZE_T_MAX - ((int)c - '0')) / 10) { + PyErr_SetString( + PyExc_ValueError, + "width too big"); + goto error; + } + width = width*10 + (c - '0'); + } + } + if (c == '.') { + prec = 0; + if (--fmtcnt >= 0) + c = *fmt++; + if (c == '*') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto error; + if (!PyLong_Check(v)) { + PyErr_SetString( + PyExc_TypeError, + "* wants int"); + goto error; + } + prec = PyLong_AsSsize_t(v); + if (prec == -1 && PyErr_Occurred()) + goto error; + if (prec < 0) + prec = 0; + if (--fmtcnt >= 0) + c = *fmt++; + } + else if (c >= 0 && isdigit(c)) { + prec = c - '0'; + while (--fmtcnt >= 0) { + c = Py_CHARMASK(*fmt++); + if (!isdigit(c)) + break; + if (prec > (INT_MAX - ((int)c - '0')) / 10) { + PyErr_SetString( + PyExc_ValueError, + "prec too big"); + goto error; + } + prec = prec*10 + (c - '0'); + } + } + } /* prec */ + if (fmtcnt >= 0) { + if (c == 'h' || c == 'l' || c == 'L') { + if (--fmtcnt >= 0) + c = *fmt++; + } + } + if (fmtcnt < 0) { + PyErr_SetString(PyExc_ValueError, + "incomplete format"); + goto error; + } + if (c != '%') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto error; + } + sign = 0; + fill = ' '; + switch (c) { + case '%': + pbuf = "%"; + len = 1; + break; + case 'a': + case 'r': + temp2 = PyObject_ASCII(v); + if (temp2 == NULL) + goto error; + temp = PyUnicode_AsLatin1String(temp2); + Py_DECREF(temp2); + if (temp == NULL) + goto error; + pbuf = PyBytes_AS_STRING(temp); + len = PyBytes_GET_SIZE(temp); + if (prec >= 0 && len > prec) + len = prec; + break; + case 's': + temp = format_obj(v); + if (temp == NULL) + goto error; + if (!PyBytes_Check(temp)) { /* redundant? */ + PyErr_Format(PyExc_TypeError, + "bytes object required, got %.200s", + Py_TYPE(temp)->tp_name); + Py_DECREF(temp); + goto error; + } + pbuf = PyBytes_AS_STRING(temp); + len = PyBytes_GET_SIZE(temp); + if (prec >= 0 && len > prec) + len = prec; + break; + case 'i': + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + if (c == 'i') + c = 'd'; + isnumok = 0; + if (PyNumber_Check(v)) { + PyObject *iobj=NULL; + + if ((PyLong_Check(v))) { + iobj = v; + Py_INCREF(iobj); + } + else { + iobj = PyNumber_Long(v); + } + if (iobj!=NULL) { + if (PyLong_Check(iobj)) { + int ilen; + + isnumok = 1; + temp = _PyBytes_FormatLong(iobj, flags, + prec, c, &pbuf, &ilen); + Py_DECREF(iobj); + len = ilen; + if (!temp) + goto error; + sign = 1; + } + else { + Py_DECREF(iobj); + } + } + } + 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'; + break; + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + temp = formatfloat(v, flags, prec, c); + if (temp == NULL) + goto error; + pbuf = PyBytes_AS_STRING(temp); + len = PyBytes_GET_SIZE(temp); + sign = 1; + if (flags & F_ZERO) + fill = '0'; + break; + case 'c': + pbuf = formatbuf; + len = formatchar(pbuf, sizeof(formatbuf), v); + if (len < 0) + goto error; + break; + default: + PyErr_Format(PyExc_ValueError, + "unsupported format character '%c' (0x%x) " + "at index %zd", + c, c, + (Py_ssize_t)(fmt - 1 - + PyBytes_AsString(format))); + goto error; + } + if (sign) { + if (*pbuf == '-' || *pbuf == '+') { + sign = *pbuf++; + len--; + } + else if (flags & F_SIGN) + sign = '+'; + else if (flags & F_BLANK) + sign = ' '; + else + sign = 0; + } + if (width < len) + width = len; + if (rescnt - (sign != 0) < width) { + reslen -= rescnt; + rescnt = width + fmtcnt + 100; + reslen += rescnt; + if (reslen < 0) { + Py_DECREF(result); + Py_XDECREF(temp); + return PyErr_NoMemory(); + } + if (_PyBytes_Resize(&result, reslen)) { + Py_XDECREF(temp); + return NULL; + } + res = PyBytes_AS_STRING(result) + + reslen - rescnt; + } + if (sign) { + if (fill != ' ') + *res++ = sign; + rescnt--; + if (width > len) + width--; + } + if ((flags & F_ALT) && (c == 'x' || c == 'X')) { + assert(pbuf[0] == '0'); + assert(pbuf[1] == c); + if (fill != ' ') { + *res++ = *pbuf++; + *res++ = *pbuf++; + } + rescnt -= 2; + width -= 2; + if (width < 0) + width = 0; + len -= 2; + } + if (width > len && !(flags & F_LJUST)) { + do { + --rescnt; + *res++ = fill; + } while (--width > len); + } + if (fill == ' ') { + if (sign) + *res++ = sign; + if ((flags & F_ALT) && + (c == 'x' || c == 'X')) { + assert(pbuf[0] == '0'); + assert(pbuf[1] == c); + *res++ = *pbuf++; + *res++ = *pbuf++; + } + } + Py_MEMCPY(res, pbuf, len); + res += len; + rescnt -= len; + while (--width >= len) { + --rescnt; + *res++ = ' '; + } + if (dict && (argidx < arglen) && c != '%') { + PyErr_SetString(PyExc_TypeError, + "not all arguments converted during string formatting"); + Py_XDECREF(temp); + goto error; + } + Py_XDECREF(temp); + } /* '%' */ + } /* until end */ + if (argidx < arglen && !dict) { + PyErr_SetString(PyExc_TypeError, + "not all arguments converted during string formatting"); + goto error; + } + if (args_owned) { + Py_DECREF(args); + } + if (_PyBytes_Resize(&result, reslen - rescnt)) + return NULL; + return result; + + error: + Py_DECREF(result); + if (args_owned) { + Py_DECREF(args); + } + return NULL; +} +/* =-= */ + + static void bytes_dealloc(PyObject *op) { @@ -2443,6 +3064,21 @@ }; static PyObject * +bytes_mod(PyObject *v, PyObject *w) +{ + if (!PyBytes_Check(v)) + Py_RETURN_NOTIMPLEMENTED; + return PyBytes_Format(v, w); +} + +static PyNumberMethods bytes_as_number = { + 0, /*nb_add*/ + 0, /*nb_subtract*/ + 0, /*nb_multiply*/ + bytes_mod, /*nb_remainder*/ +}; + +static PyObject * str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static PyObject * @@ -2733,7 +3369,7 @@ 0, /* tp_setattr */ 0, /* tp_reserved */ (reprfunc)bytes_repr, /* tp_repr */ - 0, /* tp_as_number */ + &bytes_as_number, /* tp_as_number */ &bytes_as_sequence, /* tp_as_sequence */ &bytes_as_mapping, /* tp_as_mapping */ (hashfunc)bytes_hash, /* tp_hash */ diff -r 82b58807f481 Objects/floatobject.c --- a/Objects/floatobject.c Sat Nov 16 19:10:57 2013 +0200 +++ b/Objects/floatobject.c Fri Jan 17 03:29:05 2014 -0600 @@ -1756,6 +1756,7 @@ METH_VARARGS|METH_CLASS, float_setformat_doc}, {"__format__", (PyCFunction)float__format__, METH_VARARGS, float__format__doc}, + {"__ascii__", (PyCFunction)float_repr, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff -r 82b58807f481 Objects/longobject.c --- a/Objects/longobject.c Sat Nov 16 19:10:57 2013 +0200 +++ b/Objects/longobject.c Fri Jan 17 03:29:05 2014 -0600 @@ -4902,6 +4902,7 @@ "Rounding with an ndigits argument also returns an integer."}, {"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS}, {"__format__", (PyCFunction)long__format__, METH_VARARGS}, + {"__ascii__", (PyCFunction)long_to_decimal_string, METH_NOARGS}, {"__sizeof__", (PyCFunction)long_sizeof, METH_NOARGS, "Returns size in memory, in bytes"}, {NULL, NULL} /* sentinel */ diff -r 82b58807f481 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Sat Nov 16 19:10:57 2013 +0200 +++ b/Objects/unicodeobject.c Fri Jan 17 03:29:05 2014 -0600 @@ -13651,8 +13651,8 @@ * CAUTION: o, x and X conversions on regular ints can never * produce a '-' sign, but can for Python's unbounded ints. */ -static PyObject* -formatlong(PyObject *val, struct unicode_format_arg_t *arg) +PyObject * +_PyUnicode_FormatLong(PyObject *val, int alt, int prec, int type) { PyObject *result = NULL; char *buf; @@ -13662,8 +13662,6 @@ Py_ssize_t llen; int numdigits; /* len == numnondigits + numdigits */ int numnondigits = 0; - int prec = arg->prec; - int type = arg->ch; /* Avoid exceeding SSIZE_T_MAX */ if (prec > INT_MAX-3) { @@ -13722,7 +13720,7 @@ assert(numdigits > 0); /* Get rid of base marker unless F_ALT */ - if (((arg->flags & F_ALT) == 0 && + if (((alt) == 0 && (type == 'o' || type == 'x' || type == 'X'))) { assert(buf[sign] == '0'); assert(buf[sign+1] == 'x' || buf[sign+1] == 'X' || @@ -13846,7 +13844,7 @@ return 1; } - res = formatlong(iobj, arg); + res = _PyUnicode_FormatLong(iobj, arg->flags & F_ALT, arg->prec, type); Py_DECREF(iobj); if (res == NULL) return -1;