Skip to content

Commit 24a2bd0

Browse files
gh-117642: Fix PEP 737 implementation (GH-117643)
* Fix implementation of %#T and %#N (they were implemented as %T# and %N#). * Restore tests removed in gh-116417.
1 parent 1a6594f commit 24a2bd0

File tree

5 files changed

+42
-8
lines changed

5 files changed

+42
-8
lines changed

Doc/c-api/unicode.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ APIs:
523523
- Get the fully qualified name of an object type;
524524
call :c:func:`PyType_GetFullyQualifiedName`.
525525
526-
* - ``T#``
526+
* - ``#T``
527527
- :c:expr:`PyObject*`
528528
- Similar to ``T`` format, but use a colon (``:``) as separator between
529529
the module name and the qualified name.
@@ -533,7 +533,7 @@ APIs:
533533
- Get the fully qualified name of a type;
534534
call :c:func:`PyType_GetFullyQualifiedName`.
535535
536-
* - ``N#``
536+
* - ``#N``
537537
- :c:expr:`PyTypeObject*`
538538
- Similar to ``N`` format, but use a colon (``:``) as separator between
539539
the module name and the qualified name.
@@ -574,7 +574,7 @@ APIs:
574574
copied as-is to the result string, and any extra arguments discarded.
575575
576576
.. versionchanged:: 3.13
577-
Support for ``%T``, ``%T#``, ``%N`` and ``%N#`` formats added.
577+
Support for ``%T``, ``%#T``, ``%N`` and ``%#N`` formats added.
578578
579579
580580
.. c:function:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs)

Doc/whatsnew/3.13.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1775,7 +1775,7 @@ New Features
17751775
Equivalent to getting the ``type.__module__`` attribute.
17761776
(Contributed by Eric Snow and Victor Stinner in :gh:`111696`.)
17771777

1778-
* Add support for ``%T``, ``%T#``, ``%N`` and ``%N#`` formats to
1778+
* Add support for ``%T``, ``%#T``, ``%N`` and ``%#N`` formats to
17791779
:c:func:`PyUnicode_FromFormat`: format the fully qualified name of an object
17801780
type and of a type: call :c:func:`PyType_GetModuleName`. See :pep:`737` for
17811781
more information.

Lib/test/test_capi/test_unicode.py

+34
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,40 @@ def check_format(expected, format, *args):
650650
check_format('\U0001f4bb+' if sizeof(c_wchar) > 2 else '\U0001f4bb',
651651
b'%.2lV', None, c_wchar_p('\U0001f4bb+\U0001f40d'))
652652

653+
# test %T
654+
check_format('type: str',
655+
b'type: %T', py_object("abc"))
656+
check_format(f'type: st',
657+
b'type: %.2T', py_object("abc"))
658+
check_format(f'type: str',
659+
b'type: %10T', py_object("abc"))
660+
661+
class LocalType:
662+
pass
663+
obj = LocalType()
664+
fullname = f'{__name__}.{LocalType.__qualname__}'
665+
check_format(f'type: {fullname}',
666+
b'type: %T', py_object(obj))
667+
fullname_alt = f'{__name__}:{LocalType.__qualname__}'
668+
check_format(f'type: {fullname_alt}',
669+
b'type: %#T', py_object(obj))
670+
671+
# test %N
672+
check_format('type: str',
673+
b'type: %N', py_object(str))
674+
check_format(f'type: st',
675+
b'type: %.2N', py_object(str))
676+
check_format(f'type: str',
677+
b'type: %10N', py_object(str))
678+
679+
check_format(f'type: {fullname}',
680+
b'type: %N', py_object(type(obj)))
681+
check_format(f'type: {fullname_alt}',
682+
b'type: %#N', py_object(type(obj)))
683+
with self.assertRaisesRegex(TypeError, "%N argument must be a type"):
684+
check_format('type: str',
685+
b'type: %N', py_object("abc"))
686+
653687
# test variable width and precision
654688
check_format(' abc', b'%*s', c_int(5), b'abc')
655689
check_format('ab', b'%.*s', c_int(2), b'abc')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :pep:`737` implementation for ``%#T`` and ``%#N``.

Objects/unicodeobject.c

+3-4
Original file line numberDiff line numberDiff line change
@@ -2468,6 +2468,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
24682468
switch (*f++) {
24692469
case '-': flags |= F_LJUST; continue;
24702470
case '0': flags |= F_ZERO; continue;
2471+
case '#': flags |= F_ALT; continue;
24712472
}
24722473
f--;
24732474
break;
@@ -2797,9 +2798,8 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
27972798
PyTypeObject *type = (PyTypeObject *)Py_NewRef(Py_TYPE(obj));
27982799

27992800
PyObject *type_name;
2800-
if (f[1] == '#') {
2801+
if (flags & F_ALT) {
28012802
type_name = _PyType_GetFullyQualifiedName(type, ':');
2802-
f++;
28032803
}
28042804
else {
28052805
type_name = PyType_GetFullyQualifiedName(type);
@@ -2830,9 +2830,8 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
28302830
PyTypeObject *type = (PyTypeObject*)type_raw;
28312831

28322832
PyObject *type_name;
2833-
if (f[1] == '#') {
2833+
if (flags & F_ALT) {
28342834
type_name = _PyType_GetFullyQualifiedName(type, ':');
2835-
f++;
28362835
}
28372836
else {
28382837
type_name = PyType_GetFullyQualifiedName(type);

0 commit comments

Comments
 (0)