]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117642: Fix PEP 737 implementation (GH-117643)
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 8 Apr 2024 16:27:25 +0000 (19:27 +0300)
committerGitHub <noreply@github.com>
Mon, 8 Apr 2024 16:27:25 +0000 (16:27 +0000)
* Fix implementation of %#T and %#N (they were implemented as %T# and
  %N#).
* Restore tests removed in gh-116417.

Doc/c-api/unicode.rst
Doc/whatsnew/3.13.rst
Lib/test/test_capi/test_unicode.py
Misc/NEWS.d/next/C API/2024-04-08-18-53-33.gh-issue-117642._-tYH_.rst [new file with mode: 0644]
Objects/unicodeobject.c

index 78eec14e3a24d650d2e807833c5fc89cda2c9c98..7320d035bab513e16b36c6f53e231572b80c2615 100644 (file)
@@ -523,7 +523,7 @@ APIs:
         - Get the fully qualified name of an object type;
           call :c:func:`PyType_GetFullyQualifiedName`.
 
-      * - ``T#``
+      * - ``#T``
         - :c:expr:`PyObject*`
         - Similar to ``T`` format, but use a colon (``:``) as separator between
           the module name and the qualified name.
@@ -533,7 +533,7 @@ APIs:
         - Get the fully qualified name of a type;
           call :c:func:`PyType_GetFullyQualifiedName`.
 
-      * - ``N#``
+      * - ``#N``
         - :c:expr:`PyTypeObject*`
         - Similar to ``N`` format, but use a colon (``:``) as separator between
           the module name and the qualified name.
@@ -574,7 +574,7 @@ APIs:
       copied as-is to the result string, and any extra arguments discarded.
 
    .. versionchanged:: 3.13
-      Support for ``%T``, ``%T#``, ``%N`` and ``%N#`` formats added.
+      Support for ``%T``, ``%#T``, ``%N`` and ``%#N`` formats added.
 
 
 .. c:function:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs)
index 0fe2dafbfd6f023bac8675bc5bd7e3048cee1f10..72b3a4c951eda6b2f086e9e169a49e85f5431496 100644 (file)
@@ -1775,7 +1775,7 @@ New Features
   Equivalent to getting the ``type.__module__`` attribute.
   (Contributed by Eric Snow and Victor Stinner in :gh:`111696`.)
 
-* Add support for ``%T``, ``%T#``, ``%N`` and ``%N#`` formats to
+* Add support for ``%T``, ``%#T``, ``%N`` and ``%#N`` formats to
   :c:func:`PyUnicode_FromFormat`: format the fully qualified name of an object
   type and of a type: call :c:func:`PyType_GetModuleName`. See :pep:`737` for
   more information.
index a64c75c415c3fe585242e67c3bed03260ad70064..a69f817c515ba7d41e6861838d2ec9b60b00c823 100644 (file)
@@ -650,6 +650,40 @@ class CAPITest(unittest.TestCase):
         check_format('\U0001f4bb+' if sizeof(c_wchar) > 2 else '\U0001f4bb',
                      b'%.2lV', None, c_wchar_p('\U0001f4bb+\U0001f40d'))
 
+        # test %T
+        check_format('type: str',
+                     b'type: %T', py_object("abc"))
+        check_format(f'type: st',
+                     b'type: %.2T', py_object("abc"))
+        check_format(f'type:        str',
+                     b'type: %10T', py_object("abc"))
+
+        class LocalType:
+            pass
+        obj = LocalType()
+        fullname = f'{__name__}.{LocalType.__qualname__}'
+        check_format(f'type: {fullname}',
+                     b'type: %T', py_object(obj))
+        fullname_alt = f'{__name__}:{LocalType.__qualname__}'
+        check_format(f'type: {fullname_alt}',
+                     b'type: %#T', py_object(obj))
+
+        # test %N
+        check_format('type: str',
+                     b'type: %N', py_object(str))
+        check_format(f'type: st',
+                     b'type: %.2N', py_object(str))
+        check_format(f'type:        str',
+                     b'type: %10N', py_object(str))
+
+        check_format(f'type: {fullname}',
+                     b'type: %N', py_object(type(obj)))
+        check_format(f'type: {fullname_alt}',
+                     b'type: %#N', py_object(type(obj)))
+        with self.assertRaisesRegex(TypeError, "%N argument must be a type"):
+            check_format('type: str',
+                         b'type: %N', py_object("abc"))
+
         # test variable width and precision
         check_format('  abc', b'%*s', c_int(5), b'abc')
         check_format('ab', b'%.*s', c_int(2), b'abc')
diff --git a/Misc/NEWS.d/next/C API/2024-04-08-18-53-33.gh-issue-117642._-tYH_.rst b/Misc/NEWS.d/next/C API/2024-04-08-18-53-33.gh-issue-117642._-tYH_.rst
new file mode 100644 (file)
index 0000000..edef277
--- /dev/null
@@ -0,0 +1 @@
+Fix :pep:`737` implementation for ``%#T`` and ``%#N``.
index 59b350f0a609a656841ddfa7336039ea55c2e418..5f15071d7d54efd6be681af775afd8b5acd28c07 100644 (file)
@@ -2468,6 +2468,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
         switch (*f++) {
         case '-': flags |= F_LJUST; continue;
         case '0': flags |= F_ZERO; continue;
+        case '#': flags |= F_ALT; continue;
         }
         f--;
         break;
@@ -2797,9 +2798,8 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
         PyTypeObject *type = (PyTypeObject *)Py_NewRef(Py_TYPE(obj));
 
         PyObject *type_name;
-        if (f[1] == '#') {
+        if (flags & F_ALT) {
             type_name = _PyType_GetFullyQualifiedName(type, ':');
-            f++;
         }
         else {
             type_name = PyType_GetFullyQualifiedName(type);
@@ -2830,9 +2830,8 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
         PyTypeObject *type = (PyTypeObject*)type_raw;
 
         PyObject *type_name;
-        if (f[1] == '#') {
+        if (flags & F_ALT) {
             type_name = _PyType_GetFullyQualifiedName(type, ':');
-            f++;
         }
         else {
             type_name = PyType_GetFullyQualifiedName(type);