PEP 749: Updates from discussion (#3823)
* Reject "make it a no-op forever" * annotationlib
This commit is contained in:
parent
8a3d3f0f4a
commit
736c72935b
|
@ -20,7 +20,7 @@ specification:
|
|||
* ``from __future__ import annotations`` (:pep:`563`) will continue to exist with
|
||||
its current behavior at least until Python 3.13 reaches its end-of-life. Subsequently,
|
||||
it will be deprecated and eventually removed.
|
||||
* A new standard library module, ``annotations``, is added to provide tooling for
|
||||
* A new standard library module, ``annotationlib``, is added to provide tooling for
|
||||
annotations. It will include the ``get_annotations()`` function, an enum for annotation
|
||||
formats, a ``ForwardRef`` class, and a helper function for calling ``__annotate__`` functions.
|
||||
* Annotations in the REPL are lazily evaluated, just like other module-level annotations.
|
||||
|
@ -118,8 +118,16 @@ indefinitely. However, this would permanently bifurcate the behavior of the Pyth
|
|||
language. This is undesirable; the language should have only a single set of semantics,
|
||||
not two permanently different modes.
|
||||
|
||||
New ``annotations`` module
|
||||
==========================
|
||||
*Make the future import a no-op in the future*: Instead of eventually making
|
||||
``from __future__ import annotations`` a ``SyntaxError``, we could make it do nothing
|
||||
instead at some point after Python 3.13 reaches its end-of-life. This still has some
|
||||
of the same issues outlined above around making it a no-op now, although the ecosystem
|
||||
would have had much longer to adapt. It is better to have users explicitly remove
|
||||
the future import from their code in the future once they have confirmed they do not
|
||||
rely on stringized annotations.
|
||||
|
||||
New ``annotationlib`` module
|
||||
============================
|
||||
|
||||
:pep:`649` proposes to add tooling related to annotations to the :py:mod:`inspect`
|
||||
module. However, that module is rather large, has direct or indirect dependencies
|
||||
|
@ -148,14 +156,14 @@ and `pyanalyze <https://github.com/quora/pyanalyze/blob/9e401724f9d035cf138b7261
|
|||
use the ``__forward_arg__`` attribute.
|
||||
|
||||
We replace the existing but poorly specified :py:class:`!typing.ForwardRef` with a new class,
|
||||
``annotations.ForwardRef``. It is designed to be mostly compatible with existing uses
|
||||
``annotationlib.ForwardRef``. It is designed to be mostly compatible with existing uses
|
||||
of the :py:class:`!typing.ForwardRef` class, but without the behaviors specific to the
|
||||
:py:mod:`!typing` module. For compatibility with existing users, we keep the private
|
||||
``_evaluate`` method, but mark it as deprecated. It delegates to a new public function in
|
||||
the :py:mod:`!typing` module, ``typing.evaluate_forward_ref``, that is designed to
|
||||
evaluate forward references in a way that is specific to type hints.
|
||||
|
||||
We add a function ``annotations.call_annotate_function`` as a helper for calling
|
||||
We add a function ``annotationlib.call_annotate_function`` as a helper for calling
|
||||
``__annotate__`` functions. This is a useful building block when implementing functionality
|
||||
that needs to partially evaluate annotations while a class is being constructed.
|
||||
For example, the implementation of :py:class:`typing.NamedTuple` needs to retrieve
|
||||
|
@ -165,7 +173,7 @@ can be constructed, because the annotations determine what fields exist on the n
|
|||
Specification
|
||||
-------------
|
||||
|
||||
A new module, ``annotations``, is added to the standard library. Its aim is to
|
||||
A new module, ``annotationlib``, is added to the standard library. Its aim is to
|
||||
provide tooling for introspecting and wrapping annotations.
|
||||
|
||||
The exact contents of the module are not yet specified. We will add support for
|
||||
|
@ -217,7 +225,7 @@ types and evaluates additional forward references within these types.
|
|||
|
||||
Contrary to :pep:`649`, the annotation formats (``VALUE``, ``FORWARDREF``, and ``SOURCE``)
|
||||
will not be added as global members of the :py:mod:`inspect` module. The only recommended
|
||||
way to refer to these constants will be as ``annotations.Format.VALUE``.
|
||||
way to refer to these constants will be as ``annotationlib.Format.VALUE``.
|
||||
|
||||
Open issues
|
||||
-----------
|
||||
|
@ -225,7 +233,9 @@ Open issues
|
|||
What should this module be called? Some ideas:
|
||||
|
||||
- ``annotations``: The most obvious name, but it may cause confusion with the existing
|
||||
``from __future__ import annotations``. There is a PyPI package :pypi:`annotations`,
|
||||
``from __future__ import annotations``, because users may have both ``import annotations``
|
||||
and ``from __future__ import annotations`` in the same module. The use of a common word
|
||||
as the name will make the module harder to search for. There is a PyPI package :pypi:`annotations`,
|
||||
but it had only a single release in 2015 and looks abandoned.
|
||||
- ``annotools``: Analogous to :py:mod:`itertools` and :py:mod:`functools`, but "anno" is a less
|
||||
obvious abbreviation than "iter" or "func". As of this writing, there
|
||||
|
@ -236,6 +246,8 @@ What should this module be called? Some ideas:
|
|||
no other public standard library module has an underscore in its name.
|
||||
- ``annotationslib``: Analogous to :py:mod:`tomllib`, :py:mod:`pathlib`, and :py:mod:`importlib`.
|
||||
There is no PyPI package with this name.
|
||||
- ``annotationlib``: Similar to the above, but one character shorter and subjectively reads
|
||||
better. Also not taken on PyPI.
|
||||
|
||||
Rejected alternatives
|
||||
---------------------
|
||||
|
@ -342,7 +354,7 @@ object.
|
|||
|
||||
Classes and functions defined within the REPL will also work like any other classes,
|
||||
so evaluation of their annotations will be deferred. It is possible to access the
|
||||
``__annotations__`` and ``__annotate__`` attributes or use the ``annotations`` module
|
||||
``__annotations__`` and ``__annotate__`` attributes or use the ``annotationlib`` module
|
||||
to introspect the annotations.
|
||||
|
||||
Wrappers that provide ``__annotations__``
|
||||
|
@ -402,7 +414,7 @@ that custom ``__annotate__`` functions may not work well with the
|
|||
signal that it does not support the requested format. However,
|
||||
manually implemented ``__annotate__`` functions are likely to support
|
||||
all three annotation formats; often, they will consist of a call to
|
||||
``annotations.call_annotate_function`` plus some transformation of the
|
||||
``annotationlib.call_annotate_function`` plus some transformation of the
|
||||
result.
|
||||
|
||||
In addition, the proposed mechanism couples the implementation with
|
||||
|
@ -484,9 +496,9 @@ these callables return a single value, not a dictionary of annotations.
|
|||
These attributes are read-only.
|
||||
|
||||
Usually, users would use these attributes in combinations with
|
||||
``annotations.call_evaluate_function``. For example, to get a ``TypeVar``'s bound
|
||||
``annotationlib.call_evaluate_function``. For example, to get a ``TypeVar``'s bound
|
||||
in SOURCE format, one could write
|
||||
``annotations.call_evaluate_function(T.evaluate_bound, annotations.Format.SOURCE)``.
|
||||
``annotationlib.call_evaluate_function(T.evaluate_bound, annotations.Format.SOURCE)``.
|
||||
|
||||
Miscellaneous implementation details
|
||||
====================================
|
||||
|
@ -564,7 +576,7 @@ that perform introspection, and it is important that we make it as easy as possi
|
|||
libraries to support the new semantics in a straightforward, user-friendly way.
|
||||
|
||||
We will update those parts of the standard library that are affected by this problem,
|
||||
and we propose to add commonly useful functionality to the new ``annotations`` module,
|
||||
and we propose to add commonly useful functionality to the new ``annotationlib`` module,
|
||||
so third-party tools can use the same set of tools.
|
||||
|
||||
|
||||
|
@ -583,7 +595,7 @@ quotes around annotations that require forward references, a major source of con
|
|||
for users.
|
||||
|
||||
For advanced users who need to introspect annotations, the story becomes more complex.
|
||||
The documentation of the new ``annotations`` module will serve as a reference for users
|
||||
The documentation of the new ``annotationlib`` module will serve as a reference for users
|
||||
who need to interact programmatically with annotations.
|
||||
|
||||
|
||||
|
@ -646,7 +658,7 @@ Accessing ``.type`` might throw an error:
|
|||
^^^^^^^^^
|
||||
NameError: name 'undefined' is not defined
|
||||
|
||||
But users could use ``annotations.call_evaluate_function`` to get the type in other formats:
|
||||
But users could use ``annotationlib.call_evaluate_function`` to get the type in other formats:
|
||||
|
||||
.. code:: pycon
|
||||
|
||||
|
|
Loading…
Reference in New Issue