Skip to content

Commit

Permalink
PEP 749: Rename SOURCE to STRING, go back on __annotations__ setting (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra authored Sep 26, 2024
1 parent aced24f commit 55cf374
Showing 1 changed file with 41 additions and 17 deletions.
58 changes: 41 additions & 17 deletions peps/pep-0749.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ specification:
that can be run in a "fake globals" environment. Instead, we add a fourth format,
``VALUE_WITH_FAKE_GLOBALS``, to allow third-party implementors of annotate functions to
indicate what formats they support.
* Setting the ``__annotations__`` attribute directly will not affect the ``__annotate__`` attribute.
* Deleting the ``__annotations__`` attribute directly will also clear ``__annotate__``.
* We add functionality to allow evaluating type alias values and type parameter bounds and defaults
(which were added by :pep:`695` and :pep:`696`) using PEP 649-like semantics.
* The ``SOURCE`` format is renamed to ``STRING`` to improve clarity and reduce the risk of
user confusion.

Motivation
==========
Expand Down Expand Up @@ -229,13 +231,13 @@ The module will contain the following functionality:
dictionary. This is intended to be used for evaluating deferred attributes introduced by
:pep:`695` and :pep:`696`; see below for details. *func* may be ``None``
for convenience; if ``None`` is passed, the function also returns ``None``.
* ``annotations_to_source(annotations: dict[str, object]) -> dict[str, str]``: a function that
* ``annotations_to_string(annotations: dict[str, object]) -> dict[str, str]``: a function that
converts each value in an annotations dictionary to a string representation.
This is useful for
implementing the ``SOURCE`` format in cases where the original source is not available,
such as in the functional syntax for :py:class:`typing.TypedDict`.
* ``value_to_source(value: object) -> str``: a function that converts a single value to a
string representation. This is used by ``annotations_to_source``.
* ``value_to_string(value: object) -> str``: a function that converts a single value to a
string representation. This is used by ``annotations_to_string``.
It uses ``repr()`` for most values, but for types it returns the fully qualified name.
It is also useful as a helper for the ``repr()`` of a number of objects in the
:py:mod:`typing` and :py:mod:`collections.abc` modules.
Expand Down Expand Up @@ -629,29 +631,23 @@ Third-party code that implements ``__annotate__`` functions should raise
and the function is not prepared to be run in a "fake globals" environment.
This should be mentioned in the data model documentation for ``__annotate__``.

Effect of setting ``__annotations__``
=====================================
Effect of deleting ``__annotations__``
======================================

:pep:`649` specifies:

Setting ``o.__annotations__`` to a legal value
automatically sets ``o.__annotate__`` to ``None``.

We would prefer to keep ``__annotate__`` unchanged when ``__annotations__``
is written to. Conceptually, ``__annotate__`` provides the ground truth
and ``__annotations__`` is merely a cache, and we shouldn't throw away the
ground truth if the cache is modified.

The motivation for :pep:`649`'s behavior is to keep the two attributes in sync.
However, this is impossible in general; if the ``__annotations__`` dictionary
is modified in place, this will not be reflected in the ``__annotate__`` attribute.
The overall mental model for this area will be simpler if setting ``__annotations__``
has no effect on ``__annotate__``.
However, the PEP does not say what happens if the ``__annotations__`` attribute
is deleted (using ``del``). It seems most consistent that deleting the attribute
will also delete ``__annotate__``.

Specification
-------------

The value of ``__annotate__`` is not changed when ``__annotations__`` is set.
Deleting the ``__annotations__`` attribute on functions, modules, and classes
results in setting ``__annotate__`` to None.

Deferred evaluation of PEP 695 and 696 objects
==============================================
Expand Down Expand Up @@ -730,6 +726,34 @@ can use the ``ForwardRef.evaluate`` method.
If use cases come up in the future, we could add additional functionality,
such as a new method that re-evaluates the annotation from scratch.

Renaming ``SOURCE`` to ``STRING``
=================================

The ``SOURCE`` format is meant for tools that need to show a human-readable
format that is close to the original source code. However, we cannot retrieve
the original source in ``__annotate__`` functions, and in some cases, we have
``__annotate__`` functions in Python code that do not have access to the original
code. For example, this applies to :py:func:`dataclasses.make_dataclass`
and the call-based syntax for :py:class:`typing.TypedDict`.

This makes the name ``SOURCE`` a bit of a misnomer. The goal of the format
should indeed be to recreate the source, but the name is likely to mislead
users in practice. A more neutral name would emphasize that the format returns
an annotation dictionary with only strings. We suggest ``STRING``.

Specification
-------------

The ``SOURCE`` format is renamed to ``STRING``. To reiterate the changes in this
PEP, the four supported formats are now:

- ``VALUE``: the default format, which evaluates the annotations and returns the
resulting values.
- ``VALUE_WITH_FAKE_GLOBALS``: for internal use; should be handled like ``VALUE``
by annotate functions that support execution with fake globals.
- ``FORWARDREF``: replaces undefined names with ``ForwardRef`` objects.
- ``STRING``: returns strings, attempts to recreate code close to the original source.

Miscellaneous implementation details
====================================

Expand Down

0 comments on commit 55cf374

Please sign in to comment.