summaryrefslogtreecommitdiffstats
path: root/Python/formatter_unicode.c
diff options
context:
space:
mode:
authorJohn Belmonte <john@neggie.net>2022-04-11 14:34:18 (GMT)
committerGitHub <noreply@github.com>2022-04-11 14:34:18 (GMT)
commitb0b836b20cb56c225874a4a39ef895f89ab2970f (patch)
treeb333cd2e9ee95021e1fc3b45eee2da0b7ac0ee35 /Python/formatter_unicode.c
parentdd207a6ac52d4bd9a71cf178fc1d5c17a6f07aff (diff)
downloadcpython-b0b836b20cb56c225874a4a39ef895f89ab2970f.zip
cpython-b0b836b20cb56c225874a4a39ef895f89ab2970f.tar.gz
cpython-b0b836b20cb56c225874a4a39ef895f89ab2970f.tar.bz2
bpo-45995: add "z" format specifer to coerce negative 0 to zero (GH-30049)
Add "z" format specifier to coerce negative 0 to zero. See https://github.com/python/cpython/issues/90153 (originally https://bugs.python.org/issue45995) for discussion. This covers `str.format()` and f-strings. Old-style string interpolation is not supported. Co-authored-by: Mark Dickinson <dickinsm@gmail.com>
Diffstat (limited to 'Python/formatter_unicode.c')
-rw-r--r--Python/formatter_unicode.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c
index a1e50e2..04d37c0 100644
--- a/Python/formatter_unicode.c
+++ b/Python/formatter_unicode.c
@@ -130,6 +130,7 @@ typedef struct {
Py_UCS4 fill_char;
Py_UCS4 align;
int alternate;
+ int no_neg_0;
Py_UCS4 sign;
Py_ssize_t width;
enum LocaleType thousands_separators;
@@ -166,6 +167,7 @@ parse_internal_render_format_spec(PyObject *obj,
format->fill_char = ' ';
format->align = default_align;
format->alternate = 0;
+ format->no_neg_0 = 0;
format->sign = '\0';
format->width = -1;
format->thousands_separators = LT_NO_LOCALE;
@@ -193,6 +195,13 @@ parse_internal_render_format_spec(PyObject *obj,
++pos;
}
+ /* If the next character is z, request coercion of negative 0.
+ Applies only to floats. */
+ if (end-pos >= 1 && READ_spec(pos) == 'z') {
+ format->no_neg_0 = 1;
+ ++pos;
+ }
+
/* If the next character is #, we're in alternate mode. This only
applies to integers. */
if (end-pos >= 1 && READ_spec(pos) == '#') {
@@ -779,6 +788,14 @@ format_string_internal(PyObject *value, const InternalFormatSpec *format,
goto done;
}
+ /* negative 0 coercion is not allowed on strings */
+ if (format->no_neg_0) {
+ PyErr_SetString(PyExc_ValueError,
+ "Negative zero coercion (z) not allowed in string format "
+ "specifier");
+ goto done;
+ }
+
/* alternate is not allowed on strings */
if (format->alternate) {
PyErr_SetString(PyExc_ValueError,
@@ -872,6 +889,13 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
"Precision not allowed in integer format specifier");
goto done;
}
+ /* no negative zero coercion on integers */
+ if (format->no_neg_0) {
+ PyErr_SetString(PyExc_ValueError,
+ "Negative zero coercion (z) not allowed in integer"
+ " format specifier");
+ goto done;
+ }
/* special case for character formatting */
if (format->type == 'c') {
@@ -1049,6 +1073,8 @@ format_float_internal(PyObject *value,
if (format->alternate)
flags |= Py_DTSF_ALT;
+ if (format->no_neg_0)
+ flags |= Py_DTSF_NO_NEG_0;
if (type == '\0') {
/* Omitted type specifier. Behaves in the same way as repr(x)
@@ -1238,6 +1264,8 @@ format_complex_internal(PyObject *value,
if (format->alternate)
flags |= Py_DTSF_ALT;
+ if (format->no_neg_0)
+ flags |= Py_DTSF_NO_NEG_0;
if (type == '\0') {
/* Omitted type specifier. Should be like str(self). */