Kaydet (Commit) d0c84124 authored tarafından Eric Smith's avatar Eric Smith

Added '#' formatting to integers. This adds the 0b, 0o, or 0x prefix for bin,…

Added '#' formatting to integers.  This adds the 0b, 0o, or 0x prefix for bin, oct, hex.  There's still one failing case, and I need to finish the docs.  I hope to finish those today.
üst a6864e0d
......@@ -192,6 +192,10 @@ class ModuleTest(unittest.TestCase):
self.assertRaises(ValueError, fmt.format, "{0}", 10, 20, i=100)
self.assertRaises(ValueError, fmt.format, "{i}", 10, 20, i=100)
# Alternate formatting is not supported
self.assertRaises(ValueError, format, '', '#')
self.assertRaises(ValueError, format, '', '#20')
class BytesAliasTest(unittest.TestCase):
def test_builtin(self):
......
......@@ -357,6 +357,40 @@ class TypesTests(unittest.TestCase):
test(1234, "+b", "+10011010010")
test(-1234, "+b", "-10011010010")
# alternate (#) formatting
test(0, "#b", '0b0')
test(0, "-#b", '0b0')
test(1, "-#b", '0b1')
test(-1, "-#b", '-0b1')
test(-1, "-#5b", ' -0b1')
test(1, "+#5b", ' +0b1')
test(100, "+#b", '+0b1100100')
# test(100, "#012b", '0b001100100')
test(0, "#o", '0o0')
test(0, "-#o", '0o0')
test(1, "-#o", '0o1')
test(-1, "-#o", '-0o1')
test(-1, "-#5o", ' -0o1')
test(1, "+#5o", ' +0o1')
test(100, "+#o", '+0o144')
test(0, "#x", '0x0')
test(0, "-#x", '0x0')
test(1, "-#x", '0x1')
test(-1, "-#x", '-0x1')
test(-1, "-#5x", ' -0x1')
test(1, "+#5x", ' +0x1')
test(100, "+#x", '+0x64')
test(0, "#X", '0X0')
test(0, "-#X", '0X0')
test(1, "-#X", '0X1')
test(-1, "-#X", '-0X1')
test(-1, "-#5X", ' -0X1')
test(1, "+#5X", ' +0X1')
test(100, "+#X", '+0X64')
# make sure these are errors
# precision disallowed
......@@ -461,6 +495,9 @@ class TypesTests(unittest.TestCase):
# format spec must be string
self.assertRaises(TypeError, 3L .__format__, None)
self.assertRaises(TypeError, 3L .__format__, 0)
# alternate specifier in wrong place
self.assertRaises(ValueError, 1L .__format__, "#+5x")
self.assertRaises(ValueError, 1L .__format__, "+5#x")
# ensure that only int and float type specifiers work
for format_spec in ([chr(x) for x in range(ord('a'), ord('z')+1)] +
......@@ -579,6 +616,10 @@ class TypesTests(unittest.TestCase):
self.assertRaises(ValueError, format, 1e-100, format_spec)
self.assertRaises(ValueError, format, -1e-100, format_spec)
# Alternate formatting is not supported
self.assertRaises(ValueError, format, 0.0, '#')
self.assertRaises(ValueError, format, 0.0, '#20f')
def test_main():
run_unittest(TypesTests)
......
......@@ -89,6 +89,7 @@ is_sign_element(STRINGLIB_CHAR c)
typedef struct {
STRINGLIB_CHAR fill_char;
STRINGLIB_CHAR align;
int alternate;
STRINGLIB_CHAR sign;
Py_ssize_t width;
Py_ssize_t precision;
......@@ -117,6 +118,7 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
format->fill_char = '\0';
format->align = '\0';
format->alternate = 0;
format->sign = '\0';
format->width = -1;
format->precision = -1;
......@@ -154,6 +156,13 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
++ptr;
}
/* If the next character is #, we're in alternate mode. This only
applies to integers. */
if (end-ptr >= 1 && ptr[0] == '#') {
format->alternate = 1;
++ptr;
}
/* XXX add error checking */
specified_width = get_integer(&ptr, end, &format->width);
......@@ -221,7 +230,8 @@ typedef struct {
and more efficient enough to justify a little obfuscation? */
static void
calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
Py_ssize_t n_digits, const InternalFormatSpec *format)
Py_ssize_t n_prefix, Py_ssize_t n_digits,
const InternalFormatSpec *format)
{
r->n_lpadding = 0;
r->n_spadding = 0;
......@@ -232,13 +242,15 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
r->n_rsign = 0;
/* the output will look like:
| |
| <lpadding> <lsign> <spadding> <digits> <rsign> <rpadding> |
| |
| |
| <lpadding> <lsign> <prefix> <spadding> <digits> <rsign> <rpadding> |
| |
lsign and rsign are computed from format->sign and the actual
sign of the number
prefix is given (it's for the '0x' prefix)
digits is already known
the total width is either given, or computed from the
......@@ -363,6 +375,14 @@ format_string_internal(PyObject *value, const InternalFormatSpec *format)
goto done;
}
/* alternate is not allowed on strings */
if (format->alternate) {
PyErr_SetString(PyExc_ValueError,
"Alternate form (#) not allowed in string format "
"specifier");
goto done;
}
/* '=' alignment not allowed on strings */
if (format->align == '=') {
PyErr_SetString(PyExc_ValueError,
......@@ -505,31 +525,33 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
}
else {
int base;
int leading_chars_to_skip; /* Number of characters added by
PyNumber_ToBase that we want to
skip over. */
int leading_chars_to_skip = 0; /* Number of characters added by
PyNumber_ToBase that we want to
skip over. */
/* Compute the base and how many characters will be added by
PyNumber_ToBase */
switch (format->type) {
case 'b':
base = 2;
leading_chars_to_skip = 2; /* 0b */
if (!format->alternate)
leading_chars_to_skip = 2; /* 0b */
break;
case 'o':
base = 8;
leading_chars_to_skip = 2; /* 0o */
if (!format->alternate)
leading_chars_to_skip = 2; /* 0o */
break;
case 'x':
case 'X':
base = 16;
leading_chars_to_skip = 2; /* 0x */
if (!format->alternate)
leading_chars_to_skip = 2; /* 0x */
break;
default: /* shouldn't be needed, but stops a compiler warning */
case 'd':
case 'n':
base = 10;
leading_chars_to_skip = 0;
break;
}
......@@ -564,7 +586,7 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
0, &n_grouping_chars, 0);
/* Calculate the widths of the various leading and trailing parts */
calc_number_widths(&spec, sign, n_digits + n_grouping_chars, format);
calc_number_widths(&spec, sign, 0, n_digits + n_grouping_chars, format);
/* Allocate a new string to hold the result */
result = STRINGLIB_NEW(NULL, spec.n_total);
......@@ -670,6 +692,14 @@ format_float_internal(PyObject *value,
Py_UNICODE unicodebuf[FLOAT_FORMATBUFLEN];
#endif
/* alternate is not allowed on floats. */
if (format->alternate) {
PyErr_SetString(PyExc_ValueError,
"Alternate form (#) not allowed in float format "
"specifier");
goto done;
}
/* first, do the conversion as 8-bit chars, using the platform's
snprintf. then, if needed, convert to unicode. */
......@@ -730,7 +760,7 @@ format_float_internal(PyObject *value,
--n_digits;
}
calc_number_widths(&spec, sign, n_digits, format);
calc_number_widths(&spec, sign, 0, n_digits, format);
/* allocate a string with enough space */
result = STRINGLIB_NEW(NULL, spec.n_total);
......
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