Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

PEP 649: Improve description of semantics and mark as accepted #3138

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

Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d9a17ff
Improve PEP 649's description of its semantics.
larryhastings May 5, 2023
23148f6
Fix lint.
larryhastings May 5, 2023
9ace095
PEP 693: Postpone 3.12.0b1 by two weeks (#3139)
hugovk May 8, 2023
108f275
PEP 695: Lazy evaluation, concrete scoping semantics, other changes (…
JelleZijlstra May 8, 2023
8989c52
Incorporate changes from feedback, mark Accepted.
larryhastings May 8, 2023
af3aa36
Fix PEP 12 header *order compliance*. Wow.
larryhastings May 8, 2023
7af54df
Fix Sphinx complaints.
larryhastings May 8, 2023
0034059
Merge branch 'main' into nail_down_annotation_expression_semantics
JelleZijlstra May 8, 2023
3d34d84
Make enum consistent, flesh out observed semantics.
larryhastings May 9, 2023
06d53a4
Add "Resolution" header, as pointed out by Hugo.
larryhastings May 9, 2023
1a316cc
Switch to other URL for Resolution header.
larryhastings May 9, 2023
08485e9
Apply ``global_enum`` to ``inspect.AnnotationFormat``
AA-Turner May 9, 2023
72b8183
Final? text / semantics cleanup pass.
larryhastings May 10, 2023
ade4a90
"accept" -> "accepts". Bettering my Englishes.
larryhastings May 10, 2023
0503ca1
Add new "post history" reflecting the updates.
larryhastings May 10, 2023
7da747a
Update post history with all conversations, courtesy CAM!
larryhastings May 15, 2023
c9b0773
Fix typo. Thanks, Emily!
larryhastings May 15, 2023
c36b491
Add "Discussions-To" header. Thanks, CAM!
larryhastings May 15, 2023
7896e98
Attempt to satisfy "validate-post-history" hook.
larryhastings May 16, 2023
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
146 changes: 80 additions & 66 deletions 146 pep-0649.rst
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
PEP: 649
Title: Deferred Evaluation Of Annotations Using Descriptors
Author: Larry Hastings <larry@hastings.org>
larryhastings marked this conversation as resolved.
Show resolved Hide resolved
Status: Draft
Discussions-To: https://discuss.python.org/t/pep-649-deferred-evaluation-of-annotations-tentatively-accepted/21331/
Status: Accepted
larryhastings marked this conversation as resolved.
Show resolved Hide resolved
Type: Standards Track
Topic: Typing
Content-Type: text/x-rst
Created: 11-Jan-2021
Post-History: 11-Jan-2021, 11-Apr-2021, 19-Apr-2023

Python-Version: 3.13
Post-History: `11-Jan-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/5QMMCRF4HTRRNJV56CGHVI5GRHVBDGQO/>`__,
`12-Apr-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/QSASX6PZ3LIIFIANHQQFS752BJYFUFPY/>`__,
`18-Apr-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/WUZGTGE43T7XV3EUGT6AN2N52OD3U7AE/>`__,
`09-Aug-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/2MEOWHCVDLPABOBLYUGRXVOOOBYOLLU6/>`__,
`20-Oct-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/SZLWVYV2HPLU6AH7DOUD7DWFUGBJGQAY/>`__,
`20-Oct-2021 <https://discuss.python.org/t/type-annotations-pep-649-and-pep-563/11363>`__,
`17-Nov-2021 <https://mail.python.org/archives/list/python-dev@python.org/thread/VIZEBX5EYMSYIJNDBF6DMUMZOCWHARSO/>`__,
`15-Mar-2022 <https://discuss.python.org/t/finding-edge-cases-for-peps-484-563-and-649-type-annotations/14314>`__,
`23-Nov-2022 <https://discuss.python.org/t/pep-649-deferred-evaluation-of-annotations-tentatively-accepted/21331>`__,
`07-Feb-2023 <https://discuss.python.org/t/two-polls-on-how-to-revise-pep-649/23628>`__,
`11-Apr-2023 <https://discuss.python.org/t/a-massive-pep-649-update-with-some-major-course-corrections/25672>`__,
Resolution: https://discuss.python.org/t/pep-649-deferred-evaluation-of-annotations-tentatively-accepted/21331/43

********
Abstract
Expand Down Expand Up @@ -75,6 +87,7 @@ in a specific format.
Format identifiers are always predefined integer values.
The formats defined by this PEP are:


* ``inspect.VALUE = 1``

The default value.
Expand Down Expand Up @@ -528,6 +541,31 @@ resulting in this PEP.
Implementation
**************

Observed semantics for annotations expressions
==============================================

For any object ``o`` that supports annotations,
provided that all names evaluated in the annotations expressions
are bound before ``o`` is defined and never subsequently rebound,
``o.__annotations__`` will produce an identical annotations dict both
when "stock" semantics are active and when this PEP is active.
In particular, name resolution will be performed identically in
both scenarios.

When this PEP is active, the value of ``o.__annotations__``
won't be calculated until the first time ``o.__annotations__``
itself is evaluated. All evaluation of the annotation expressions
is delayed until this moment, which also means that

* names referenced in the annotations expressions will use their
*current* value at this moment, and
* if evaluating the annotations expressions raises an exception,
that exception will be raised at this moment.

Once ``o.__annotations__`` is successfully calculated for the
first time, this value is cached and will be returned by future
requests for ``o.__annotations__``.

__annotate__ and __annotations__
================================

Expand Down Expand Up @@ -556,9 +594,9 @@ code should prefer to interact with it only via the

The callable stored in ``__annotate__`` must accept a
single required positional argument called ``format``,
which will always be an ``int``. It must either return
a dict (or subclass of dict) or raise
``NotImplementedError()``.
which will always be an ``int`` (or a subclass of ``int``).
It must either return a dict (or subclass of dict) or
raise ``NotImplementedError()``.

Here's a formal definition of ``__annotate__``, as it will
appear in the "Magic methods" section of the Python
Expand All @@ -573,25 +611,25 @@ Language Reference:
annotations values should be provided. Must be one of the
following:

``1`` (exported as ``inspect.VALUE``)
``inspect.VALUE`` (equivalent to the ``int`` constant ``1``)
larryhastings marked this conversation as resolved.
Show resolved Hide resolved

Values are the result of evaluating the annotation expressions.

``2`` (exported as ``inspect.SOURCE``)
``inspect.FORWARDREF`` (equivalent to the ``int`` constant ``2``)

Values are real annotation values (as per ``inspect.VALUE`` format)
for defined values, and ``ForwardRef`` proxies for undefined values.
Real objects may be exposed to, or contain references to,
``ForwardRef`` proxy objects.

``inspect.SOURCE`` (equivalent to the ``int`` constant ``3``)

Values are the text string of the annotation as it
appears in the source code. May only be approximate;
whitespace may be normalized, and constant values may
be optimized. It's possible the exact values of these
strings could change in future version of Python.

``3`` (exported as ``inspect.FORWARDREF``)

Values are real annotation values (as per ``inspect.VALUE`` format)
for defined values, and ``ForwardRef`` proxies for undefined values.
Real objects may be exposed to, or contain references to,
``ForwardRef`` proxy objects.

If an ``__annotate__`` function doesn't support the requested
format, it must raise ``NotImplementedError()``.
``__annotate__`` functions must always support ``1`` (``inspect.VALUE``)
Expand Down Expand Up @@ -713,25 +751,12 @@ makes some modifications to the annotations before it returns them.
This PEP adds a new keyword-only parameter to these two functions,
``format``. ``format`` specifies what format the values in the
annotations dict should be returned in.
``format`` accepts the following values, defined as attributes on the
``inspect`` module::

VALUE = 1
FORWARDREF = 2
SOURCE = 3
The ``format`` parameter on these two functions accepts the same values
as the ``format`` parameter on the ``__annotate__`` magic method
defined above; however, these ``format`` parameters also have a default
value of ``inspect.VALUE``.

The default value for the ``format`` parameter is ``1``,
which is ``VALUE`` format.

The defined ``format`` values are guaranteed to be contiguous,
and the ``inspect`` module also publishes attributes representing
the minimum and maximum supported ``format`` values::

FORMAT_MIN = VALUE
FORMAT_MAX = SOURCE


Also, when either ``__annotations__`` or ``__annotate__`` is updated on an
When either ``__annotations__`` or ``__annotate__`` is updated on an
object, the other of those two attributes is now out-of-date and should also
either be updated or deleted (set to ``None``, in the case of ``__annotate__``
which cannot be deleted). In general, the semantics established in the previous
Expand Down Expand Up @@ -1017,40 +1042,29 @@ the wrapped callable, which for simplicity must be named
return ann


Other modifications to existing objects
=======================================
Other modifications to the Python runtime
=========================================

This PEP adds two more attributes to existing Python objects:
a ``__locals__`` attribute to function objects, and
an optional ``__globals__`` attribute to class objects.

In Python, the bytecode interpreter can reference both a
"globals" and a "locals" dictionary. However, the current
function object can only be bound to a globals dictionary,
via the ``__globals__`` attribute. Traditionally the
"locals" dictionary is only set when executing a class.
This PEP needs to set the "locals" dictionary to the class dict
when evaluating annotations defined inside a class namespace.
So this PEP defines a new ``__locals__`` attribute on
functions. By default it is uninitialized, or rather is set
to an internal value that indicates it hasn't been explicitly set.
It can be set to either ``None`` or a dictionary. If it's set to
a dictionary, the interpreter will use that dictionary as
the "locals" dictionary when running the function.

In Python, function objects contain a reference to their own
``__globals__``. However, class objects aren't currently
defined as doing so in Python. The implementation of
``__annotate__`` in CPython needs a reference to the module
globals in order to bind the unbound code object. So this PEP
defines a new ``__globals__`` attribute on class objects,
which stores a reference to the globals for the module where
the class was defined. Note that this attribute is optional,
but was useful for the CPython implementation.

(The class ``__globals__`` attribute does create a new reference
cycle, between a class and its module. However, any class that
contains a method already participates in at least one such cycle.)
This PEP does not dictate exactly how it should be
implemented; that is left up to the language implementation
maintainers. However, the best implementation of this
PEP may require adding additional information to existing
Python objects, which is implicitly condoned by the acceptance
of this PEP.

For example, it may be necessary to add a
``__globals__`` attribute to class objects, so that the
``__annotate__`` function for that class can be lazily
bound, only on demand. Also, ``__annotate__`` functions
defined on methods defined in a class may need to retain
a reference to the class's ``__dict__``, in order to
correctly evaluate names bound in that class. It's expected
that the CPython implementation of this PEP will include
both those new attributes.

All such new information added to existing Python objects
should be done with "dunder" attributes, as they will of
course be implementation details.


Interactive REPL Shell
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.