diff options
author | Eric V. Smith <eric@trueblade.com> | 2016-09-10 03:06:47 (GMT) |
---|---|---|
committer | Eric V. Smith <eric@trueblade.com> | 2016-09-10 03:06:47 (GMT) |
commit | 89e1b1aae0775341735de6bc5e97b3c1e9cea0fa (patch) | |
tree | cadcc5860ce497d17783b2af9901d9bb71ee1820 /Python | |
parent | 37d398ebd1b177001df231b9bba17429ac61ff12 (diff) | |
download | cpython-89e1b1aae0775341735de6bc5e97b3c1e9cea0fa.zip cpython-89e1b1aae0775341735de6bc5e97b3c1e9cea0fa.tar.gz cpython-89e1b1aae0775341735de6bc5e97b3c1e9cea0fa.tar.bz2 |
Issue 27080: PEP 515: add '_' formatting option.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/formatter_unicode.c | 72 |
1 files changed, 51 insertions, 21 deletions
diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c index db9f5b8..95c507e 100644 --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -32,14 +32,20 @@ invalid_comma_type(Py_UCS4 presentation_type) { if (presentation_type > 32 && presentation_type < 128) PyErr_Format(PyExc_ValueError, - "Cannot specify ',' with '%c'.", + "Cannot specify ',' or '_' with '%c'.", (char)presentation_type); else PyErr_Format(PyExc_ValueError, - "Cannot specify ',' with '\\x%x'.", + "Cannot specify ',' or '_' with '\\x%x'.", (unsigned int)presentation_type); } +static void +invalid_comma_and_underscore() +{ + PyErr_Format(PyExc_ValueError, "Cannot specify both ',' and '_'."); +} + /* get_integer consumes 0 or more decimal digit characters from an input string, updates *result with the corresponding positive @@ -108,6 +114,12 @@ is_sign_element(Py_UCS4 c) } } +/* Locale type codes. LT_NO_LOCALE must be zero. */ +#define LT_NO_LOCALE 0 +#define LT_DEFAULT_LOCALE 1 +#define LT_UNDERSCORE_LOCALE 2 +#define LT_UNDER_FOUR_LOCALE 3 +#define LT_CURRENT_LOCALE 4 typedef struct { Py_UCS4 fill_char; @@ -223,9 +235,22 @@ parse_internal_render_format_spec(PyObject *format_spec, /* Comma signifies add thousands separators */ if (end-pos && READ_spec(pos) == ',') { - format->thousands_separators = 1; + format->thousands_separators = LT_DEFAULT_LOCALE; ++pos; } + /* Underscore signifies add thousands separators */ + if (end-pos && READ_spec(pos) == '_') { + if (format->thousands_separators != 0) { + invalid_comma_and_underscore(); + return 0; + } + format->thousands_separators = LT_UNDERSCORE_LOCALE; + ++pos; + } + if (end-pos && READ_spec(pos) == ',') { + invalid_comma_and_underscore(); + return 0; + } /* Parse field precision */ if (end-pos && READ_spec(pos) == '.') { @@ -275,6 +300,16 @@ parse_internal_render_format_spec(PyObject *format_spec, case '\0': /* These are allowed. See PEP 378.*/ break; + case 'b': + case 'o': + case 'x': + case 'X': + /* Underscores are allowed in bin/oct/hex. See PEP 515. */ + if (format->thousands_separators == LT_UNDERSCORE_LOCALE) { + /* Every four digits, not every three, in bin/oct/hex. */ + format->thousands_separators = LT_UNDER_FOUR_LOCALE; + break; + } default: invalid_comma_type(format->type); return 0; @@ -351,11 +386,6 @@ fill_padding(_PyUnicodeWriter *writer, /*********** common routines for numeric formatting *********************/ /************************************************************************/ -/* Locale type codes. */ -#define LT_CURRENT_LOCALE 0 -#define LT_DEFAULT_LOCALE 1 -#define LT_NO_LOCALE 2 - /* Locale info needed for formatting integers and the part of floats before and including the decimal. Note that locales only support 8-bit chars, not unicode. */ @@ -667,8 +697,8 @@ static const char no_grouping[1] = {CHAR_MAX}; /* Find the decimal point character(s?), thousands_separator(s?), and grouping description, either for the current locale if type is - LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE, or - none if LT_NO_LOCALE. */ + LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE or + LT_UNDERSCORE_LOCALE/LT_UNDER_FOUR_LOCALE, or none if LT_NO_LOCALE. */ static int get_locale_info(int type, LocaleInfo *locale_info) { @@ -691,16 +721,22 @@ get_locale_info(int type, LocaleInfo *locale_info) break; } case LT_DEFAULT_LOCALE: + case LT_UNDERSCORE_LOCALE: + case LT_UNDER_FOUR_LOCALE: locale_info->decimal_point = PyUnicode_FromOrdinal('.'); - locale_info->thousands_sep = PyUnicode_FromOrdinal(','); + locale_info->thousands_sep = PyUnicode_FromOrdinal( + type == LT_DEFAULT_LOCALE ? ',' : '_'); if (!locale_info->decimal_point || !locale_info->thousands_sep) { Py_XDECREF(locale_info->decimal_point); Py_XDECREF(locale_info->thousands_sep); return -1; } - locale_info->grouping = "\3"; /* Group every 3 characters. The + if (type != LT_UNDER_FOUR_LOCALE) + locale_info->grouping = "\3"; /* Group every 3 characters. The (implicit) trailing 0 means repeat infinitely. */ + else + locale_info->grouping = "\4"; /* Bin/oct/hex group every four. */ break; case LT_NO_LOCALE: locale_info->decimal_point = PyUnicode_FromOrdinal('.'); @@ -952,9 +988,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format, /* Determine the grouping, separator, and decimal point, if any. */ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), + format->thousands_separators, &locale) == -1) goto done; @@ -1099,9 +1133,7 @@ format_float_internal(PyObject *value, /* Determine the grouping, separator, and decimal point, if any. */ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), + format->thousands_separators, &locale) == -1) goto done; @@ -1277,9 +1309,7 @@ format_complex_internal(PyObject *value, /* Determine the grouping, separator, and decimal point, if any. */ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), + format->thousands_separators, &locale) == -1) goto done; |