Skip to content

Commit

Permalink
pythongh-117642: Fix PEP 737 implementation (pythonGH-117643)
Browse files Browse the repository at this point in the history
* Fix implementation of %#T and %#N (they were implemented as %T# and
  %N#).
* Restore tests removed in pythongh-116417.
  • Loading branch information
serhiy-storchaka authored and diegorusso committed Apr 17, 2024
1 parent e0afca7 commit 7bfeb8b
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 8 deletions.
6 changes: 3 additions & 3 deletions Doc/c-api/unicode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
34 changes: 34 additions & 0 deletions Lib/test/test_capi/test_unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,40 @@ def check_format(expected, format, *args):
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')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix :pep:`737` implementation for ``%#T`` and ``%#N``.
7 changes: 3 additions & 4 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 7bfeb8b

Please sign in to comment.