PEP 737: Remove Python changes (#3704)
This commit is contained in:
parent
ec2ca2ec6c
commit
b69e2daa81
|
@ -1,5 +1,5 @@
|
||||||
PEP: 737
|
PEP: 737
|
||||||
Title: Unify type name formatting
|
Title: C API to format a type fully qualified name
|
||||||
Author: Victor Stinner <vstinner@python.org>
|
Author: Victor Stinner <vstinner@python.org>
|
||||||
Discussions-To: https://discuss.python.org/t/pep-737-unify-type-name-formatting/39872
|
Discussions-To: https://discuss.python.org/t/pep-737-unify-type-name-formatting/39872
|
||||||
Status: Draft
|
Status: Draft
|
||||||
|
@ -12,17 +12,12 @@ Post-History: `29-Nov-2023 <https://discuss.python.org/t/pep-737-unify-type-name
|
||||||
Abstract
|
Abstract
|
||||||
========
|
========
|
||||||
|
|
||||||
Add new convenient APIs to format type names the same way in Python and
|
Add new convenient C APIs to format a type fully qualified name. No longer
|
||||||
in C. No longer format type names differently depending on how types are
|
format type names differently depending on how types are implemented.
|
||||||
implemented.
|
|
||||||
|
|
||||||
Recommend using the type fully qualified name in error messages and in
|
Recommend using the type fully qualified name in error messages and in
|
||||||
``__repr__()`` methods in new code. Recommend not truncating type names
|
``__repr__()`` methods in new C code. Recommend not truncating type
|
||||||
in new code.
|
names in new C code.
|
||||||
|
|
||||||
Add ``N`` and ``#N`` formats to ``type.__format__()`` to format a type
|
|
||||||
fully qualified name. For example, ``f"{type(obj):N}"`` formats the
|
|
||||||
fully qualified name of an object *obj*.
|
|
||||||
|
|
||||||
Add ``%T``, ``%#T``, ``%N`` and ``%#N`` formats to
|
Add ``%T``, ``%#T``, ``%N`` and ``%#N`` formats to
|
||||||
``PyUnicode_FromFormat()`` to format the fully qualified, respectively,
|
``PyUnicode_FromFormat()`` to format the fully qualified, respectively,
|
||||||
|
@ -180,16 +175,149 @@ limit of 500 bytes is outdated
|
||||||
Specification
|
Specification
|
||||||
=============
|
=============
|
||||||
|
|
||||||
* Add ``type.__fully_qualified_name__`` attribute.
|
|
||||||
* Add ``type.__format__()`` method.
|
|
||||||
* Add formats to ``PyUnicode_FromFormat()``.
|
|
||||||
* Add ``PyType_GetModuleName()`` function.
|
|
||||||
* Add ``PyType_GetFullyQualifiedName()`` function.
|
* Add ``PyType_GetFullyQualifiedName()`` function.
|
||||||
|
* Add ``PyType_GetModuleName()`` function.
|
||||||
|
* Add formats to ``PyUnicode_FromFormat()``.
|
||||||
* Recommend using the type fully qualified name in error messages and
|
* Recommend using the type fully qualified name in error messages and
|
||||||
in ``__repr__()`` methods in new code.
|
in ``__repr__()`` methods in new C code.
|
||||||
* Recommend not truncating type names in new code.
|
* Recommend not truncating type names in new C code.
|
||||||
|
|
||||||
|
|
||||||
|
Add PyType_GetFullyQualifiedName() function
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Add the ``PyType_GetFullyQualifiedName()`` function to get 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__"``.
|
||||||
|
|
||||||
|
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``.
|
||||||
|
|
||||||
|
|
||||||
|
Add PyType_GetModuleName() function
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Add the ``PyType_GetModuleName()`` function to get the module name of a
|
||||||
|
type (``type.__module__`` string). 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 formats to PyUnicode_FromFormat()
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
Add the following formats to ``PyUnicode_FromFormat()``:
|
||||||
|
|
||||||
|
* ``%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.
|
||||||
|
|
||||||
|
For example, the existing code using *tp_name*:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"__format__ must return a str, not %.200s",
|
||||||
|
Py_TYPE(result)->tp_name);
|
||||||
|
|
||||||
|
can be replaced with the ``%T`` format:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"__format__ must return a str, not %T", result);
|
||||||
|
|
||||||
|
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 formatted type name no longer depends on the type implementation.
|
||||||
|
* The type name is no longer truncated.
|
||||||
|
|
||||||
|
Note: The ``%T`` format is used by ``time.strftime()``, but not by
|
||||||
|
``printf()``.
|
||||||
|
|
||||||
|
|
||||||
|
Formats Summary
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
* - C object
|
||||||
|
- C type
|
||||||
|
- Format
|
||||||
|
* - ``%T``
|
||||||
|
- ``%N``
|
||||||
|
- Type **fully qualified** name.
|
||||||
|
* - ``%#T``
|
||||||
|
- ``%#N``
|
||||||
|
- Type **fully qualified** name, **colon** separator.
|
||||||
|
|
||||||
|
Recommend using the type fully qualified name
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
The type fully qualified name is recommended in error messages and in
|
||||||
|
``__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
|
||||||
|
generic names. Using the fully qualified name helps identifying the type
|
||||||
|
in an unambiguous way.
|
||||||
|
|
||||||
|
|
||||||
|
Recommend not truncating type names
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
==============
|
||||||
|
|
||||||
|
* Pull request: `Add type.__fully_qualified_name__ attribute <https://github.com/python/cpython/pull/112133>`_.
|
||||||
|
* Pull request: `Add %T format to PyUnicode_FromFormat() <https://github.com/python/cpython/pull/111703>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Backwards Compatibility
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Changes proposed in this PEP are backward compatible.
|
||||||
|
|
||||||
|
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 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__ attribute
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
|
@ -202,6 +330,22 @@ equal to ``"__main__"``.
|
||||||
The ``type.__repr__()`` is left unchanged, it only omits the module if
|
The ``type.__repr__()`` is left unchanged, it only omits the module if
|
||||||
the module is equal to ``"builtins"``.
|
the module is equal to ``"builtins"``.
|
||||||
|
|
||||||
|
This change was `rejected by the Steering Council
|
||||||
|
<https://discuss.python.org/t/pep-737-unify-type-name-formatting/39872/51>`__:
|
||||||
|
|
||||||
|
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
|
||||||
----------------------------
|
----------------------------
|
||||||
|
@ -228,141 +372,9 @@ guesswork when you want to import the name, see
|
||||||
``pkgutil.resolve_name()``, ``python -m inspect`` command line
|
``pkgutil.resolve_name()``, ``python -m inspect`` command line
|
||||||
interface, and ``setuptools`` entry points.
|
interface, and ``setuptools`` entry points.
|
||||||
|
|
||||||
|
This change was `rejected by the Steering Council
|
||||||
|
<https://discuss.python.org/t/pep-737-unify-type-name-formatting/39872/52>`__.
|
||||||
|
|
||||||
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`` and ``%#T``: the alternative form uses the **colon** separator
|
|
||||||
(``:``), instead of the dot separator (``.``), between the module name
|
|
||||||
and the qualified name.
|
|
||||||
|
|
||||||
For example, the existing code using *tp_name*:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"__format__ must return a str, not %.200s",
|
|
||||||
Py_TYPE(result)->tp_name);
|
|
||||||
|
|
||||||
can be replaced with the ``%T`` format:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"__format__ must return a str, not %T", result);
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Note: The ``%T`` format is used by ``time.strftime()``, but not by
|
|
||||||
``printf()``.
|
|
||||||
|
|
||||||
|
|
||||||
Formats Summary
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. list-table::
|
|
||||||
:header-rows: 1
|
|
||||||
|
|
||||||
* - 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.
|
|
||||||
|
|
||||||
In non-trivial applications, it is likely to have two types with the
|
|
||||||
same short name defined in two different modules, especially with
|
|
||||||
generic names. Using the fully qualified name helps identifying the type
|
|
||||||
in an unambiguous way.
|
|
||||||
|
|
||||||
|
|
||||||
Recommend not truncating type names
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
Type names should not be truncated in new code. For example, the
|
|
||||||
``%.100s`` format should be avoided: use the ``%s`` format instead (or
|
|
||||||
``%T`` format in C).
|
|
||||||
|
|
||||||
|
|
||||||
Implementation
|
|
||||||
==============
|
|
||||||
|
|
||||||
* Pull request: `Add type.__fully_qualified_name__ attribute <https://github.com/python/cpython/pull/112133>`_.
|
|
||||||
* Pull request: `Add %T format to PyUnicode_FromFormat() <https://github.com/python/cpython/pull/111703>`_.
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
Rejected Ideas
|
|
||||||
==============
|
|
||||||
|
|
||||||
Change str(type)
|
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__``,
|
Use ``f"{obj!t:T}"`` to format ``type(obj).__fully_qualified_name__``,
|
||||||
similar to ``f"{type(obj):T}"``.
|
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
|
opposed to this
|
||||||
<https://mail.python.org/archives/list/python-dev@python.org/message/BMIW3FEB77OS7OB3YYUUDUBITPWLRG3U/>`_;
|
<https://mail.python.org/archives/list/python-dev@python.org/message/BMIW3FEB77OS7OB3YYUUDUBITPWLRG3U/>`_;
|
||||||
Eric is the author of the f-string :pep:`498` "Literal String Interpolation".
|
Eric is the author of the f-string :pep:`498` "Literal String Interpolation".
|
||||||
|
|
Loading…
Reference in New Issue