CINXE.COM
PEP 749 – Implementing PEP 649 | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 749 – Implementing PEP 649 | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0749/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 749 – Implementing PEP 649 | peps.python.org'> <meta property="og:description" content="This PEP supplements PEP 649 by providing various tweaks and additions to its specification:"> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0749/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="This PEP supplements PEP 649 by providing various tweaks and additions to its specification:"> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 749</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 749 – Implementing PEP 649</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Jelle Zijlstra <jelle.zijlstra at gmail.com></dd> <dt class="field-even">Discussions-To<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/pep-749-implementing-pep-649/54974">Discourse thread</a></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Proposal under active discussion and revision">Draft</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-odd">Topic<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="../topic/typing/">Typing</a></dd> <dt class="field-even">Requires<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="../pep-0649/">649</a></dd> <dt class="field-odd">Created<span class="colon">:</span></dt> <dd class="field-odd">28-May-2024</dd> <dt class="field-even">Python-Version<span class="colon">:</span></dt> <dd class="field-even">3.14</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/pep-749-implementing-pep-649/54974" title="Discourse thread">04-Jun-2024</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#the-future-of-from-future-import-annotations">The future of <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code></a><ul> <li><a class="reference internal" href="#specification">Specification</a></li> <li><a class="reference internal" href="#rejected-alternatives">Rejected alternatives</a></li> </ul> </li> <li><a class="reference internal" href="#new-annotationlib-module">New <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module</a><ul> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#id1">Specification</a></li> <li><a class="reference internal" href="#id2">Rejected alternatives</a></li> </ul> </li> <li><a class="reference internal" href="#behavior-of-the-repl">Behavior of the REPL</a><ul> <li><a class="reference internal" href="#id3">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#wrappers-that-provide-annotations">Wrappers that provide <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a><ul> <li><a class="reference internal" href="#id4">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#annotations-and-metaclasses">Annotations and metaclasses</a><ul> <li><a class="reference internal" href="#pre-existing-bugs">Pre-existing bugs</a></li> <li><a class="reference internal" href="#metaclass-behavior-with-pep-649">Metaclass behavior with PEP 649</a></li> <li><a class="reference internal" href="#id5">Specification</a></li> <li><a class="reference internal" href="#id6">Rejected alternatives</a></li> </ul> </li> <li><a class="reference internal" href="#adding-the-value-with-fake-globals-format">Adding the <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code> format</a><ul> <li><a class="reference internal" href="#id7">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#effect-of-deleting-annotations">Effect of deleting <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a><ul> <li><a class="reference internal" href="#id8">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#deferred-evaluation-of-pep-695-and-696-objects">Deferred evaluation of PEP 695 and 696 objects</a><ul> <li><a class="reference internal" href="#id9">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#behavior-of-dataclass-field-types">Behavior of dataclass field types</a></li> <li><a class="reference internal" href="#renaming-source-to-string">Renaming <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> to <code class="docutils literal notranslate"><span class="pre">STRING</span></code></a><ul> <li><a class="reference internal" href="#id10">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#miscellaneous-implementation-details">Miscellaneous implementation details</a><ul> <li><a class="reference internal" href="#supported-operations-on-forwardref-objects">Supported operations on <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> objects</a></li> <li><a class="reference internal" href="#signature-of-annotate-functions">Signature of <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li> <li><a class="reference internal" href="#appendix">Appendix</a><ul> <li><a class="reference internal" href="#which-expressions-can-be-stringified">Which expressions can be stringified?</a></li> </ul> </li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP supplements <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> by providing various tweaks and additions to its specification:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code> (<a class="pep reference internal" href="../pep-0563/" title="PEP 563 – Postponed Evaluation of Annotations">PEP 563</a>) will continue to exist with its current behavior at least until Python 3.13 reaches its end-of-life. Subsequently, it will be deprecated and eventually removed.</li> <li>A new standard library module, <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code>, is added to provide tooling for annotations. It will include the <code class="docutils literal notranslate"><span class="pre">get_annotations()</span></code> function, an enum for annotation formats, a <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> class, and a helper function for calling <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions.</li> <li>Annotations in the REPL are lazily evaluated, just like other module-level annotations.</li> <li>We specify the behavior of wrapper objects that provide annotations, such as <a class="reference external" href="https://docs.python.org/3/library/functions.html#classmethod" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">classmethod()</span></code></a> and code that uses <a class="reference external" href="https://docs.python.org/3/library/functools.html#functools.wraps" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.wraps()</span></code></a>.</li> <li>There will not be a code flag for marking <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions that can be run in a “fake globals” environment. Instead, we add a fourth format, <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code>, to allow third-party implementors of annotate functions to indicate what formats they support.</li> <li>Deleting the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> attribute directly will also clear <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code>.</li> <li>We add functionality to allow evaluating type alias values and type parameter bounds and defaults (which were added by <a class="pep reference internal" href="../pep-0695/" title="PEP 695 – Type Parameter Syntax">PEP 695</a> and <a class="pep reference internal" href="../pep-0696/" title="PEP 696 – Type Defaults for Type Parameters">PEP 696</a>) using PEP 649-like semantics.</li> <li>The <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> format is renamed to <code class="docutils literal notranslate"><span class="pre">STRING</span></code> to improve clarity and reduce the risk of user confusion.</li> </ul> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> provides an excellent framework for creating better semantics for annotations in Python. It solves a common pain point for users of annotations, including those using static type hints as well as those using runtime typing, and it makes the language more elegant and powerful. The PEP was originally proposed in 2021 for Python 3.10, and it was accepted in 2023. However, the implementation took longer than anticipated, and now the PEP is expected to be implemented in Python 3.14.</p> <p>I have started working on the implementation of the PEP in CPython. I found that the PEP leaves some areas underspecified, and some of its decisions in corner cases are questionable. This new PEP proposes several changes and additions to the specification to address these issues.</p> <p>This PEP supplements rather than supersedes PEP 649. The changes proposed here should make the overall user experience better, but they do not change the general framework of the earlier PEP.</p> </section> <section id="the-future-of-from-future-import-annotations"> <h2><a class="toc-backref" href="#the-future-of-from-future-import-annotations" role="doc-backlink">The future of <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code></a></h2> <p><a class="pep reference internal" href="../pep-0563/" title="PEP 563 – Postponed Evaluation of Annotations">PEP 563</a> previously introduced the future import <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code>, which changes all annotations to strings. <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> proposes an alternative approach that does not require this future import, and states:</p> <blockquote> <div>If this PEP is accepted, PEP 563 will be deprecated and eventually removed.</div></blockquote> <p>However, the PEP does not provide a detailed plan for this deprecation.</p> <p>There is some previous discussion of this topic <a class="reference external" href="https://discuss.python.org/t/pep-649-deferred-evaluation-of-annotations-tentatively-accepted/21331/44">on Discourse</a> (note that in the linked post I proposed something different from what is proposed here).</p> <section id="specification"> <h3><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h3> <p>We suggest the following deprecation plan:</p> <ul class="simple"> <li>In Python 3.14, <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code> will continue to work as it did before, converting annotations into strings.<ul> <li>If the future import is active, the <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> function of objects with annotations will return the annotations as strings when called with the <code class="docutils literal notranslate"><span class="pre">VALUE</span></code> format, reflecting the behavior of <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>.</li> </ul> </li> <li>Sometime after the last release that did not support <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> semantics (expected to be 3.13) reaches its end-of-life, <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code> is deprecated. Compiling any code that uses the future import will emit a <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#DeprecationWarning" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">DeprecationWarning</span></code></a>. This will happen no sooner than the first release after Python 3.13 reaches its end-of-life, but the community may decide to wait longer.</li> <li>After at least two releases, the future import is removed, and annotations are always evaluated as per <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>. Code that continues to use the future import will raise a <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#SyntaxError" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">SyntaxError</span></code></a>, similar to any other undefined future import.</li> </ul> </section> <section id="rejected-alternatives"> <h3><a class="toc-backref" href="#rejected-alternatives" role="doc-backlink">Rejected alternatives</a></h3> <p><em>Immediately make the future import a no-op</em>: We considered applying <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> semantics to all code in Python 3.14, making the future import a no-op. However, this would break code that works in 3.13 under the following set of conditions:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code> is active</li> <li>There are annotations that rely on forward references</li> <li>Annotations are eagerly evaluated at import time, for example by a metaclass or class or function decorator. For example, this currently applies to the released version of <code class="docutils literal notranslate"><span class="pre">typing_extensions.TypedDict</span></code>.</li> </ul> <p>This is expected to be a common pattern, so we cannot afford to break such code during the upgrade from 3.13 to 3.14.</p> <p>Such code would still break when the future import is eventually removed. However, this is many years in the future, giving affected libraries plenty of time to update their code.</p> <p><em>Immediately deprecate the future import</em>: Instead of waiting until Python 3.13 reaches its end-of-life, we could immediately start emitting warnings when the future import is used. However, many libraries are already using <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code> as an elegant way to enable unrestricted forward references in their annotations. If we deprecate the future import immediately, it would be impossible for these libraries to use unrestricted forward references on all supported Python versions while avoiding deprecation warnings: unlike other features deprecated from the standard library, a <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import must be the first statement in a given module, meaning it would be impossible to only conditionally import <code class="docutils literal notranslate"><span class="pre">__future__.annotations</span></code> on Python 3.13 and lower. (The necessary <code class="docutils literal notranslate"><span class="pre">sys.version_info</span></code> check would count as a statement preceding the <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import.)</p> <p><em>Keep the future import around forever</em>: We could also decide to keep the future import indefinitely. However, this would permanently bifurcate the behavior of the Python language. This is undesirable; the language should have only a single set of semantics, not two permanently different modes.</p> <p><em>Make the future import a no-op in the future</em>: Instead of eventually making <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code> a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code>, 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.</p> </section> </section> <section id="new-annotationlib-module"> <h2><a class="toc-backref" href="#new-annotationlib-module" role="doc-backlink">New <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module</a></h2> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> proposes to add tooling related to annotations to the <a class="reference external" href="https://docs.python.org/3/library/inspect.html#module-inspect" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">inspect</span></code></a> module. However, that module is rather large, has direct or indirect dependencies on at least 35 other standard library modules, and is so slow to import that other standard library modules are often discouraged from importing it. Furthermore, we anticipate adding more tools in addition to the <a class="reference external" href="https://docs.python.org/3/library/inspect.html#inspect.get_annotations" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">inspect.get_annotations()</span></code></a> function and the <code class="docutils literal notranslate"><span class="pre">VALUE</span></code>, <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code>, and <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> formats.</p> <p>A new standard library module provides a logical home for this functionality and also enables us to add more tooling that is useful for consumers of annotations.</p> <section id="rationale"> <h3><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h3> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> indicates that <code class="xref py py-class docutils literal notranslate"><span class="pre">typing.ForwardRef</span></code> should be used to implement the <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code> format in <a class="reference external" href="https://docs.python.org/3/library/inspect.html#inspect.get_annotations" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">inspect.get_annotations()</span></code></a>. However, the existing implementation of <code class="xref py py-class docutils literal notranslate"><span class="pre">typing.ForwardRef</span></code> is intertwined with the rest of the <code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code> module, and it would not make sense to add <code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code>-specific behavior to the generic <code class="docutils literal notranslate"><span class="pre">get_annotations()</span></code> function. Furthermore, <code class="xref py py-class docutils literal notranslate"><span class="pre">typing.ForwardRef</span></code> is a problematic class: it is public and documented, but the documentation lists no attributes or methods for it. Nonetheless, third-party libraries make use of some of its undocumented attributes. For instance, <a class="reference external" href="https://github.com/pydantic/pydantic/blob/00ff77ed37589d924d3c10e0d5a48a7ef679a0d7/pydantic/v1/typing.py#L66">Pydantic</a> and <a class="reference external" href="https://github.com/agronholm/typeguard/blob/016f8139f5a0a63147d68df9558cc5584cd2c49a/src/typeguard/_utils.py#L44">Typeguard</a> use the <code class="docutils literal notranslate"><span class="pre">_evaluate</span></code> method; <a class="reference external" href="https://github.com/beartype/beartype/blob/0b4453f83c7ed4be054d8733aab8075e1478e166/beartype/_util/hint/pep/proposal/pep484585/utilpep484585ref.py#L210">beartype</a> and <a class="reference external" href="https://github.com/quora/pyanalyze/blob/9e401724f9d035cf138b72612834b6d5a00eb8e8/pyanalyze/annotations.py#L509">pyanalyze</a> use the <code class="docutils literal notranslate"><span class="pre">__forward_arg__</span></code> attribute.</p> <p>We replace the existing but poorly specified <code class="xref py py-class docutils literal notranslate"><span class="pre">typing.ForwardRef</span></code> with a new class, <code class="docutils literal notranslate"><span class="pre">annotationlib.ForwardRef</span></code>. It is designed to be mostly compatible with existing uses of the <code class="xref py py-class docutils literal notranslate"><span class="pre">typing.ForwardRef</span></code> class, but without the behaviors specific to the <code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code> module. For compatibility with existing users, we keep the private <code class="docutils literal notranslate"><span class="pre">_evaluate</span></code> method, but mark it as deprecated. It delegates to a new public function in the <code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code> module, <code class="docutils literal notranslate"><span class="pre">typing.evaluate_forward_ref</span></code>, that is designed to evaluate forward references in a way that is specific to type hints.</p> <p>We add a function <code class="docutils literal notranslate"><span class="pre">annotationlib.call_annotate_function</span></code> as a helper for calling <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions. This is a useful building block when implementing functionality that needs to partially evaluate annotations while a class is being constructed. For example, the implementation of <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.NamedTuple" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.NamedTuple</span></code></a> needs to retrieve the annotations from a class namespace dictionary before the namedtuple class itself can be constructed, because the annotations determine what fields exist on the namedtuple.</p> </section> <section id="id1"> <h3><a class="toc-backref" href="#id1" role="doc-backlink">Specification</a></h3> <p>A new module, <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code>, is added to the standard library. Its aim is to provide tooling for introspecting and wrapping annotations.</p> <p>The design of the module is informed by the experience of updating the standard library (e.g., <a class="reference external" href="https://docs.python.org/3/library/dataclasses.html#module-dataclasses" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">dataclasses</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypedDict</span></code></a>) to use <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> semantics.</p> <p>The module will contain the following functionality:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">get_annotations()</span></code>: A function that returns the annotations of a function, module, or class. This will replace <a class="reference external" href="https://docs.python.org/3/library/inspect.html#inspect.get_annotations" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">inspect.get_annotations()</span></code></a>. The latter will delegate to the new function. It may eventually be deprecated, but to minimize disruption, we do not propose an immediate deprecation.</li> <li><code class="docutils literal notranslate"><span class="pre">get_annotate_function()</span></code>: A function that returns the <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> function of an object, if it has one, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if it does not. This is usually equivalent to accessing the <code class="docutils literal notranslate"><span class="pre">.__annotate__</span></code> attribute, except in the presence of metaclasses (see <a class="reference internal" href="#pep749-metaclasses"><span class="std std-ref">below</span></a>).</li> <li><code class="docutils literal notranslate"><span class="pre">Format</span></code>: an enum that contains the possible formats of annotations. This will replace the <code class="docutils literal notranslate"><span class="pre">VALUE</span></code>, <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code>, and <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> formats in <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>. PEP 649 proposed to make these values global members of the <a class="reference external" href="https://docs.python.org/3/library/inspect.html#module-inspect" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">inspect</span></code></a> module; we prefer to place them within an enum. We propose to add a fourth format, <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code> (see below).</li> <li><code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code>: a class representing a forward reference; it may be returned by <code class="docutils literal notranslate"><span class="pre">get_annotations()</span></code> when the format is <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code>. The existing class <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.ForwardRef" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.ForwardRef</span></code></a> will become an alias of this class. Its members include:<ul> <li><code class="docutils literal notranslate"><span class="pre">__forward_arg__</span></code>: the string argument of the forward reference</li> <li><code class="docutils literal notranslate"><span class="pre">evaluate(globals=None,</span> <span class="pre">locals=None,</span> <span class="pre">type_params=None,</span> <span class="pre">owner=None)</span></code>: a method that attempts to evaluate the forward reference. The <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> object may hold a reference to the globals and other namespaces of the object that it originated from. If so, these namespaces may be used to evaluate the forward reference. The <em>owner</em> argument may be the object that holds the original annotation, such as the class or module object; it is used to extract the globals and locals namespaces if these are not provided.</li> <li><code class="docutils literal notranslate"><span class="pre">_evaluate()</span></code>, with the same interface as the existing <code class="docutils literal notranslate"><span class="pre">ForwardRef._evaluate</span></code> method. It will be undocumented and immediately deprecated. It is provided for compatibility with existing users of <code class="docutils literal notranslate"><span class="pre">typing.ForwardRef</span></code>.</li> </ul> </li> <li><code class="docutils literal notranslate"><span class="pre">call_annotate_function(func:</span> <span class="pre">Callable,</span> <span class="pre">format:</span> <span class="pre">Format)</span></code>: a helper for calling an <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> function with a given format. If the function does not support this format, <code class="docutils literal notranslate"><span class="pre">call_annotate_function()</span></code> will set up a “fake globals” environment, as described in <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>, and use that environment to return the desired annotations format.</li> <li><code class="docutils literal notranslate"><span class="pre">call_evaluate_function(func:</span> <span class="pre">Callable</span> <span class="pre">|</span> <span class="pre">None,</span> <span class="pre">format:</span> <span class="pre">Format)</span></code>: similar to <code class="docutils literal notranslate"><span class="pre">call_annotate_function</span></code>, but does not rely on the function returning an annotations dictionary. This is intended to be used for evaluating deferred attributes introduced by <a class="pep reference internal" href="../pep-0695/" title="PEP 695 – Type Parameter Syntax">PEP 695</a> and <a class="pep reference internal" href="../pep-0696/" title="PEP 696 – Type Defaults for Type Parameters">PEP 696</a>; see below for details. <em>func</em> may be <code class="docutils literal notranslate"><span class="pre">None</span></code> for convenience; if <code class="docutils literal notranslate"><span class="pre">None</span></code> is passed, the function also returns <code class="docutils literal notranslate"><span class="pre">None</span></code>.</li> <li><code class="docutils literal notranslate"><span class="pre">annotations_to_string(annotations:</span> <span class="pre">dict[str,</span> <span class="pre">object])</span> <span class="pre">-></span> <span class="pre">dict[str,</span> <span class="pre">str]</span></code>: a function that converts each value in an annotations dictionary to a string representation. This is useful for implementing the <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> format in cases where the original source is not available, such as in the functional syntax for <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypedDict</span></code></a>.</li> <li><code class="docutils literal notranslate"><span class="pre">value_to_string(value:</span> <span class="pre">object)</span> <span class="pre">-></span> <span class="pre">str</span></code>: a function that converts a single value to a string representation. This is used by <code class="docutils literal notranslate"><span class="pre">annotations_to_string</span></code>. It uses <code class="docutils literal notranslate"><span class="pre">repr()</span></code> for most values, but for types it returns the fully qualified name. It is also useful as a helper for the <code class="docutils literal notranslate"><span class="pre">repr()</span></code> of a number of objects in the <a class="reference external" href="https://docs.python.org/3/library/typing.html#module-typing" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/collections.abc.html#module-collections.abc" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">collections.abc</span></code></a> modules.</li> </ul> <p>A new function is also added to the <code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code> module, <code class="docutils literal notranslate"><span class="pre">typing.evaluate_forward_ref</span></code>. This function is a wrapper around the <code class="docutils literal notranslate"><span class="pre">ForwardRef.evaluate</span></code> method, but it performs additional work that is specific to type hints. For example, it recurses into complex types and evaluates additional forward references within these types.</p> <p>Contrary to <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>, the annotation formats (<code class="docutils literal notranslate"><span class="pre">VALUE</span></code>, <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code>, and <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code>) will not be added as global members of the <a class="reference external" href="https://docs.python.org/3/library/inspect.html#module-inspect" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">inspect</span></code></a> module. The only recommended way to refer to these constants will be as <code class="docutils literal notranslate"><span class="pre">annotationlib.Format.VALUE</span></code>.</p> </section> <section id="id2"> <h3><a class="toc-backref" href="#id2" role="doc-backlink">Rejected alternatives</a></h3> <p><em>Use a different name</em>: Naming is hard, and I considered several ideas:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">annotations</span></code>: The most obvious name, but it may cause confusion with the existing <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code>, because users may have both <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">annotations</span></code> and <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code> 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 <a class="extlink-pypi reference external" href="https://pypi.org/project/annotations/">annotations</a>, but it had only a single release in 2015 and looks abandoned.</li> <li><code class="docutils literal notranslate"><span class="pre">annotation</span></code> (in the singular): Similar, but does not cause confusion with the future import. There is an abandoned PyPI package <a class="extlink-pypi reference external" href="https://pypi.org/project/annotation/">annotation</a>, but it apparently never released any artifacts.</li> <li><code class="docutils literal notranslate"><span class="pre">annotools</span></code>: Analogous to <a class="reference external" href="https://docs.python.org/3/library/itertools.html#module-itertools" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">itertools</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/functools.html#module-functools" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">functools</span></code></a>, but “anno” is a less obvious abbreviation than “iter” or “func”. As of this writing, there is no PyPI package with this name.</li> <li><code class="docutils literal notranslate"><span class="pre">annotationtools</span></code>: A more explicit version. There is a PyPI package <a class="extlink-pypi reference external" href="https://pypi.org/project/annotationtools/">annotationtools</a>, which had a release in 2023.</li> <li><code class="docutils literal notranslate"><span class="pre">annotation_tools</span></code>: A variation of the above but without a PyPI conflict. However, no other public standard library module has an underscore in its name.</li> <li><code class="docutils literal notranslate"><span class="pre">annotationslib</span></code>: Analogous to <a class="reference external" href="https://docs.python.org/3/library/tomllib.html#module-tomllib" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">tomllib</span></code></a>, <a class="reference external" href="https://docs.python.org/3/library/pathlib.html#module-pathlib" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">pathlib</span></code></a>, and <a class="reference external" href="https://docs.python.org/3/library/importlib.html#module-importlib" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a>. There is no PyPI package with this name.</li> <li><code class="docutils literal notranslate"><span class="pre">annotationlib</span></code>: Similar to the above, but one character shorter and subjectively reads better. Also not taken on PyPI.</li> </ul> <p><code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> appears to be the best option.</p> <p><em>Add the functionality to the inspect module</em>: As described above, the <a class="reference external" href="https://docs.python.org/3/library/inspect.html#module-inspect" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">inspect</span></code></a> module is already quite large, and its import time is prohibitive for some use cases.</p> <p><em>Add the functionality to the typing module</em>: While annotations are mostly used for typing, they may also be used for other purposes. We prefer to keep a clean separation between functionality for introspecting annotations and functionality that is exclusively meant for type hints.</p> <p><em>Add the functionality to the types module</em>: The <a class="reference external" href="https://docs.python.org/3/library/types.html#module-types" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">types</span></code></a> module is meant for functionality related to <em>types</em>, and annotations can exist on functions and modules, not only on types.</p> <p><em>Develop this functionality in a third-party package</em>: The functionality in this new module will be pure Python code, and it is possible to implement a third-party package that provides the same functionality by interacting directly with <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions generated by the interpreter. However, the functionality of the proposed new module will certainly be useful in the standard library itself (e.g., for implementing <a class="reference external" href="https://docs.python.org/3/library/dataclasses.html#module-dataclasses" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">dataclasses</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.NamedTuple" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.NamedTuple</span></code></a>), so it makes sense to include it in the standard library.</p> <p><em>Add this functionality to a private module</em>: It would be possible to initially develop the module in a private standard library module (e.g., <code class="docutils literal notranslate"><span class="pre">_annotations</span></code>), and publicize it only after we have gained more experience with the API. However, we already know that we will need parts of this module for the standard library itself (e.g., for implementing <code class="xref py py-mod docutils literal notranslate"><span class="pre">dataclasses</span></code> and <code class="xref py py-class docutils literal notranslate"><span class="pre">typing.NamedTuple</span></code>). Even if we make it private, the module will inevitably get used by third-party users. It is preferable to start with a clear, documented API from the beginning, to enable third-party users to support <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> semantics as thoroughly as the standard library. The module will immediately be used in other parts of the standard library, ensuring that it covers a reasonable set of use cases.</p> </section> </section> <section id="behavior-of-the-repl"> <h2><a class="toc-backref" href="#behavior-of-the-repl" role="doc-backlink">Behavior of the REPL</a></h2> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> specifies the following behavior of the interactive REPL:</p> <blockquote> <div>For the sake of simplicity, in this case we forego delayed evaluation. Module-level annotations in the REPL shell will continue to work exactly as they do with “stock semantics”, evaluating immediately and setting the result directly inside the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> dict.</div></blockquote> <p>There are several problems with this proposed behavior. It makes the REPL the only context where annotations are still evaluated immediately, which is confusing for users and complicates the language.</p> <p>It also makes the implementation of the REPL more complex, as it needs to ensure that all statements are compiled in “interactive” mode, even if their output does not need to be displayed. (This matters if there are multiple statements in a single line evaluated by the REPL.)</p> <p>Most importantly, this breaks some plausible use cases that inexperienced users could run into. A user might write the following in a file:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span><span class="p">:</span> <span class="n">X</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span> <span class="k">class</span><span class="w"> </span><span class="nc">X</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> <p>Under <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> this would work fine: <code class="docutils literal notranslate"><span class="pre">X</span></code> is not yet defined when it is used in the annotation for <code class="docutils literal notranslate"><span class="pre">a</span></code>, but the annotation is lazily evaluated. However, if a user were to paste this same code into the REPL and execute it line by line, it would throw a <code class="docutils literal notranslate"><span class="pre">NameError</span></code>, because the name <code class="docutils literal notranslate"><span class="pre">X</span></code> is not yet defined.</p> <p>This topic was previously discussed <a class="reference external" href="https://discuss.python.org/t/pep-649-behavior-of-the-repl/54109">on Discourse</a>.</p> <section id="id3"> <h3><a class="toc-backref" href="#id3" role="doc-backlink">Specification</a></h3> <p>We propose to treat the interactive console like any other module-level code, and make annotations lazily evaluated. This makes the language more consistent and avoids subtle behavior changes between modules and the REPL.</p> <p>Because the REPL is evaluated line by line, we would generate a new <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> function for every evaluated statement in the global scope that contains annotations. Whenever a line containing annotations is evaluated, the previous <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> function is lost:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span> <span class="gp">>>> </span><span class="n">__annotate__</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="go">{'x': <class 'int'>}</span> <span class="gp">>>> </span><span class="n">y</span><span class="p">:</span> <span class="nb">str</span> <span class="gp">>>> </span><span class="n">__annotate__</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="go">{'y': <class 'str'>}</span> <span class="gp">>>> </span><span class="n">z</span><span class="p">:</span> <span class="n">doesntexist</span> <span class="gp">>>> </span><span class="n">__annotate__</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="gt">Traceback (most recent call last):</span> <span class="gr">File "<python-input-5>", line 1, in <module></span> <span class="gr"> __annotate__(1)</span> <span class="gr"> ~~~~~~~~~~~~^^^</span> <span class="gr">File "<python-input-4>", line 1, in __annotate__</span> <span class="gr"> z</span>: <span class="n">doesntexist</span> <span class="x"> ^^^^^^^^^^^</span> <span class="x">NameError: name 'doesntexist' is not defined</span> </pre></div> </div> <p>There will be no <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> key in the global namespace of the REPL. In module namespaces, this key is created lazily when the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> descriptor of the module object is accessed, but in the REPL there is no such module object.</p> <p>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 <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> and <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> attributes or use the <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module to introspect the annotations.</p> </section> </section> <section id="wrappers-that-provide-annotations"> <h2><a class="toc-backref" href="#wrappers-that-provide-annotations" role="doc-backlink">Wrappers that provide <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a></h2> <p>Several objects in the standard library and elsewhere provide annotations for their wrapped object. <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> does not specify how such wrappers should behave.</p> <section id="id4"> <h3><a class="toc-backref" href="#id4" role="doc-backlink">Specification</a></h3> <p>Wrappers that provide annotations should be designed with the following goals in mind:</p> <ul class="simple"> <li>Evaluation of <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> should be deferred for as long as possible, consistent with the behavior of built-in functions, classes, and modules.</li> <li>Backward compatibility with the behavior prior to the implementation of <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> should be preserved.</li> <li>The <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> and <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> attributes should both be supplied with semantics consistent to those of the wrapped object.</li> </ul> <p>More specifically:</p> <ul class="simple"> <li><a class="reference external" href="https://docs.python.org/3/library/functools.html#functools.update_wrapper" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.update_wrapper()</span></code></a> (and therefore <a class="reference external" href="https://docs.python.org/3/library/functools.html#functools.wraps" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.wraps()</span></code></a>) will copy only the <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> attribute from the wrapped object to the wrapper. The <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> descriptor on the wrapper function will use the copied <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code>.</li> <li>The constructors for <a class="reference external" href="https://docs.python.org/3/library/functions.html#classmethod" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">classmethod()</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/functions.html#staticmethod" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">staticmethod()</span></code></a> currently copy the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> attribute from the wrapped object to the wrapper. They will instead have writable attributes for <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> and <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>. Reading these attributes will retrieve the corresponding attribute from the underlying callable and cache it in the wrapper’s <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>. Writing to these attributes will directly update the <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>, without affecting the wrapped callable.</li> </ul> </section> </section> <section id="annotations-and-metaclasses"> <span id="pep749-metaclasses"></span><h2><a class="toc-backref" href="#annotations-and-metaclasses" role="doc-backlink">Annotations and metaclasses</a></h2> <p>Testing of the initial implementation of this PEP revealed serious problems with the interaction between metaclasses and class annotations.</p> <section id="pre-existing-bugs"> <h3><a class="toc-backref" href="#pre-existing-bugs" role="doc-backlink">Pre-existing bugs</a></h3> <p>We found several bugs in the existing behavior of <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> on classes while investigating the behaviors to be specified in this PEP. Fixing these bugs on Python 3.13 and earlier is outside the scope of this PEP, but they are noted here to explain the corner cases that need to be dealt with.</p> <p>For context, on Python 3.10 through 3.13 the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> dictionary is placed in the class namespace if the class has any annotations. If it does not, there is no <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> class dictionary key when the class is created, but accessing <code class="docutils literal notranslate"><span class="pre">cls.__annotations__</span></code> invokes a descriptor defined on <code class="docutils literal notranslate"><span class="pre">type</span></code> that returns an empty dictionary and stores it in the class dictionary. <a class="reference external" href="https://docs.python.org/3/c-api/typeobj.html#static-types" title="(in Python v3.13)"><span class="xref std std-ref">Static types</span></a> are an exception: they never have annotations, and accessing <code class="docutils literal notranslate"><span class="pre">.__annotations__</span></code> raises <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#AttributeError" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">AttributeError</span></code></a>. On Python 3.9 and earlier, the behavior was different; see <a class="reference external" href="https://github.com/python/cpython/issues/88067">gh-88067</a>.</p> <p>The following code fails identically on Python 3.10 through 3.13:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Meta</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span> <span class="k">pass</span> <span class="k">class</span><span class="w"> </span><span class="nc">X</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">Meta</span><span class="p">):</span> <span class="n">a</span><span class="p">:</span> <span class="nb">str</span> <span class="k">class</span><span class="w"> </span><span class="nc">Y</span><span class="p">(</span><span class="n">X</span><span class="p">):</span> <span class="k">pass</span> <span class="n">Meta</span><span class="o">.</span><span class="vm">__annotations__</span> <span class="c1"># important</span> <span class="k">assert</span> <span class="n">Y</span><span class="o">.</span><span class="vm">__annotations__</span> <span class="o">==</span> <span class="p">{},</span> <span class="n">Y</span><span class="o">.</span><span class="vm">__annotations__</span> <span class="c1"># fails: {'a': <class 'str'>}</span> </pre></div> </div> <p>If the annotations on the metaclass <code class="docutils literal notranslate"><span class="pre">Meta</span></code> are accessed before the annotations on <code class="docutils literal notranslate"><span class="pre">Y</span></code>, then the annotations for the base class <code class="docutils literal notranslate"><span class="pre">X</span></code> are leaked to <code class="docutils literal notranslate"><span class="pre">Y</span></code>. However, if the metaclass’s annotations are <em>not</em> accessed (i.e., the line <code class="docutils literal notranslate"><span class="pre">Meta.__annotations__</span></code> above is removed), then the annotations for <code class="docutils literal notranslate"><span class="pre">Y</span></code> are correctly empty.</p> <p>Similarly, annotations from annotated metaclasses leak to unannotated classes that are instances of the metaclass:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Meta</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span> <span class="n">a</span><span class="p">:</span> <span class="nb">str</span> <span class="k">class</span><span class="w"> </span><span class="nc">X</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">Meta</span><span class="p">):</span> <span class="k">pass</span> <span class="k">assert</span> <span class="n">X</span><span class="o">.</span><span class="vm">__annotations__</span> <span class="o">==</span> <span class="p">{},</span> <span class="n">X</span><span class="o">.</span><span class="vm">__annotations__</span> <span class="c1"># fails: {'a': <class 'str'>}</span> </pre></div> </div> <p>The reason for these behaviors is that if the metaclass contains an <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> entry in its class dictionary, this prevents instances of the metaclass from using the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> data descriptor on the base <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> class. In the first case, accessing <code class="docutils literal notranslate"><span class="pre">Meta.__annotations__</span></code> sets <code class="docutils literal notranslate"><span class="pre">Meta.__dict__["__annotations__"]</span> <span class="pre">=</span> <span class="pre">{}</span></code> as a side effect. Then, looking up the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> attribute on <code class="docutils literal notranslate"><span class="pre">Y</span></code> first sees the metaclass attribute, but skips it because it is a data descriptor. Next, it looks in the class dictionaries of the classes in its method resolution order (MRO), finds <code class="docutils literal notranslate"><span class="pre">X.__annotations__</span></code>, and returns it. In the second example, there are no annotations anywhere in the MRO, so <code class="docutils literal notranslate"><span class="pre">type.__getattribute__</span></code> falls back to returning the metaclass attribute.</p> </section> <section id="metaclass-behavior-with-pep-649"> <h3><a class="toc-backref" href="#metaclass-behavior-with-pep-649" role="doc-backlink">Metaclass behavior with PEP 649</a></h3> <p>With <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>, the behavior of accessing the <code class="docutils literal notranslate"><span class="pre">.__annotations__</span></code> attribute on classes when metaclasses are involved becomes even more erratic, because now <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> is only lazily added to the class dictionary even for classes with annotations. The new <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> attribute is also lazily created on classes without annotations, which causes further misbehaviors when metaclasses are involved.</p> <p>The cause of these problems is that we set the <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> and <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> class dictionary entries only under some circumstances, and rely on descriptors defined on <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> to fill them in if they are not set. When normal attribute lookup is used, this approach breaks down in the presence of metaclasses, because entries in the metaclass’s own class dictionary can render the descriptors invisible.</p> <p>While we considered several approaches that would allow <code class="docutils literal notranslate"><span class="pre">cls.__annotations__</span></code> and <code class="docutils literal notranslate"><span class="pre">cls.__annotate__</span></code> to work reliably when <code class="docutils literal notranslate"><span class="pre">cls</span></code> is a type with a custom metaclass, any such approach would expose significant complexity to advanced users. Instead, we recommend a simpler approach that confines the complexity to the <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module: in <code class="docutils literal notranslate"><span class="pre">annotationlib.get_annotations</span></code>, we bypass normal attribute lookup by using the <code class="docutils literal notranslate"><span class="pre">type.__annotations__</span></code> descriptor directly.</p> </section> <section id="id5"> <h3><a class="toc-backref" href="#id5" role="doc-backlink">Specification</a></h3> <p>Users should always use <code class="docutils literal notranslate"><span class="pre">annotationlib.get_annotations</span></code> to access the annotations of a class object, and <code class="docutils literal notranslate"><span class="pre">annotationlib.get_annotate_function</span></code> to access the <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> function. These functions will return only the class’s own annotations, even when metaclasses are involved.</p> <p>The behavior of accessing the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> and <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> attributes on classes with a metaclass other than <code class="docutils literal notranslate"><span class="pre">builtins.type</span></code> is unspecified. The documentation should warn against direct use of these attributes and recommend using the <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module instead.</p> <p>Similarly, the presence of <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> and <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> keys in the class dictionary is an implementation detail and should not be relied upon.</p> </section> <section id="id6"> <h3><a class="toc-backref" href="#id6" role="doc-backlink">Rejected alternatives</a></h3> <p>We considered two broad approaches for dealing with the behavior of the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> and <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> entries in classes:</p> <ul class="simple"> <li>Ensure that the entry is <em>always</em> present in the class dictionary, even if it is empty or has not yet been evaluated. This means we do not have to rely on the descriptors defined on <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> to fill in the field, and therefore the metaclass’s attributes will not interfere. (Prototype in <a class="reference external" href="https://github.com/python/cpython/pull/120719">gh-120719</a>.)</li> <li>Ensure that the entry is <em>never</em> present in the class dictionary, or at least never added by logic in the language core. This means that the descriptors on <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> will always be used, without interference from the metaclass. (Prototype in <a class="reference external" href="https://github.com/python/cpython/pull/120816">gh-120816</a>.)</li> </ul> <p>Alex Waygood suggested an implementation using the first approach. When a heap type (such as a class created through the <code class="docutils literal notranslate"><span class="pre">class</span></code> statement) is created, <code class="docutils literal notranslate"><span class="pre">cls.__dict__["__annotations__"]</span></code> is set to a special descriptor. On <code class="docutils literal notranslate"><span class="pre">__get__</span></code>, the descriptor evaluates the annotations by calling <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> and returning the result. The annotations dictionary is cached within the descriptor instance. The descriptor also behaves like a mapping, so that code that uses <code class="docutils literal notranslate"><span class="pre">cls.__dict__["__annotations__"]</span></code> will still usually work: treating the object as a mapping will evaluate the annotations and behave as if the descriptor itself was the annotations dictionary. (Code that assumes that <code class="docutils literal notranslate"><span class="pre">cls.__dict__["__annotations__"]</span></code> is specifically an instance of <code class="docutils literal notranslate"><span class="pre">dict</span></code> may break, however.)</p> <p>This approach is also straightforward to implement for <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code>: this attribute is already always set for classes with annotations, and we can set it explicitly to <code class="docutils literal notranslate"><span class="pre">None</span></code> for classes without annotations.</p> <p>While this approach would fix the known edge cases with metaclasses, it introduces significant complexity to all classes, including a new built-in type (for the annotations descriptor) with unusual behavior.</p> <p>The alternative approach would be to never set <code class="docutils literal notranslate"><span class="pre">__dict__["__annotations__"]</span></code> and use some other storage to store the cached annotations. This behavior change would have to apply even to classes defined under <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code>, because otherwise there could be buggy behavior if a class is defined without <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code> but its metaclass does have the future enabled. As <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> previously noted, removing <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> from class dictionaries also has backwards compatibility implications: <code class="docutils literal notranslate"><span class="pre">cls.__dict__.get("__annotations__")</span></code> is a common idiom to retrieve annotations.</p> <p>This approach would also mean that accessing <code class="docutils literal notranslate"><span class="pre">.__annotations__</span></code> on an instance of an annotated class no longer works. While this behavior is not documented, it is a long-standing feature of Python and is relied upon by some users.</p> </section> </section> <section id="adding-the-value-with-fake-globals-format"> <h2><a class="toc-backref" href="#adding-the-value-with-fake-globals-format" role="doc-backlink">Adding the <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code> format</a></h2> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> specifies:</p> <blockquote> <div>This PEP assumes that third-party libraries may implement their own <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> methods, and those functions would almost certainly work incorrectly when run in this “fake globals” environment. For that reason, this PEP allocates a flag on code objects, one of the unused bits in <code class="docutils literal notranslate"><span class="pre">co_flags</span></code>, to mean “This code object can be run in a ‘fake globals’ environment.” This makes the “fake globals” environment strictly opt-in, and it’s expected that only <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> methods generated by the Python compiler will set it.</div></blockquote> <p>However, this mechanism couples the implementation with low-level details of the code object. The code object flags are CPython-specific and the documentation <a class="reference external" href="https://docs.python.org/3/library/inspect.html#inspect-module-co-flags" title="(in Python v3.13)"><span class="xref std std-ref">explicitly warns</span></a> against relying on the values.</p> <p>Larry Hastings suggested an alternative approach that does not rely on code flags: a fourth format, <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code>. Compiler-generated annotate functions would support only the <code class="docutils literal notranslate"><span class="pre">VALUE</span></code> and <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code> formats, both of which are implemented identically. The standard library would use the <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code> format when invoking an annotate function in one of the special “fake globals” environments.</p> <p>This approach is useful as a forward-compatible mechanism for adding new annotation formats in the future. Users who manually write annotate functions should raise <code class="docutils literal notranslate"><span class="pre">NotImplementedError</span></code> if the <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code> format is requested, so the standard library will not call the manually written annotate function with “fake globals”, which could have unpredictable results.</p> <section id="id7"> <h3><a class="toc-backref" href="#id7" role="doc-backlink">Specification</a></h3> <p>An additional format, <code class="docutils literal notranslate"><span class="pre">FAKE_GLOBALS_VALUE</span></code>, is added to the <code class="docutils literal notranslate"><span class="pre">Format</span></code> enum in the <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module, with value equal to 2. (As a result, the values of the other formats will shift relative to PEP 649: <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code> will be 3 and <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> will be 4.)</p> <p>Compiler-generated annotate functions will support this format and return the same value as they would return for the <code class="docutils literal notranslate"><span class="pre">VALUE</span></code> format. The standard library will pass this format to the <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> function when it is called in a “fake globals” environment, as used to implement the <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code> and <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> formats. All public functions in the <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module that accept a format argument will raise <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#NotImplementedError" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">NotImplementedError</span></code></a> if the format is <code class="docutils literal notranslate"><span class="pre">FAKE_GLOBALS_VALUE</span></code>.</p> <p>Third-party code that implements <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions should raise <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#NotImplementedError" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">NotImplementedError</span></code></a> if the <code class="docutils literal notranslate"><span class="pre">FAKE_GLOBALS_VALUE</span></code> format is passed and the function is not prepared to be run in a “fake globals” environment. This should be mentioned in the data model documentation for <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code>.</p> </section> </section> <section id="effect-of-deleting-annotations"> <h2><a class="toc-backref" href="#effect-of-deleting-annotations" role="doc-backlink">Effect of deleting <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a></h2> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> specifies:</p> <blockquote> <div>Setting <code class="docutils literal notranslate"><span class="pre">o.__annotations__</span></code> to a legal value automatically sets <code class="docutils literal notranslate"><span class="pre">o.__annotate__</span></code> to <code class="docutils literal notranslate"><span class="pre">None</span></code>.</div></blockquote> <p>However, the PEP does not say what happens if the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> attribute is deleted (using <code class="docutils literal notranslate"><span class="pre">del</span></code>). It seems most consistent that deleting the attribute will also delete <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code>.</p> <section id="id8"> <h3><a class="toc-backref" href="#id8" role="doc-backlink">Specification</a></h3> <p>Deleting the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> attribute on functions, modules, and classes results in setting <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> to None.</p> </section> </section> <section id="deferred-evaluation-of-pep-695-and-696-objects"> <h2><a class="toc-backref" href="#deferred-evaluation-of-pep-695-and-696-objects" role="doc-backlink">Deferred evaluation of PEP 695 and 696 objects</a></h2> <p>Since <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> was written, Python 3.12 and 3.13 gained support for several new features that also use deferred evaluation, similar to the behavior this PEP proposes for annotations:</p> <ul class="simple"> <li>The value of type aliases created through the <a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#type" title="(in Python v3.13)"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">type</span></code></a> statement (<a class="pep reference internal" href="../pep-0695/" title="PEP 695 – Type Parameter Syntax">PEP 695</a>)</li> <li>The bound and constraints of <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypeVar" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypeVar</span></code></a> objects created through the syntax for generics (<a class="pep reference internal" href="../pep-0695/" title="PEP 695 – Type Parameter Syntax">PEP 695</a>)</li> <li>The default value of <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypeVar" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypeVar</span></code></a>, <code class="xref py py-class docutils literal notranslate"><span class="pre">ParamSpec</span></code>, and <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypeVarTuple" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypeVarTuple</span></code></a> objects (<a class="pep reference internal" href="../pep-0696/" title="PEP 696 – Type Defaults for Type Parameters">PEP 696</a>)</li> </ul> <p>Currently, these objects use deferred evaluation, but there is no direct access to the function object used for deferred evaluation. To enable the same kind of introspection that is now possible for annotations, we propose to expose the internal function objects, allowing users to evaluate them using the FORWARDREF and SOURCE formats.</p> <section id="id9"> <h3><a class="toc-backref" href="#id9" role="doc-backlink">Specification</a></h3> <p>We will add the following new attributes:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">evaluate_value</span></code> on <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypeAliasType" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypeAliasType</span></code></a></li> <li><code class="docutils literal notranslate"><span class="pre">evaluate_bound</span></code>, <code class="docutils literal notranslate"><span class="pre">evaluate_constraints</span></code>, and <code class="docutils literal notranslate"><span class="pre">evaluate_default</span></code> on <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypeVar" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypeVar</span></code></a></li> <li><code class="docutils literal notranslate"><span class="pre">evaluate_default</span></code> on <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.ParamSpec" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.ParamSpec</span></code></a></li> <li><code class="docutils literal notranslate"><span class="pre">evaluate_default</span></code> on <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypeVarTuple" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypeVarTuple</span></code></a></li> </ul> <p>Except for <code class="docutils literal notranslate"><span class="pre">evaluate_value</span></code>, these attributes may be <code class="docutils literal notranslate"><span class="pre">None</span></code> if the object does not have a bound, constraints, or default. Otherwise, the attribute is a callable, similar to an <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> function, that takes a single integer argument and returns the evaluated value. Unlike <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions, these callables return a single value, not a dictionary of annotations. These attributes are read-only.</p> <p>Usually, users would use these attributes in combinations with <code class="docutils literal notranslate"><span class="pre">annotationlib.call_evaluate_function</span></code>. For example, to get a <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>’s bound in SOURCE format, one could write <code class="docutils literal notranslate"><span class="pre">annotationlib.call_evaluate_function(T.evaluate_bound,</span> <span class="pre">annotationlib.Format.SOURCE)</span></code>.</p> </section> </section> <section id="behavior-of-dataclass-field-types"> <h2><a class="toc-backref" href="#behavior-of-dataclass-field-types" role="doc-backlink">Behavior of dataclass field types</a></h2> <p>One consequence of the deferred evaluation of annotations is that dataclasses can use forward references in their annotations:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span><span class="w"> </span><span class="nn">dataclasses</span><span class="w"> </span><span class="kn">import</span> <span class="n">dataclass</span> <span class="gp">>>> </span><span class="nd">@dataclass</span> <span class="gp">... </span><span class="k">class</span><span class="w"> </span><span class="nc">D</span><span class="p">:</span> <span class="gp">... </span> <span class="n">x</span><span class="p">:</span> <span class="n">undefined</span> <span class="gp">...</span> </pre></div> </div> <p>However, the <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code> format leaks into the field types of the dataclass:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">fields</span><span class="p">(</span><span class="n">D</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">type</span> <span class="go">ForwardRef('undefined')</span> </pre></div> </div> <p>We considered a change where the <code class="docutils literal notranslate"><span class="pre">.type</span></code> attribute of a field object would trigger evaluation of annotations, so that the field type could contain actual values in the case of forward references that were defined after the dataclass itself was created, but before the field type is accessed. However, this would also mean that accessing <code class="docutils literal notranslate"><span class="pre">.type</span></code> could now run arbitrary code in the annotation, and potentially throws errors such as <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#NameError" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">NameError</span></code></a>.</p> <p>Therefore, we consider it more user-friendly to keep the <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> object in the type, and document that users who want to resolve forward references can use the <code class="docutils literal notranslate"><span class="pre">ForwardRef.evaluate</span></code> method.</p> <p>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.</p> </section> <section id="renaming-source-to-string"> <h2><a class="toc-backref" href="#renaming-source-to-string" role="doc-backlink">Renaming <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> to <code class="docutils literal notranslate"><span class="pre">STRING</span></code></a></h2> <p>The <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> 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 <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions, and in some cases, we have <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions in Python code that do not have access to the original code. For example, this applies to <a class="reference external" href="https://docs.python.org/3/library/dataclasses.html#dataclasses.make_dataclass" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">dataclasses.make_dataclass()</span></code></a> and the call-based syntax for <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypedDict</span></code></a>.</p> <p>This makes the name <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> 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 <code class="docutils literal notranslate"><span class="pre">STRING</span></code>.</p> <section id="id10"> <h3><a class="toc-backref" href="#id10" role="doc-backlink">Specification</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> format is renamed to <code class="docutils literal notranslate"><span class="pre">STRING</span></code>. To reiterate the changes in this PEP, the four supported formats are now:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">VALUE</span></code>: the default format, which evaluates the annotations and returns the resulting values.</li> <li><code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code>: for internal use; should be handled like <code class="docutils literal notranslate"><span class="pre">VALUE</span></code> by annotate functions that support execution with fake globals.</li> <li><code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code>: replaces undefined names with <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> objects.</li> <li><code class="docutils literal notranslate"><span class="pre">STRING</span></code>: returns strings, attempts to recreate code close to the original source.</li> </ul> </section> </section> <section id="miscellaneous-implementation-details"> <h2><a class="toc-backref" href="#miscellaneous-implementation-details" role="doc-backlink">Miscellaneous implementation details</a></h2> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> goes into considerable detail on some aspects of the implementation. To avoid confusion, we describe a few aspects where the current implementation differs from that described in the PEP. However, these details are not guaranteed to hold in the future, and they may change without notice in the future, unless they are documented in the language reference.</p> <section id="supported-operations-on-forwardref-objects"> <h3><a class="toc-backref" href="#supported-operations-on-forwardref-objects" role="doc-backlink">Supported operations on <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> objects</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> format is implemented by the “stringizer” technique, where the globals dictionary of a function is augmented so that every lookup results in a special object that can be used to reconstruct the operations that are performed on the object.</p> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> specifies:</p> <blockquote> <div>In practice, the “stringizer” functionality will be implemented in the <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> object currently defined in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module. <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> will be extended to implement all stringizer functionality; it will also be extended to support evaluating the string it contains, to produce the real value (assuming all symbols referenced are defined).</div></blockquote> <p>However, this is likely to lead to confusion in practice. An object that implements stringizer functionality must implement almost all special methods, including <code class="docutils literal notranslate"><span class="pre">__getattr__</span></code> and <code class="docutils literal notranslate"><span class="pre">__eq__</span></code>, to return a new stringizer. Such an object is confusing to work with: all operations succeed, but they are likely to return different objects than the user expects.</p> <p>The current implementation instead implements only a few useful methods on the <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> class. During the evaluation of annotations, an instance of a private stringizer class is used instead of <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code>. After evaluation completes, the implementation of the FORWARDREF format converts these internal objects into <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> objects.</p> </section> <section id="signature-of-annotate-functions"> <h3><a class="toc-backref" href="#signature-of-annotate-functions" role="doc-backlink">Signature of <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions</a></h3> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> specifies the signature of <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions as:</p> <blockquote> <div><code class="docutils literal notranslate"><span class="pre">__annotate__(format:</span> <span class="pre">int)</span> <span class="pre">-></span> <span class="pre">dict</span></code></div></blockquote> <p>However, using <code class="docutils literal notranslate"><span class="pre">format</span></code> as a parameter name could lead to collisions if an annotation uses a symbol named <code class="docutils literal notranslate"><span class="pre">format</span></code>. To avoid this problem, the current implementation uses a positional-only parameter that is named <code class="docutils literal notranslate"><span class="pre">format</span></code> in the function signature, but that does not shadow use of the name <code class="docutils literal notranslate"><span class="pre">format</span></code> within the annotation.</p> </section> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> provides a thorough discussion of the backwards compatibility implications on existing code that uses either stock or <a class="pep reference internal" href="../pep-0563/" title="PEP 563 – Postponed Evaluation of Annotations">PEP 563</a> semantics.</p> <p>However, there is another set of compatibility problems: new code that is written assuming <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> semantics, but uses existing tools that eagerly evaluate annotations. For example, consider a <code class="docutils literal notranslate"><span class="pre">dataclass</span></code>-like class decorator <code class="docutils literal notranslate"><span class="pre">@annotator</span></code> that retrieves the annotated fields in the class it decorates, either by accessing <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> directly or by calling <a class="reference external" href="https://docs.python.org/3/library/inspect.html#inspect.get_annotations" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">inspect.get_annotations()</span></code></a>.</p> <p>Once <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> is implemented, code like this will work fine:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">X</span><span class="p">:</span> <span class="n">y</span><span class="p">:</span> <span class="n">Y</span> <span class="k">class</span><span class="w"> </span><span class="nc">Y</span><span class="p">:</span> <span class="k">pass</span> </pre></div> </div> <p>But this will not, unless <code class="docutils literal notranslate"><span class="pre">@annotator</span></code> is changed to use the new <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code> format:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@annotator</span> <span class="k">class</span><span class="w"> </span><span class="nc">X</span><span class="p">:</span> <span class="n">y</span><span class="p">:</span> <span class="n">Y</span> <span class="k">class</span><span class="w"> </span><span class="nc">Y</span><span class="p">:</span> <span class="k">pass</span> </pre></div> </div> <p>This is not strictly a backwards compatibility issue, since no previously working code would break; before <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>, this code would have raised <code class="docutils literal notranslate"><span class="pre">NameError</span></code> at runtime. In a sense, it is no different from any other new Python feature that needs to be supported by third-party libraries. Nevertheless, it is a serious issue for libraries that perform introspection, and it is important that we make it as easy as possible for libraries to support the new semantics in a straightforward, user-friendly way.</p> <p>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 <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module, so third-party tools can use the same set of tools.</p> </section> <section id="security-implications"> <h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2> <p>None.</p> </section> <section id="how-to-teach-this"> <h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How to Teach This</a></h2> <p>The semantics of <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>, as modified by this PEP, should largely be intuitive for users who add annotations to their code. We eliminate the need for manually adding quotes around annotations that require forward references, a major source of confusion for users.</p> <p>For advanced users who need to introspect annotations, the story becomes more complex. The documentation of the new <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module will serve as a reference for users who need to interact programmatically with annotations.</p> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>The changes proposed in this PEP have been implemented on the main branch of the CPython repository.</p> </section> <section id="acknowledgments"> <h2><a class="toc-backref" href="#acknowledgments" role="doc-backlink">Acknowledgments</a></h2> <p>First of all, I thank Larry Hastings for writing <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>. This PEP modifies some of his initial decisions, but the overall design is still his.</p> <p>I thank Carl Meyer and Alex Waygood for feedback on early drafts of this PEP. Alex Waygood, Alyssa Coghlan, and David Ellis provided insightful feedback and suggestions on the interaction between metaclasses and <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>. Larry Hastings also provided useful feedback on this PEP. Nikita Sobolev made various changes to the standard library that make use of PEP 649 functionality, and his experience helped improve the design.</p> </section> <section id="appendix"> <h2><a class="toc-backref" href="#appendix" role="doc-backlink">Appendix</a></h2> <section id="which-expressions-can-be-stringified"> <h3><a class="toc-backref" href="#which-expressions-can-be-stringified" role="doc-backlink">Which expressions can be stringified?</a></h3> <p><a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> acknowledges that the stringifier cannot handle all expressions. Now that we have a draft implementation, we can be more precise about the expressions that can and cannot be handled. Below is a list of all expressions in the Python AST that can and cannot be recovered by the stringifier. The full list should probably not be added to the documentation, but creating it is a useful exercise.</p> <p>First, the stringifier of course cannot recover any information that is not present in the compiled code, including comments, whitespace, parenthesization, and operations that get simplified by the AST optimizer.</p> <p>Second, the stringifier can intercept almost all operations that involve names looked up in some scope, but it cannot intercept operations that operate fully on constants. As a corollary, this also means it is not safe to request the <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> format on untrusted code: Python is powerful enough that it is possible to achieve arbitrary code execution even with no access to any globals or builtins. For example:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">def</span><span class="w"> </span><span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="n">__base__</span><span class="o">.</span><span class="n">__subclasses__</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="fm">__init__</span><span class="o">.</span><span class="n">__builtins__</span><span class="p">[</span><span class="s2">"print"</span><span class="p">](</span><span class="s2">"Hello world"</span><span class="p">)):</span> <span class="k">pass</span> <span class="gp">...</span> <span class="gp">>>> </span><span class="n">annotationlib</span><span class="o">.</span><span class="n">get_annotations</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="n">annotationlib</span><span class="o">.</span><span class="n">Format</span><span class="o">.</span><span class="n">SOURCE</span><span class="p">)</span> <span class="go">Hello world</span> <span class="go">{'x': 'None'}</span> </pre></div> </div> <p>(This particular example worked for me on the current implementation of a draft of this PEP; the exact code may not keep working in the future.)</p> <p>The following are supported (sometimes with caveats):</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">BinOp</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">UnaryOp</span></code><ul> <li><code class="docutils literal notranslate"><span class="pre">Invert</span></code> (<code class="docutils literal notranslate"><span class="pre">~</span></code>), <code class="docutils literal notranslate"><span class="pre">UAdd</span></code> (<code class="docutils literal notranslate"><span class="pre">+</span></code>), and <code class="docutils literal notranslate"><span class="pre">USub</span></code> (<code class="docutils literal notranslate"><span class="pre">-</span></code>) are supported</li> <li><code class="docutils literal notranslate"><span class="pre">Not</span></code> (<code class="docutils literal notranslate"><span class="pre">not</span></code>) is not supported</li> </ul> </li> <li><code class="docutils literal notranslate"><span class="pre">Dict</span></code> (except when using <code class="docutils literal notranslate"><span class="pre">**</span></code> unpacking)</li> <li><code class="docutils literal notranslate"><span class="pre">Set</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">Compare</span></code><ul> <li><code class="docutils literal notranslate"><span class="pre">Eq</span></code> and <code class="docutils literal notranslate"><span class="pre">NotEq</span></code> are supported</li> <li><code class="docutils literal notranslate"><span class="pre">Lt</span></code>, <code class="docutils literal notranslate"><span class="pre">LtE</span></code>, <code class="docutils literal notranslate"><span class="pre">Gt</span></code>, and <code class="docutils literal notranslate"><span class="pre">GtE</span></code> are supported, but the operand may be flipped</li> <li><code class="docutils literal notranslate"><span class="pre">Is</span></code>, <code class="docutils literal notranslate"><span class="pre">IsNot</span></code>, <code class="docutils literal notranslate"><span class="pre">In</span></code>, and <code class="docutils literal notranslate"><span class="pre">NotIn</span></code> are not supported</li> </ul> </li> <li><code class="docutils literal notranslate"><span class="pre">Call</span></code> (except when using <code class="docutils literal notranslate"><span class="pre">**</span></code> unpacking)</li> <li><code class="docutils literal notranslate"><span class="pre">Constant</span></code> (though not the exact representation of the constant; for example, escape sequences in strings are lost; hexadecimal numbers are converted to decimal)</li> <li><code class="docutils literal notranslate"><span class="pre">Attribute</span></code> (assuming the value is not a constant)</li> <li><code class="docutils literal notranslate"><span class="pre">Subscript</span></code> (assuming the value is not a constant)</li> <li><code class="docutils literal notranslate"><span class="pre">Starred</span></code> (<code class="docutils literal notranslate"><span class="pre">*</span></code> unpacking)</li> <li><code class="docutils literal notranslate"><span class="pre">Name</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">List</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">Tuple</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">Slice</span></code></li> </ul> <p>The following are unsupported, but throw an informative error when encountered by the stringifier:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">FormattedValue</span></code> (f-strings; error is not detected if conversion specifiers like <code class="docutils literal notranslate"><span class="pre">!r</span></code> are used)</li> <li><code class="docutils literal notranslate"><span class="pre">JoinedStr</span></code> (f-strings)</li> </ul> <p>The following are unsupported and result in incorrect output:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">BoolOp</span></code> (<code class="docutils literal notranslate"><span class="pre">and</span></code> and <code class="docutils literal notranslate"><span class="pre">or</span></code>)</li> <li><code class="docutils literal notranslate"><span class="pre">IfExp</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">Lambda</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">ListComp</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">SetComp</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">DictComp</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">GeneratorExp</span></code></li> </ul> <p>The following are disallowed in annotation scopes and therefore not relevant:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">NamedExpr</span></code> (<code class="docutils literal notranslate"><span class="pre">:=</span></code>)</li> <li><code class="docutils literal notranslate"><span class="pre">Await</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">Yield</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">YieldFrom</span></code></li> </ul> </section> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0749.rst">https://github.com/python/peps/blob/main/peps/pep-0749.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0749.rst">2025-03-06 05:28:20 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#the-future-of-from-future-import-annotations">The future of <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">annotations</span></code></a><ul> <li><a class="reference internal" href="#specification">Specification</a></li> <li><a class="reference internal" href="#rejected-alternatives">Rejected alternatives</a></li> </ul> </li> <li><a class="reference internal" href="#new-annotationlib-module">New <code class="docutils literal notranslate"><span class="pre">annotationlib</span></code> module</a><ul> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#id1">Specification</a></li> <li><a class="reference internal" href="#id2">Rejected alternatives</a></li> </ul> </li> <li><a class="reference internal" href="#behavior-of-the-repl">Behavior of the REPL</a><ul> <li><a class="reference internal" href="#id3">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#wrappers-that-provide-annotations">Wrappers that provide <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a><ul> <li><a class="reference internal" href="#id4">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#annotations-and-metaclasses">Annotations and metaclasses</a><ul> <li><a class="reference internal" href="#pre-existing-bugs">Pre-existing bugs</a></li> <li><a class="reference internal" href="#metaclass-behavior-with-pep-649">Metaclass behavior with PEP 649</a></li> <li><a class="reference internal" href="#id5">Specification</a></li> <li><a class="reference internal" href="#id6">Rejected alternatives</a></li> </ul> </li> <li><a class="reference internal" href="#adding-the-value-with-fake-globals-format">Adding the <code class="docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code> format</a><ul> <li><a class="reference internal" href="#id7">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#effect-of-deleting-annotations">Effect of deleting <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a><ul> <li><a class="reference internal" href="#id8">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#deferred-evaluation-of-pep-695-and-696-objects">Deferred evaluation of PEP 695 and 696 objects</a><ul> <li><a class="reference internal" href="#id9">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#behavior-of-dataclass-field-types">Behavior of dataclass field types</a></li> <li><a class="reference internal" href="#renaming-source-to-string">Renaming <code class="docutils literal notranslate"><span class="pre">SOURCE</span></code> to <code class="docutils literal notranslate"><span class="pre">STRING</span></code></a><ul> <li><a class="reference internal" href="#id10">Specification</a></li> </ul> </li> <li><a class="reference internal" href="#miscellaneous-implementation-details">Miscellaneous implementation details</a><ul> <li><a class="reference internal" href="#supported-operations-on-forwardref-objects">Supported operations on <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> objects</a></li> <li><a class="reference internal" href="#signature-of-annotate-functions">Signature of <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> functions</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li> <li><a class="reference internal" href="#appendix">Appendix</a><ul> <li><a class="reference internal" href="#which-expressions-can-be-stringified">Which expressions can be stringified?</a></li> </ul> </li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0749.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>