https://github.com/python/cpython/commit/82a89b38aa48688c593f7888964b153015d38462
commit: 82a89b38aa48688c593f7888964b153015d38462
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-09-30T05:30:22+02:00
summary:

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.

files:
M Lib/test/test_format.py
M Objects/unicode_format.c
M Objects/unicode_writer.c

diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
index 5d322cb444cfb6..a556faae252fa5 100644
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -240,6 +240,8 @@ def test_common_format(self):
         testcommon("%d", 42, "42")
         testcommon("%d", -42, "-42")
         testcommon("%d", 42.0, "42")
+        testcommon("%#d", 42, "42")
+        testcommon("%#d", -42, "-42")
         testcommon("%#x", 1, "0x1")
         testcommon("%#X", 1, "0X1")
         testcommon("%#o", 1, "0o1")
@@ -250,8 +252,12 @@ def test_common_format(self):
         testcommon("%#X", 0, "0X0")
         testcommon("%x", 0x42, "42")
         testcommon("%x", -0x42, "-42")
+        testcommon("%#x", 0x42, "0x42")
+        testcommon("%#x", -0x42, "-0x42")
         testcommon("%o", 0o42, "42")
         testcommon("%o", -0o42, "-42")
+        testcommon("%#o", 0o42, "0o42")
+        testcommon("%#o", -0o42, "-0o42")
         # alternate float formatting
         testcommon('%g', 1.1, '1.1')
         testcommon('%#g', 1.1, '1.10000')
@@ -344,12 +350,21 @@ def test_common_format(self):
                         "format argument 1: %g requires a real number, not 
str")
 
     def test_str_format(self):
+        testformat("%s", "abc", "abc")
         testformat("%r", "\u0378", "'\\u0378'")  # non printable
         testformat("%a", "\u0378", "'\\u0378'")  # non printable
         testformat("%r", "\u0374", "'\u0374'")   # printable
         testformat("%a", "\u0374", "'\\u0374'")  # printable
         testformat('%(x)r', {'x': 1}, '1')
 
+        # Some small ints
+        for fmt in ('s', 'r', 'a'):
+            with self.subTest(fmt=fmt):
+                testformat("%" + fmt, 42, "42")
+                testformat("%#" + fmt, 42, "42")
+                testformat("%" + fmt, -42, "-42")
+                testformat("%#" + fmt, -42, "-42")
+
         # Test exception for unknown format characters, etc.
         if verbose:
             print('Testing exceptions')
diff --git a/Objects/unicode_format.c b/Objects/unicode_format.c
index 1d6f3f7d9a6f6a..caadf18f6a5d30 100644
--- a/Objects/unicode_format.c
+++ b/Objects/unicode_format.c
@@ -571,6 +571,7 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
             arg->ch = FORMAT_READ(ctx);
             ctx->fmtpos++;
         }
+        assert(arg->width >= 0);
     }
     else if (arg->ch >= '0' && arg->ch <= '9') {
         arg->width = arg->ch - '0';
@@ -590,6 +591,7 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
             }
             arg->width = arg->width*10 + (arg->ch - '0');
         }
+        assert(arg->width >= 0);
     }
 
     /* Parse precision. Example: "%.3f" => prec=3 */
@@ -645,6 +647,7 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
                 arg->prec = arg->prec*10 + (arg->ch - '0');
             }
         }
+        assert(arg->prec >= 0);
     }
 
     /* Ignore "h", "l" and "L" format prefix (ex: "%hi" or "%ls") */
@@ -701,24 +704,27 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
     case 's':
     case 'r':
     case 'a':
-        if (PyLong_CheckExact(v) && arg->width == -1 && arg->prec == -1) {
-            /* Fast path */
-            if (_PyLong_FormatWriter(writer, v, 10, arg->flags & F_ALT) == -1)
-                return -1;
-            return 1;
+        if (arg->width < 0 && arg->prec < 0) {
+            if (arg->ch == 's') {
+                if (PyUnicodeWriter_WriteStr((PyUnicodeWriter*)writer, v) < 0) 
{
+                    return -1;
+                }
+                return 1;
+            }
+            else if (arg->ch == 'r') {
+                if (PyUnicodeWriter_WriteRepr((PyUnicodeWriter*)writer, v) < 
0) {
+                    return -1;
+                }
+                return 1;
+            }
         }
 
-        if (PyUnicode_CheckExact(v) && arg->ch == 's') {
-            *p_str = Py_NewRef(v);
-        }
-        else {
-            if (arg->ch == 's')
-                *p_str = PyObject_Str(v);
-            else if (arg->ch == 'r')
-                *p_str = PyObject_Repr(v);
-            else
-                *p_str = PyObject_ASCII(v);
-        }
+        if (arg->ch == 's')
+            *p_str = PyObject_Str(v);
+        else if (arg->ch == 'r')
+            *p_str = PyObject_Repr(v);
+        else
+            *p_str = PyObject_ASCII(v);
         break;
 
     case 'i':
diff --git a/Objects/unicode_writer.c b/Objects/unicode_writer.c
index 0949e45d51cbad..be3cfb2538b780 100644
--- a/Objects/unicode_writer.c
+++ b/Objects/unicode_writer.c
@@ -285,15 +285,16 @@ _PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, 
PyObject *str)
 
 
 int
-PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
+PyUnicodeWriter_WriteStr(PyUnicodeWriter *pub_writer, PyObject *obj)
 {
+    _PyUnicodeWriter *writer = (_PyUnicodeWriter*)pub_writer;
     PyTypeObject *type = Py_TYPE(obj);
     if (type == &PyUnicode_Type) {
-        return _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, obj);
+        return _PyUnicodeWriter_WriteStr(writer, obj);
     }
 
     if (type == &PyLong_Type) {
-        return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0);
+        return _PyLong_FormatWriter(writer, obj, 10, 0);
     }
 
     PyObject *str = PyObject_Str(obj);
@@ -301,21 +302,22 @@ PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, 
PyObject *obj)
         return -1;
     }
 
-    int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
+    int res = _PyUnicodeWriter_WriteStr(writer, str);
     Py_DECREF(str);
     return res;
 }
 
 
 int
-PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
+PyUnicodeWriter_WriteRepr(PyUnicodeWriter *pub_writer, PyObject *obj)
 {
+    _PyUnicodeWriter *writer = (_PyUnicodeWriter*)pub_writer;
     if (obj == NULL) {
-        return _PyUnicodeWriter_WriteASCIIString((_PyUnicodeWriter*)writer, 
"<NULL>", 6);
+        return _PyUnicodeWriter_WriteASCIIString(writer, "<NULL>", 6);
     }
 
     if (Py_TYPE(obj) == &PyLong_Type) {
-        return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0);
+        return _PyLong_FormatWriter(writer, obj, 10, 0);
     }
 
     PyObject *repr = PyObject_Repr(obj);
@@ -323,7 +325,7 @@ PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject 
*obj)
         return -1;
     }
 
-    int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, repr);
+    int res = _PyUnicodeWriter_WriteStr(writer, repr);
     Py_DECREF(repr);
     return res;
 }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to