Skip to content

Commit 82a89b3

Browse files
authored
gh-158451: Reuse PyUnicodeWriter_WriteStr() in PyUnicode_Format() (#158467)
Remove special case for int in PyUnicode_Format(). Instead, reuse PyUnicodeWriter_WriteStr() and PyUnicodeWriter_WriteRepr() in PyUnicode_Format(). Add PyUnicode_Format() tests on integer formats.
1 parent c3cb468 commit 82a89b3

3 files changed

Lines changed: 47 additions & 24 deletions

File tree

‎Lib/test/test_format.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ def test_common_format(self):
240240
testcommon("%d", 42, "42")
241241
testcommon("%d", -42, "-42")
242242
testcommon("%d", 42.0, "42")
243+
testcommon("%#d", 42, "42")
244+
testcommon("%#d", -42, "-42")
243245
testcommon("%#x", 1, "0x1")
244246
testcommon("%#X", 1, "0X1")
245247
testcommon("%#o", 1, "0o1")
@@ -250,8 +252,12 @@ def test_common_format(self):
250252
testcommon("%#X", 0, "0X0")
251253
testcommon("%x", 0x42, "42")
252254
testcommon("%x", -0x42, "-42")
255+
testcommon("%#x", 0x42, "0x42")
256+
testcommon("%#x", -0x42, "-0x42")
253257
testcommon("%o", 0o42, "42")
254258
testcommon("%o", -0o42, "-42")
259+
testcommon("%#o", 0o42, "0o42")
260+
testcommon("%#o", -0o42, "-0o42")
255261
# alternate float formatting
256262
testcommon('%g', 1.1, '1.1')
257263
testcommon('%#g', 1.1, '1.10000')
@@ -344,12 +350,21 @@ def test_common_format(self):
344350
"format argument 1: %g requires a real number, not str")
345351

346352
def test_str_format(self):
353+
testformat("%s", "abc", "abc")
347354
testformat("%r", "\u0378", "'\\u0378'") # non printable
348355
testformat("%a", "\u0378", "'\\u0378'") # non printable
349356
testformat("%r", "\u0374", "'\u0374'") # printable
350357
testformat("%a", "\u0374", "'\\u0374'") # printable
351358
testformat('%(x)r', {'x': 1}, '1')
352359

360+
# Some small ints
361+
for fmt in ('s', 'r', 'a'):
362+
with self.subTest(fmt=fmt):
363+
testformat("%" + fmt, 42, "42")
364+
testformat("%#" + fmt, 42, "42")
365+
testformat("%" + fmt, -42, "-42")
366+
testformat("%#" + fmt, -42, "-42")
367+
353368
# Test exception for unknown format characters, etc.
354369
if verbose:
355370
print('Testing exceptions')

‎Objects/unicode_format.c‎

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,7 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
571571
arg->ch = FORMAT_READ(ctx);
572572
ctx->fmtpos++;
573573
}
574+
assert(arg->width >= 0);
574575
}
575576
else if (arg->ch >= '0' && arg->ch <= '9') {
576577
arg->width = arg->ch - '0';
@@ -590,6 +591,7 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
590591
}
591592
arg->width = arg->width*10 + (arg->ch - '0');
592593
}
594+
assert(arg->width >= 0);
593595
}
594596

595597
/* Parse precision. Example: "%.3f" => prec=3 */
@@ -645,6 +647,7 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
645647
arg->prec = arg->prec*10 + (arg->ch - '0');
646648
}
647649
}
650+
assert(arg->prec >= 0);
648651
}
649652

650653
/* Ignore "h", "l" and "L" format prefix (ex: "%hi" or "%ls") */
@@ -701,24 +704,27 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
701704
case 's':
702705
case 'r':
703706
case 'a':
704-
if (PyLong_CheckExact(v) && arg->width == -1 && arg->prec == -1) {
705-
/* Fast path */
706-
if (_PyLong_FormatWriter(writer, v, 10, arg->flags & F_ALT) == -1)
707-
return -1;
708-
return 1;
707+
if (arg->width < 0 && arg->prec < 0) {
708+
if (arg->ch == 's') {
709+
if (PyUnicodeWriter_WriteStr((PyUnicodeWriter*)writer, v) < 0) {
710+
return -1;
711+
}
712+
return 1;
713+
}
714+
else if (arg->ch == 'r') {
715+
if (PyUnicodeWriter_WriteRepr((PyUnicodeWriter*)writer, v) < 0) {
716+
return -1;
717+
}
718+
return 1;
719+
}
709720
}
710721

711-
if (PyUnicode_CheckExact(v) && arg->ch == 's') {
712-
*p_str = Py_NewRef(v);
713-
}
714-
else {
715-
if (arg->ch == 's')
716-
*p_str = PyObject_Str(v);
717-
else if (arg->ch == 'r')
718-
*p_str = PyObject_Repr(v);
719-
else
720-
*p_str = PyObject_ASCII(v);
721-
}
722+
if (arg->ch == 's')
723+
*p_str = PyObject_Str(v);
724+
else if (arg->ch == 'r')
725+
*p_str = PyObject_Repr(v);
726+
else
727+
*p_str = PyObject_ASCII(v);
722728
break;
723729

724730
case 'i':

‎Objects/unicode_writer.c‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -285,45 +285,47 @@ _PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, PyObject *str)
285285

286286

287287
int
288-
PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
288+
PyUnicodeWriter_WriteStr(PyUnicodeWriter *pub_writer, PyObject *obj)
289289
{
290+
_PyUnicodeWriter *writer = (_PyUnicodeWriter*)pub_writer;
290291
PyTypeObject *type = Py_TYPE(obj);
291292
if (type == &PyUnicode_Type) {
292-
return _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, obj);
293+
return _PyUnicodeWriter_WriteStr(writer, obj);
293294
}
294295

295296
if (type == &PyLong_Type) {
296-
return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0);
297+
return _PyLong_FormatWriter(writer, obj, 10, 0);
297298
}
298299

299300
PyObject *str = PyObject_Str(obj);
300301
if (str == NULL) {
301302
return -1;
302303
}
303304

304-
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
305+
int res = _PyUnicodeWriter_WriteStr(writer, str);
305306
Py_DECREF(str);
306307
return res;
307308
}
308309

309310

310311
int
311-
PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
312+
PyUnicodeWriter_WriteRepr(PyUnicodeWriter *pub_writer, PyObject *obj)
312313
{
314+
_PyUnicodeWriter *writer = (_PyUnicodeWriter*)pub_writer;
313315
if (obj == NULL) {
314-
return _PyUnicodeWriter_WriteASCIIString((_PyUnicodeWriter*)writer, "<NULL>", 6);
316+
return _PyUnicodeWriter_WriteASCIIString(writer, "<NULL>", 6);
315317
}
316318

317319
if (Py_TYPE(obj) == &PyLong_Type) {
318-
return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0);
320+
return _PyLong_FormatWriter(writer, obj, 10, 0);
319321
}
320322

321323
PyObject *repr = PyObject_Repr(obj);
322324
if (repr == NULL) {
323325
return -1;
324326
}
325327

326-
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, repr);
328+
int res = _PyUnicodeWriter_WriteStr(writer, repr);
327329
Py_DECREF(repr);
328330
return res;
329331
}

0 commit comments

Comments
 (0)