diff --git a/peps/pep-0749.rst b/peps/pep-0749.rst index dfed42a5d2e..5afd763a2d2 100644 --- a/peps/pep-0749.rst +++ b/peps/pep-0749.rst @@ -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 ========== @@ -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. @@ -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 ============================================== @@ -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 ====================================