Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-119180: Add discussion of annotations to the 3.14 What's New #124393

Merged
merged 5 commits into from
Sep 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 88 additions & 1 deletion Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,91 @@ Summary -- Release highlights
New Features
============

.. _whatsnew-314-pep649:

PEP 649: Deferred Evaluation of Annotations
-------------------------------------------

The :term:`annotations <annotation>` on functions, classes, and modules are no
longer evaluated eagerly. Instead, annotations are stored in special-purpose
:term:`annotate functions <annotate function>` and evaluated only when
necessary. This is specified in :pep:`649` and :pep:`749`.

This change is designed to make annotations in Python more performant and more
usable in most circumstances. The runtime cost for defining annotations is
minimized, but it remains possible to introspect annotations at runtime.
It is usually no longer necessary to enclose annotations in strings if they
contain forward references.

The new :mod:`annotationlib` module provides tools for inspecting deferred
annotations. Annotations may be evaluated in the :attr:`~annotationlib.Format.VALUE`
format (which evaluates annotations to runtime values, similar to the behavior in
earlier Python versions), the :attr:`~annotationlib.Format.FORWARDREF` format
(which replaces undefined names with special markers), and the
:attr:`~annotationlib.Format.SOURCE` format (which returns annotations as strings).
Comment on lines +90 to +94
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These will render as VALUE, FORWARDREF, SOURCE. Is that what we want, or would Format.VALUE, Format.FORWARDREF and Format.SOURCE be better?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did intend these to render as VALUE etc. Do you think adding Format is better?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd weakly prefer Format.VALUE, but it might make the markup quite verbose, and I don't have a strong opinion :-)


This example shows how these formats behave:

.. doctest::

>>> from annotationlib import get_annotations, Format
>>> def func(arg: Undefined):
... pass
>>> get_annotations(func, format=Format.VALUE)
Traceback (most recent call last):
...
NameError: name 'Undefined' is not defined
>>> get_annotations(func, format=Format.FORWARDREF)
{'arg': ForwardRef('Undefined')}
>>> get_annotations(func, format=Format.SOURCE)
{'arg': 'Undefined'}

Implications for annotated code
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you define annotations in your code (for example, for use with a static type
checker), then this change probably does not affect you: you can keep
writing annotations the same way you did with previous versions of Python.

You will likely be able to remove quoted strings in annotations, which are frequently
used for forward references. Similarly, if you use ``from __future__ import annotations``
to avoid having to write strings in annotations, you may well be able to
remove that import. However, if you rely on third-party libraries that read annotations,
those libraries may need changes to support unquoted annotations before they
work as expected.

Implications for readers of ``__annotations__``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If your code reads the ``__annotations__`` attribute on objects, you may want
to make changes in order to support code that relies on deferred evaluation of
annotations. For example, you may want to use :func:`annotationlib.get_annotations`
with the :attr:`~annotationlib.Format.FORWARDREF` format, as the :mod:`dataclasses`
module now does.

Related changes
^^^^^^^^^^^^^^^

The changes in Python 3.14 are designed to rework how ``__annotations__``
works at runtime while minimizing breakage to code that contains
annotations in source code and to code that reads ``__annotations__``. However,
if you rely on undocumented details of the annotation behavior or on private
functions in the standard library, there are many ways in which your code may
not work in Python 3.14. To safeguard your code against future changes,
use only the documented functionality of the :mod:`annotationlib` module.

``from __future__ import annotations``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In Python 3.7, :pep:`563` introduced the ``from __future__ import annotations``
directive, which turns all annotations into strings. This directive is now
considered deprecated and it is expected to be removed in a future version of Python.
However, this removal will not happen until after Python 3.13, the last version of
Python without deferred evaluation of annotations, reaches its end of life.
In Python 3.14, the behavior of code using ``from __future__ import annotations``
is unchanged.


Improved Error Messages
-----------------------

Expand Down Expand Up @@ -109,7 +194,9 @@ Other Language Changes
New Modules
===========

* None yet.
* :mod:`annotationlib`: For introspecting :term:`annotations <annotation>`.
See :pep:`749` for more details.
(Contributed by Jelle Zijlstra in :gh:`119180`.)


Improved Modules
Expand Down
Loading