mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
1a6594f661
commit
24a2bd0481
|
@ -523,7 +523,7 @@ APIs:
|
||||||
- Get the fully qualified name of an object type;
|
- Get the fully qualified name of an object type;
|
||||||
call :c:func:`PyType_GetFullyQualifiedName`.
|
call :c:func:`PyType_GetFullyQualifiedName`.
|
||||||
|
|
||||||
* - ``T#``
|
* - ``#T``
|
||||||
- :c:expr:`PyObject*`
|
- :c:expr:`PyObject*`
|
||||||
- Similar to ``T`` format, but use a colon (``:``) as separator between
|
- Similar to ``T`` format, but use a colon (``:``) as separator between
|
||||||
the module name and the qualified name.
|
the module name and the qualified name.
|
||||||
|
@ -533,7 +533,7 @@ APIs:
|
||||||
- Get the fully qualified name of a type;
|
- Get the fully qualified name of a type;
|
||||||
call :c:func:`PyType_GetFullyQualifiedName`.
|
call :c:func:`PyType_GetFullyQualifiedName`.
|
||||||
|
|
||||||
* - ``N#``
|
* - ``#N``
|
||||||
- :c:expr:`PyTypeObject*`
|
- :c:expr:`PyTypeObject*`
|
||||||
- Similar to ``N`` format, but use a colon (``:``) as separator between
|
- Similar to ``N`` format, but use a colon (``:``) as separator between
|
||||||
the module name and the qualified name.
|
the module name and the qualified name.
|
||||||
|
@ -574,7 +574,7 @@ APIs:
|
||||||
copied as-is to the result string, and any extra arguments discarded.
|
copied as-is to the result string, and any extra arguments discarded.
|
||||||
|
|
||||||
.. versionchanged:: 3.13
|
.. 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)
|
.. c:function:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs)
|
||||||
|
|
|
@ -1775,7 +1775,7 @@ New Features
|
||||||
Equivalent to getting the ``type.__module__`` attribute.
|
Equivalent to getting the ``type.__module__`` attribute.
|
||||||
(Contributed by Eric Snow and Victor Stinner in :gh:`111696`.)
|
(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
|
: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
|
type and of a type: call :c:func:`PyType_GetModuleName`. See :pep:`737` for
|
||||||
more information.
|
more information.
|
||||||
|
|
|
@ -650,6 +650,40 @@ class CAPITest(unittest.TestCase):
|
||||||
check_format('\U0001f4bb+' if sizeof(c_wchar) > 2 else '\U0001f4bb',
|
check_format('\U0001f4bb+' if sizeof(c_wchar) > 2 else '\U0001f4bb',
|
||||||
b'%.2lV', None, c_wchar_p('\U0001f4bb+\U0001f40d'))
|
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
|
# test variable width and precision
|
||||||
check_format(' abc', b'%*s', c_int(5), b'abc')
|
check_format(' abc', b'%*s', c_int(5), b'abc')
|
||||||
check_format('ab', b'%.*s', c_int(2), b'abc')
|
check_format('ab', b'%.*s', c_int(2), b'abc')
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix :pep:`737` implementation for ``%#T`` and ``%#N``.
|
|
@ -2468,6 +2468,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
|
||||||
switch (*f++) {
|
switch (*f++) {
|
||||||
case '-': flags |= F_LJUST; continue;
|
case '-': flags |= F_LJUST; continue;
|
||||||
case '0': flags |= F_ZERO; continue;
|
case '0': flags |= F_ZERO; continue;
|
||||||
|
case '#': flags |= F_ALT; continue;
|
||||||
}
|
}
|
||||||
f--;
|
f--;
|
||||||
break;
|
break;
|
||||||
|
@ -2797,9 +2798,8 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
|
||||||
PyTypeObject *type = (PyTypeObject *)Py_NewRef(Py_TYPE(obj));
|
PyTypeObject *type = (PyTypeObject *)Py_NewRef(Py_TYPE(obj));
|
||||||
|
|
||||||
PyObject *type_name;
|
PyObject *type_name;
|
||||||
if (f[1] == '#') {
|
if (flags & F_ALT) {
|
||||||
type_name = _PyType_GetFullyQualifiedName(type, ':');
|
type_name = _PyType_GetFullyQualifiedName(type, ':');
|
||||||
f++;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
type_name = PyType_GetFullyQualifiedName(type);
|
type_name = PyType_GetFullyQualifiedName(type);
|
||||||
|
@ -2830,9 +2830,8 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
|
||||||
PyTypeObject *type = (PyTypeObject*)type_raw;
|
PyTypeObject *type = (PyTypeObject*)type_raw;
|
||||||
|
|
||||||
PyObject *type_name;
|
PyObject *type_name;
|
||||||
if (f[1] == '#') {
|
if (flags & F_ALT) {
|
||||||
type_name = _PyType_GetFullyQualifiedName(type, ':');
|
type_name = _PyType_GetFullyQualifiedName(type, ':');
|
||||||
f++;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
type_name = PyType_GetFullyQualifiedName(type);
|
type_name = PyType_GetFullyQualifiedName(type);
|
||||||
|
|
Loading…
Reference in New Issue