Skip to content

Commit 8cbcebf

Browse files
authored
PEP 737: Add type.__format__() method (#3589)
* Add type.__format__() method. * Add more formats to PyUnicode_FromFormat(). * Add PyType_GetModuleName() function.
1 parent d8e1130 commit 8cbcebf

File tree

1 file changed

+137
-104
lines changed

1 file changed

+137
-104
lines changed

peps/pep-0737.rst

Lines changed: 137 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,19 @@ Abstract
1414

1515
Add new convenient APIs to format type names the same way in Python and
1616
in C. No longer format type names differently depending on how types are
17-
implemented. No longer truncate type names in the standard library.
17+
implemented.
1818

1919
Recommend using the type fully qualified name in error messages and in
20-
``__repr__()`` methods in new code.
20+
``__repr__()`` methods in new code. Recommend not truncating type names
21+
in new code.
22+
23+
Add ``N`` and ``#N`` formats to ``type.__format__()`` to format a type
24+
fully qualified name. For example, ``f"{type(obj):N}"`` formats the
25+
fully qualified name of an object *obj*.
26+
27+
Add ``%T``, ``%#T``, ``%N`` and ``%#N`` formats to
28+
``PyUnicode_FromFormat()`` to format the fully qualified, respectively,
29+
of an object type and of a type.
2130

2231
Make C code safer by avoiding borrowed reference which can lead to
2332
crashes. The new C API is compatible with the limited C API.
@@ -172,16 +181,17 @@ Specification
172181
=============
173182

174183
* Add ``type.__fully_qualified_name__`` attribute.
175-
* Add ``%T``, ``%#T``, ``%N``, ``%#N`` formats to
176-
``PyUnicode_FromFormat()``.
184+
* Add ``type.__format__()`` method.
185+
* Add formats to ``PyUnicode_FromFormat()``.
186+
* Add ``PyType_GetModuleName()`` function.
177187
* Add ``PyType_GetFullyQualifiedName()`` function.
178188
* Recommend using the type fully qualified name in error messages and
179189
in ``__repr__()`` methods in new code.
180-
* Recommend not truncating type names.
190+
* Recommend not truncating type names in new code.
181191

182192

183-
Python API
184-
----------
193+
Add type.__fully_qualified_name__ attribute
194+
-------------------------------------------
185195

186196
Add ``type.__fully_qualified_name__`` read-only attribute, the fully
187197
qualified name of a type: similar to
@@ -190,39 +200,48 @@ qualified name of a type: similar to
190200
equal to ``"__main__"``.
191201

192202
The ``type.__repr__()`` is left unchanged, it only omits the module if
193-
the module is equal to ``"builtins"``. It includes the module if the
194-
module is equal to ``"__main__"``. Pseudo-code::
195-
196-
def type_repr(cls):
197-
if isinstance(cls.__module__, str) and cls.__module__ != "builtins":
198-
name = f"{cls.__module__}.{cls.__qualname__}"
199-
else:
200-
name = cls.__qualname__
201-
return f"<class '{name}'>"
202-
203-
204-
Add PyUnicode_FromFormat() formats
205-
----------------------------------
206-
207-
Add formats to ``PyUnicode_FromFormat()``:
208-
209-
* ``%T`` formats the type fully qualified name of an **object**:
210-
similar to ``type(obj).__fully_qualified_name__``.
211-
* ``%#T`` formats the type short name of an **object**:
212-
similar to ``type(obj).__name__``.
213-
* ``%N`` formats the fully qualified name of a **type**:
214-
similar to ``type.__fully_qualified_name__``.
215-
* ``%#N`` formats the short name of an object of a **type**:
216-
similar to ``type.__name__``.
217-
218-
The hash character (``#``) in the format string stands for
219-
`alternative format
220-
<https://docs.python.org/3/library/string.html#format-specification-mini-language>`_.
221-
For example, ``f"{123:x}"`` returns ``'7b'`` and ``f"{123:#x}"`` returns
222-
``'0x7b'`` (``#`` adds ``'0x'`` prefix).
223-
224-
The ``%T`` format is used by ``time.strftime()``, but it's not used by
225-
``printf()``.
203+
the module is equal to ``"builtins"``.
204+
205+
206+
Add type.__format__() method
207+
----------------------------
208+
209+
Add ``type.__format__()`` method with the following formats:
210+
211+
* ``N`` formats the type **fully qualified name**
212+
(``type.__fully_qualified_name__``);
213+
``N`` stands for **N**\ ame.
214+
* ``#N`` (alternative form) formats the type **fully qualified name**
215+
using the **colon** (``:``) separator, instead of the dot separator
216+
(``.``), between the module name and the qualified name.
217+
218+
Examples using f-string::
219+
220+
>>> import datetime
221+
>>> f"{datetime.timedelta:N}" # fully qualified name
222+
'datetime.timedelta'
223+
>>> f"{datetime.timedelta:#N}" # fully qualified name, colon separator
224+
'datetime:timedelta'
225+
226+
The colon (``:``) separator used by the ``#N`` format eliminates
227+
guesswork when you want to import the name, see
228+
``pkgutil.resolve_name()``, ``python -m inspect`` command line
229+
interface, and ``setuptools`` entry points.
230+
231+
232+
Add formats to PyUnicode_FromFormat()
233+
-------------------------------------
234+
235+
Add the following formats to ``PyUnicode_FromFormat()``:
236+
237+
* ``%N`` formats the **fully qualified name** of a **type**
238+
(``type.__fully_qualified_name__``); **N** stands for type **N**\ ame.
239+
* ``%T`` formats the type **fully qualified name** of an **object**
240+
(``type(obj).__fully_qualified_name__``); **T** stands for object
241+
**T**\ ype.
242+
* ``%#N`` and ``%#T``: the alternative form uses the **colon** separator
243+
(``:``), instead of the dot separator (``.``), between the module name
244+
and the qualified name.
226245

227246
For example, the existing code using *tp_name*:
228247

@@ -247,8 +266,45 @@ Advantages of the updated code:
247266
* The ``PyTypeObject.tp_name`` bytes string no longer has to be decoded
248267
from UTF-8 at each ``PyErr_Format()`` call, since
249268
``type.__fully_qualified_name__`` is already a Unicode string.
269+
* The formatted type name no longer depends on the type implementation.
250270
* The type name is no longer truncated.
251271

272+
Note: The ``%T`` format is used by ``time.strftime()``, but not by
273+
``printf()``.
274+
275+
276+
Formats Summary
277+
---------------
278+
279+
.. list-table::
280+
:header-rows: 1
281+
282+
* - C object
283+
- C type
284+
- Python
285+
- Format
286+
* - ``%T``
287+
- ``%N``
288+
- ``:N``
289+
- Type **fully qualified** name.
290+
* - ``%#T``
291+
- ``%#N``
292+
- ``:#N``
293+
- Type **fully qualified** name, **colon** separator.
294+
295+
Add PyType_GetModuleName() function
296+
-----------------------------------
297+
298+
Add the ``PyType_GetModuleName()`` function to get the module name of a
299+
type (``type.__module__``). API:
300+
301+
.. code-block:: c
302+
303+
PyObject* PyType_GetModuleName(PyTypeObject *type)
304+
305+
On success, return a new reference to the string. On error, raise an
306+
exception and return ``NULL``.
307+
252308

253309
Add PyType_GetFullyQualifiedName() function
254310
-------------------------------------------
@@ -279,12 +335,9 @@ in an unambiguous way.
279335
Recommend not truncating type names
280336
-----------------------------------
281337

282-
Type names must not be truncated. For example, the ``%.100s`` format
283-
should be avoided: use the ``%s`` format instead (or ``%T`` and ``%#T``
284-
formats in C).
285-
286-
Code in the standard library is updated to no longer truncate type
287-
names.
338+
Type names should not be truncated in new code. For example, the
339+
``%.100s`` format should be avoided: use the ``%s`` format instead (or
340+
``%T`` format in C).
288341

289342

290343
Implementation
@@ -303,12 +356,9 @@ Adding new APIs has no effect on the backward compatibility. Existing
303356
APIs are left unchanged.
304357

305358
Replacing the type short name with the type fully qualified name is only
306-
recommended in new code. Existing code should be left
307-
unchanged and so remains backward compatible.
308-
309-
In the standard library, type names are no longer truncated. We believe
310-
that no code should be affected in practice, since type names longer
311-
than 100 characters are rare.
359+
recommended in new code. No longer truncating type names is only
360+
recommended in new code. Existing code should be left unchanged and so
361+
remains backward compatible.
312362

313363

314364
Rejected Ideas
@@ -330,38 +380,14 @@ See the `pull request: type(str) returns the fully qualified name
330380
<https://github.com/python/cpython/pull/112129>`_.
331381

332382

333-
Add formats to type.__format__()
334-
--------------------------------
335-
336-
Examples of proposed formats for ``type.__format__()``:
337-
338-
* ``f"{type(obj):z}"`` formats ``type(obj).__name__``.
339-
* ``f"{type(obj):M.T}"`` formats ``type(obj).__fully_qualified_name__``.
340-
* ``f"{type(obj):M:T}"`` formats ``type(obj).__fully_qualified_name__``
341-
using colon (``:``) separator.
342-
* ``f"{type(obj):T}"`` formats ``type(obj).__name__``.
343-
* ``f"{type(obj):#T}"`` formats ``type(obj).__fully_qualified_name__``.
344-
345-
Using short format (such as ``z``, a single letter) requires to refer to
346-
format documentation to understand how a type name is formatted, whereas
347-
``type(obj).__name__`` is explicit.
348-
349-
The dot character (``.``) is already used for the "precision" in format
350-
strings. The colon character (``:``) is already used to separated the
351-
expression from the format specification. For example, ``f"{3.14:g}"``
352-
uses ``g`` format which comes after the colon (``:``). Usually, a format
353-
type is a single letter, such as ``g`` in ``f"{3.14:g}"``, not ``M.T``
354-
or ``M:T``. Reusing dot and colon characters for a different purpose can
355-
be misleading and make the format parser more complicated.
356-
357383
Add !t formatter to get an object type
358384
--------------------------------------
359385

360-
Use ``f"{obj!t:T}"`` to format ``type(obj).__name__``, similar to
361-
``f"{type(obj).__name__}"``.
386+
Use ``f"{obj!t:T}"`` to format ``type(obj).__fully_qualified_name__``,
387+
similar to ``f"{type(obj):T}"``.
362388

363-
When the ``!t`` formatter was proposed in 2018, `Eric Smith was opposed
364-
to this
389+
When the ``!t`` formatter was proposed in 2018, `Eric Smith was stronly
390+
opposed to this
365391
<https://mail.python.org/archives/list/python-dev@python.org/message/BMIW3FEB77OS7OB3YYUUDUBITPWLRG3U/>`_;
366392
Eric is the author of the f-string :pep:`498` "Literal String Interpolation".
367393

@@ -370,23 +396,12 @@ Add formats to str % args
370396
-------------------------
371397

372398
It was proposed to add formats to format a type name in ``str % arg``.
373-
For example, ``%T`` and ``%#T`` formats.
399+
For example, add the ``%T`` format to format a type fully qualified
400+
name.
374401

375402
Nowadays, f-strings are preferred for new code.
376403

377404

378-
Use colon separator in fully qualified name
379-
-------------------------------------------
380-
381-
The colon (``:``) separator eliminates guesswork when you want to import
382-
the name, see ``pkgutil.resolve_name()``. A type fully qualified name
383-
can be formatted as ``f"{type.__module__}:{type.__qualname__}"``, or
384-
``type.__qualname__`` if the type module is ``"builtins"``.
385-
386-
In the standard library, no code formats a type fully qualified name
387-
this way.
388-
389-
390405
Other ways to format type names in C
391406
------------------------------------
392407

@@ -421,8 +436,23 @@ between different modules and make the API more error prone.
421436
About the ``%t`` format, ``printf()`` now uses ``t`` as a length
422437
modifier for ``ptrdiff_t`` argument.
423438

424-
``type.__qualname__`` can be used in Python and ``PyType_GetQualName()``
425-
can be used in C to format a type qualified name.
439+
The following APIs to be used to format a type:
440+
441+
.. list-table::
442+
:header-rows: 1
443+
444+
* - C API
445+
- Python API
446+
- Format
447+
* - ``PyType_GetName()``
448+
- ``type.__name__``
449+
- Type **short** name.
450+
* - ``PyType_GetQualName()``
451+
- ``type.__qualname__``
452+
- Type **qualified** name.
453+
* - ``PyType_GetModuleName()``
454+
- ``type.__module__``
455+
- Type **module** name.
426456

427457

428458
Use %T format with Py_TYPE(): pass a type
@@ -471,13 +501,15 @@ Python does crash.
471501
Other proposed APIs to get a type fully qualified name
472502
------------------------------------------------------
473503

474-
* ``type.__fullyqualname__`` attribute name: attribute without an underscore
504+
* Add ``type.__fullyqualname__`` attribute: name without underscore
475505
between words. Several dunders, including some of the most recently
476-
added ones, include an underscore in the word: ``__class_getitem__``,
477-
``__release_buffer__``, ``__type_params__``, ``__init_subclass__`` and
478-
``__text_signature__``.
479-
* ``type.__fqn__`` attribute name, where FQN stands for Fully Qualified
480-
Name.
506+
added ones, include an underscore in the word:
507+
``__class_getitem__``, ``__release_buffer__``, ``__type_params__``,
508+
``__init_subclass__`` and ``__text_signature__``.
509+
* Add ``type.__fqn__`` attribute: FQN name stands for **F**\ ully
510+
**Q**\ ualified **N**\ ame.
511+
* Add ``type.fully_qualified_name()`` method. Methods added to ``type``
512+
are inherited by all types and so can affect existing code.
481513
* Add a function to the ``inspect`` module. Need to import the
482514
``inspect`` module to use it.
483515

@@ -493,9 +525,10 @@ not treat the ``__main__`` module differently: include it in the name.
493525
Existing code such as ``type.__repr__()``, ``collections.abc`` and
494526
``unittest`` modules format a type name with
495527
``f'{obj.__module__}.{obj.__qualname__}'`` and only omit the module part
496-
if the module is equal to ``builtins``. Only the ``traceback`` and
497-
``pdb`` modules also the module if it's equal to ``"builtins"`` or
498-
``"__main__"``.
528+
if the module is equal to ``builtins``.
529+
530+
Only the ``traceback`` and ``pdb`` modules also omit the module if it's
531+
equal to ``"builtins"`` or ``"__main__"``.
499532

500533
The ``type.__fully_qualified_name__`` attribute omits the ``__main__``
501534
module to produce shorter names for a common case: types defined in a

0 commit comments

Comments
 (0)