PEP 737: Remove Python changes (#3704)
This commit is contained in:
parent
ec2ca2ec6c
commit
b69e2daa81
|
@ -1,5 +1,5 @@
|
|||
PEP: 737
|
||||
Title: Unify type name formatting
|
||||
Title: C API to format a type fully qualified name
|
||||
Author: Victor Stinner <vstinner@python.org>
|
||||
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 <https://discuss.python.org/t/pep-737-unify-type-name
|
|||
Abstract
|
||||
========
|
||||
|
||||
Add new convenient APIs to format type names the same way in Python and
|
||||
in C. No longer format type names differently depending on how types are
|
||||
implemented.
|
||||
Add new convenient C APIs to format a type fully qualified name. No longer
|
||||
format type names differently depending on how types are implemented.
|
||||
|
||||
Recommend using the type fully qualified name in error messages and in
|
||||
``__repr__()`` methods in new code. Recommend not truncating type names
|
||||
in new 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*.
|
||||
``__repr__()`` methods in new C code. Recommend not truncating type
|
||||
names in new C code.
|
||||
|
||||
Add ``%T``, ``%#T``, ``%N`` and ``%#N`` formats to
|
||||
``PyUnicode_FromFormat()`` to format the fully qualified, respectively,
|
||||
|
@ -180,16 +175,149 @@ limit of 500 bytes is outdated
|
|||
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_GetModuleName()`` function.
|
||||
* Add formats to ``PyUnicode_FromFormat()``.
|
||||
* Recommend using the type fully qualified name in error messages and
|
||||
in ``__repr__()`` methods in new code.
|
||||
* Recommend not truncating type names in new code.
|
||||
in ``__repr__()`` methods in new C 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
|
||||
-------------------------------------------
|
||||
|
||||
|
@ -202,6 +330,22 @@ 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
|
||||
<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
|
||||
----------------------------
|
||||
|
@ -228,141 +372,9 @@ 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
|
||||
<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)
|
||||
----------------
|
||||
|
@ -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
|
||||
<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".
|
||||
|
|
Loading…
Reference in New Issue