diff --git a/peps/pep-0737.rst b/peps/pep-0737.rst index 59a1a5df430..a74b7d50cd0 100644 --- a/peps/pep-0737.rst +++ b/peps/pep-0737.rst @@ -1,5 +1,5 @@ PEP: 737 -Title: Unify type name formatting +Title: C API to format a type fully qualified name Author: Victor Stinner Discussions-To: https://discuss.python.org/t/pep-737-unify-type-name-formatting/39872 Status: Draft @@ -12,17 +12,12 @@ Post-History: `29-Nov-2023 >> import datetime - >>> f"{datetime.timedelta:N}" # fully qualified name - 'datetime.timedelta' - >>> f"{datetime.timedelta:#N}" # fully qualified name, colon separator - 'datetime:timedelta' +Add the ``PyType_GetModuleName()`` function to get the module name of a +type (``type.__module__`` string). API: -The colon (``:``) separator used by the ``#N`` format eliminates -guesswork when you want to import the name, see -``pkgutil.resolve_name()``, ``python -m inspect`` command line -interface, and ``setuptools`` entry points. +.. code-block:: c + + PyObject* PyType_GetModuleName(PyTypeObject *type) + +On success, return a new reference to the string. On error, raise an +exception and return ``NULL``. Add formats to PyUnicode_FromFormat() @@ -234,11 +221,12 @@ Add formats to PyUnicode_FromFormat() Add the following formats to ``PyUnicode_FromFormat()``: -* ``%N`` formats the **fully qualified name** of a **type** - (``type.__fully_qualified_name__``); **N** stands for type **N**\ ame. -* ``%T`` formats the type **fully qualified name** of an **object** - (``type(obj).__fully_qualified_name__``); **T** stands for object - **T**\ ype. +* ``%N`` formats the **fully qualified name** of a **type**, + similar to ``PyType_GetFullyQualifiedName(type)``; + **N** stands for type **N**\ ame. +* ``%T`` formats the type **fully qualified name** of an **object**, + similar to ``PyType_GetFullyQualifiedName(Py_TYPE(obj))``; + **T** stands for object **T**\ ype. * ``%#N`` and ``%#T``: the alternative form uses the **colon** separator (``:``), instead of the dot separator (``.``), between the module name and the qualified name. @@ -263,9 +251,6 @@ Advantages of the updated code: * Safer C code: avoid ``Py_TYPE()`` which returns a borrowed reference. * The ``PyTypeObject.tp_name`` member is no longer read explicitly: the code becomes compatible with the limited C API. -* The ``PyTypeObject.tp_name`` bytes string no longer has to be decoded - from UTF-8 at each ``PyErr_Format()`` call, since - ``type.__fully_qualified_name__`` is already a Unicode string. * The formatted type name no longer depends on the type implementation. * The type name is no longer truncated. @@ -281,50 +266,19 @@ Formats Summary * - C object - C type - - Python - Format * - ``%T`` - ``%N`` - - ``:N`` - Type **fully qualified** name. * - ``%#T`` - ``%#N`` - - ``:#N`` - Type **fully qualified** name, **colon** separator. -Add PyType_GetModuleName() function ------------------------------------ - -Add the ``PyType_GetModuleName()`` function to get the module name of a -type (``type.__module__``). API: - -.. code-block:: c - - PyObject* PyType_GetModuleName(PyTypeObject *type) - -On success, return a new reference to the string. On error, raise an -exception and return ``NULL``. - - -Add PyType_GetFullyQualifiedName() function -------------------------------------------- - -Add the ``PyType_GetFullyQualifiedName()`` function to get the fully -qualified name of a type (``type.__fully_qualified_name__``). API: - -.. code-block:: c - - PyObject* PyType_GetFullyQualifiedName(PyTypeObject *type) - -On success, return a new reference to the string. On error, raise an -exception and return ``NULL``. - - Recommend using the type fully qualified name --------------------------------------------- The type fully qualified name is recommended in error messages and in -``__repr__()`` methods in new code. +``__repr__()`` methods in new C code. In non-trivial applications, it is likely to have two types with the same short name defined in two different modules, especially with @@ -335,7 +289,7 @@ in an unambiguous way. Recommend not truncating type names ----------------------------------- -Type names should not be truncated in new code. For example, the +Type names should not be truncated in new C code. For example, the ``%.100s`` format should be avoided: use the ``%s`` format instead (or ``%T`` format in C). @@ -352,18 +306,76 @@ Backwards Compatibility Changes proposed in this PEP are backward compatible. -Adding new APIs has no effect on the backward compatibility. Existing -APIs are left unchanged. +Adding new C APIs has no effect on the backward compatibility. Existing +C APIs are left unchanged. No Python API is changed. Replacing the type short name with the type fully qualified name is only -recommended in new code. No longer truncating type names is only -recommended in new code. Existing code should be left unchanged and so -remains backward compatible. +recommended in new C code. No longer truncating type names is only +recommended in new C code. Existing code should be left unchanged and so +remains backward compatible. There is no recommendation for Python code. Rejected Ideas ============== +Add type.__fully_qualified_name__ attribute +------------------------------------------- + +Add ``type.__fully_qualified_name__`` read-only attribute, the fully +qualified name of a type: similar to +``f"{type.__module__}.{type.__qualname__}"``, or ``type.__qualname__`` if +``type.__module__`` is not a string or is equal to ``"builtins"`` or is +equal to ``"__main__"``. + +The ``type.__repr__()`` is left unchanged, it only omits the module if +the module is equal to ``"builtins"``. + +This change was `rejected by the Steering Council +`__: + + We can see the usefulness of the C API changes proposed by the PEP + and would likely accept those changes as is. + + We see less justification for the Python level changes. We + especially question the need for ``__fully_qualified_name__``. + +Thomas Wouters added: + + If there really is a desire for formatting types the exact same way + the C API does it, a utility function would make more sense to me, + personally, than ``type.__format__``, but I think the SC could be + persuaded given some concrete use-cases. + + +Add type.__format__() method +---------------------------- + +Add ``type.__format__()`` method with the following formats: + +* ``N`` formats the type **fully qualified name** + (``type.__fully_qualified_name__``); + ``N`` stands for **N**\ ame. +* ``#N`` (alternative form) formats the type **fully qualified name** + using the **colon** (``:``) separator, instead of the dot separator + (``.``), between the module name and the qualified name. + +Examples using f-string:: + + >>> import datetime + >>> f"{datetime.timedelta:N}" # fully qualified name + 'datetime.timedelta' + >>> f"{datetime.timedelta:#N}" # fully qualified name, colon separator + 'datetime:timedelta' + +The colon (``:``) separator used by the ``#N`` format eliminates +guesswork when you want to import the name, see +``pkgutil.resolve_name()``, ``python -m inspect`` command line +interface, and ``setuptools`` entry points. + +This change was `rejected by the Steering Council +`__. + + Change str(type) ---------------- @@ -386,7 +398,7 @@ Add !t formatter to get an object type Use ``f"{obj!t:T}"`` to format ``type(obj).__fully_qualified_name__``, similar to ``f"{type(obj):T}"``. -When the ``!t`` formatter was proposed in 2018, `Eric Smith was stronly +When the ``!t`` formatter was proposed in 2018, `Eric Smith was strongly opposed to this `_; Eric is the author of the f-string :pep:`498` "Literal String Interpolation".