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
|
* ``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,
|
its current behavior at least until Python 3.13 reaches its end-of-life. Subsequently,
|
||||||
it will be deprecated and eventually removed.
|
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
|
annotations. It will include the ``get_annotations()`` function, an enum for annotation
|
||||||
formats, a ``ForwardRef`` class, and a helper function for calling ``__annotate__`` functions.
|
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.
|
* 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,
|
language. This is undesirable; the language should have only a single set of semantics,
|
||||||
not two permanently different modes.
|
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`
|
: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
|
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.
|
use the ``__forward_arg__`` attribute.
|
||||||
|
|
||||||
We replace the existing but poorly specified :py:class:`!typing.ForwardRef` with a new class,
|
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
|
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
|
: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
|
``_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
|
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.
|
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
|
``__annotate__`` functions. This is a useful building block when implementing functionality
|
||||||
that needs to partially evaluate annotations while a class is being constructed.
|
that needs to partially evaluate annotations while a class is being constructed.
|
||||||
For example, the implementation of :py:class:`typing.NamedTuple` needs to retrieve
|
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
|
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.
|
provide tooling for introspecting and wrapping annotations.
|
||||||
|
|
||||||
The exact contents of the module are not yet specified. We will add support for
|
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``)
|
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
|
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
|
Open issues
|
||||||
-----------
|
-----------
|
||||||
|
@ -225,7 +233,9 @@ Open issues
|
||||||
What should this module be called? Some ideas:
|
What should this module be called? Some ideas:
|
||||||
|
|
||||||
- ``annotations``: The most obvious name, but it may cause confusion with the existing
|
- ``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.
|
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
|
- ``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
|
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.
|
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`.
|
- ``annotationslib``: Analogous to :py:mod:`tomllib`, :py:mod:`pathlib`, and :py:mod:`importlib`.
|
||||||
There is no PyPI package with this name.
|
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
|
Rejected alternatives
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -342,7 +354,7 @@ object.
|
||||||
|
|
||||||
Classes and functions defined within the REPL will also work like any other classes,
|
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
|
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.
|
to introspect the annotations.
|
||||||
|
|
||||||
Wrappers that provide ``__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,
|
signal that it does not support the requested format. However,
|
||||||
manually implemented ``__annotate__`` functions are likely to support
|
manually implemented ``__annotate__`` functions are likely to support
|
||||||
all three annotation formats; often, they will consist of a call to
|
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.
|
result.
|
||||||
|
|
||||||
In addition, the proposed mechanism couples the implementation with
|
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.
|
These attributes are read-only.
|
||||||
|
|
||||||
Usually, users would use these attributes in combinations with
|
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
|
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
|
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.
|
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,
|
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.
|
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 users.
|
||||||
|
|
||||||
For advanced users who need to introspect annotations, the story becomes more complex.
|
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.
|
who need to interact programmatically with annotations.
|
||||||
|
|
||||||
|
|
||||||
|
@ -646,7 +658,7 @@ Accessing ``.type`` might throw an error:
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
NameError: name 'undefined' is not defined
|
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
|
.. code:: pycon
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue