Spaces:
Sleeping
Sleeping
| <html lang="en" data-content_root="../"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <meta property="og:title" content="annotationlib — Functionality for introspecting annotations" /> | |
| <meta property="og:type" content="website" /> | |
| <meta property="og:url" content="https://docs.python.org/3/library/annotationlib.html" /> | |
| <meta property="og:site_name" content="Python documentation" /> | |
| <meta property="og:description" content="Source code: Lib/annotationlib.py The annotationlib module provides tools for introspecting annotations on modules, classes, and functions. Annotations are lazily evaluated and often contain forwar..." /> | |
| <meta property="og:image:width" content="1146" /> | |
| <meta property="og:image:height" content="600" /> | |
| <meta property="og:image" content="https://docs.python.org/3.15/_images/social_previews/summary_library_annotationlib_f16fa90e.png" /> | |
| <meta property="og:image:alt" content="Source code: Lib/annotationlib.py The annotationlib module provides tools for introspecting annotations on modules, classes, and functions. Annotations are lazily evaluated and often contain forwar..." /> | |
| <meta name="description" content="Source code: Lib/annotationlib.py The annotationlib module provides tools for introspecting annotations on modules, classes, and functions. Annotations are lazily evaluated and often contain forwar..." /> | |
| <meta name="twitter:card" content="summary_large_image" /> | |
| <meta name="theme-color" content="#3776ab"> | |
| <title>annotationlib — Functionality for introspecting annotations — Python 3.15.0a6 documentation</title><meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" /> | |
| <link rel="stylesheet" type="text/css" href="../_static/classic.css?v=234b1a7c" /> | |
| <link rel="stylesheet" type="text/css" href="../_static/pydoctheme.css?v=89a2f22a" /> | |
| <link rel="stylesheet" type="text/css" href="../_static/profiling-sampling-visualization.css?v=0c2600ae" /> | |
| <link id="pygments_dark_css" media="(prefers-color-scheme: dark)" rel="stylesheet" type="text/css" href="../_static/pygments_dark.css?v=5349f25f" /> | |
| <script src="../_static/documentation_options.js?v=6b7c9ff5"></script> | |
| <script src="../_static/doctools.js?v=9bcbadda"></script> | |
| <script src="../_static/sphinx_highlight.js?v=dc90522c"></script> | |
| <script src="../_static/profiling-sampling-visualization.js?v=9811ed04"></script> | |
| <script src="../_static/sidebar.js"></script> | |
| <link rel="search" type="application/opensearchdescription+xml" | |
| title="Search within Python 3.15.0a6 documentation" | |
| href="../_static/opensearch.xml"/> | |
| <link rel="author" title="About these documents" href="../about.html" /> | |
| <link rel="index" title="Index" href="../genindex.html" /> | |
| <link rel="search" title="Search" href="../search.html" /> | |
| <link rel="copyright" title="Copyright" href="../copyright.html" /> | |
| <link rel="next" title="site — Site-specific configuration hook" href="site.html" /> | |
| <link rel="prev" title="inspect — Inspect live objects" href="inspect.html" /> | |
| <script defer file-types="bz2,epub,zip" data-domain="docs.python.org" src="https://analytics.python.org/js/script.file-downloads.outbound-links.js"></script> | |
| <link rel="canonical" href="https://docs.python.org/3/library/annotationlib.html"> | |
| <style> | |
| @media only screen { | |
| table.full-width-table { | |
| width: 100%; | |
| } | |
| } | |
| </style> | |
| <link rel="stylesheet" href="../_static/pydoctheme_dark.css" media="(prefers-color-scheme: dark)" id="pydoctheme_dark_css"> | |
| <link rel="shortcut icon" type="image/png" href="../_static/py.svg"> | |
| <script type="text/javascript" src="../_static/copybutton.js"></script> | |
| <script type="text/javascript" src="../_static/menu.js"></script> | |
| <script type="text/javascript" src="../_static/search-focus.js"></script> | |
| <script type="text/javascript" src="../_static/themetoggle.js"></script> | |
| <script type="text/javascript" src="../_static/rtd_switcher.js"></script> | |
| <meta name="readthedocs-addons-api-version" content="1"> | |
| </head> | |
| <body> | |
| <div class="mobile-nav"> | |
| <input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation" | |
| aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu"> | |
| <nav class="nav-content" role="navigation"> | |
| <label for="menuToggler" class="toggler__label"> | |
| <span></span> | |
| </label> | |
| <span class="nav-items-wrapper"> | |
| <a href="https://www.python.org/" class="nav-logo"> | |
| <img src="../_static/py.svg" alt="Python logo"> | |
| </a> | |
| <span class="version_switcher_placeholder"></span> | |
| <form role="search" class="search" action="../search.html" method="get"> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon"> | |
| <path fill-rule="nonzero" fill="currentColor" d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path> | |
| </svg> | |
| <input placeholder="Quick search" aria-label="Quick search" type="search" name="q"> | |
| <input type="submit" value="Go"> | |
| </form> | |
| </span> | |
| </nav> | |
| <div class="menu-wrapper"> | |
| <nav class="menu" role="navigation" aria-label="main navigation"> | |
| <div class="language_switcher_placeholder"></div> | |
| <label class="theme-selector-label"> | |
| Theme | |
| <select class="theme-selector" oninput="activateTheme(this.value)"> | |
| <option value="auto" selected>Auto</option> | |
| <option value="light">Light</option> | |
| <option value="dark">Dark</option> | |
| </select> | |
| </label> | |
| <div> | |
| <h3><a href="../contents.html">Table of Contents</a></h3> | |
| <ul> | |
| <li><a class="reference internal" href="#"><code class="xref py py-mod docutils literal notranslate"><span class="pre">annotationlib</span></code> — Functionality for introspecting annotations</a><ul> | |
| <li><a class="reference internal" href="#annotation-semantics">Annotation semantics</a></li> | |
| <li><a class="reference internal" href="#classes">Classes</a></li> | |
| <li><a class="reference internal" href="#functions">Functions</a></li> | |
| <li><a class="reference internal" href="#recipes">Recipes</a><ul> | |
| <li><a class="reference internal" href="#using-annotations-in-a-metaclass">Using annotations in a metaclass</a></li> | |
| </ul> | |
| </li> | |
| <li><a class="reference internal" href="#limitations-of-the-string-format">Limitations of the <code class="docutils literal notranslate"><span class="pre">STRING</span></code> format</a></li> | |
| <li><a class="reference internal" href="#limitations-of-the-forwardref-format">Limitations of the <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code> format</a></li> | |
| <li><a class="reference internal" href="#security-implications-of-introspecting-annotations">Security implications of introspecting annotations</a></li> | |
| </ul> | |
| </li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h4>Previous topic</h4> | |
| <p class="topless"><a href="inspect.html" | |
| title="previous chapter"><code class="xref py py-mod docutils literal notranslate"><span class="pre">inspect</span></code> — Inspect live objects</a></p> | |
| </div> | |
| <div> | |
| <h4>Next topic</h4> | |
| <p class="topless"><a href="site.html" | |
| title="next chapter"><code class="xref py py-mod docutils literal notranslate"><span class="pre">site</span></code> — Site-specific configuration hook</a></p> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const title = document.querySelector('meta[property="og:title"]').content; | |
| const elements = document.querySelectorAll('.improvepage'); | |
| const pageurl = window.location.href.split('?')[0]; | |
| elements.forEach(element => { | |
| const url = new URL(element.href.split('?')[0].replace("-nojs", "")); | |
| url.searchParams.set('pagetitle', title); | |
| url.searchParams.set('pageurl', pageurl); | |
| url.searchParams.set('pagesource', "library/annotationlib.rst"); | |
| element.href = url.toString(); | |
| }); | |
| }); | |
| </script> | |
| <div role="note" aria-label="source link"> | |
| <h3>This page</h3> | |
| <ul class="this-page-menu"> | |
| <li><a href="../bugs.html">Report a bug</a></li> | |
| <li><a class="improvepage" href="../improve-page-nojs.html">Improve this page</a></li> | |
| <li> | |
| <a href="https://github.com/python/cpython/blob/main/Doc/library/annotationlib.rst?plain=1" | |
| rel="nofollow">Show source | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| </nav> | |
| </div> | |
| </div> | |
| <div class="related" role="navigation" aria-label="Related"> | |
| <h3>Navigation</h3> | |
| <ul> | |
| <li class="right" style="margin-right: 10px"> | |
| <a href="../genindex.html" title="General Index" | |
| accesskey="I">index</a></li> | |
| <li class="right" > | |
| <a href="../py-modindex.html" title="Python Module Index" | |
| >modules</a> |</li> | |
| <li class="right" > | |
| <a href="site.html" title="site — Site-specific configuration hook" | |
| accesskey="N">next</a> |</li> | |
| <li class="right" > | |
| <a href="inspect.html" title="inspect — Inspect live objects" | |
| accesskey="P">previous</a> |</li> | |
| <li><img src="../_static/py.svg" alt="Python logo" style="vertical-align: middle; margin-top: -1px"></li> | |
| <li><a href="https://www.python.org/">Python</a> »</li> | |
| <li class="switchers"> | |
| <div class="language_switcher_placeholder"></div> | |
| <div class="version_switcher_placeholder"></div> | |
| </li> | |
| <li> | |
| </li> | |
| <li id="cpython-language-and-version"> | |
| <a href="../index.html">3.15.0a6 Documentation</a> » | |
| </li> | |
| <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li> | |
| <li class="nav-item nav-item-2"><a href="python.html" accesskey="U">Python Runtime Services</a> »</li> | |
| <li class="nav-item nav-item-this"><a href=""><code class="xref py py-mod docutils literal notranslate"><span class="pre">annotationlib</span></code> — Functionality for introspecting annotations</a></li> | |
| <li class="right"> | |
| <div class="inline-search" role="search"> | |
| <form class="inline-search" action="../search.html" method="get"> | |
| <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" id="search-box"> | |
| <input type="submit" value="Go"> | |
| </form> | |
| </div> | |
| | | |
| </li> | |
| <li class="right"> | |
| <label class="theme-selector-label"> | |
| Theme | |
| <select class="theme-selector" oninput="activateTheme(this.value)"> | |
| <option value="auto" selected>Auto</option> | |
| <option value="light">Light</option> | |
| <option value="dark">Dark</option> | |
| </select> | |
| </label> |</li> | |
| </ul> | |
| </div> | |
| <div class="document"> | |
| <div class="documentwrapper"> | |
| <div class="bodywrapper"> | |
| <div class="body" role="main"> | |
| <section id="module-annotationlib"> | |
| <span id="annotationlib-functionality-for-introspecting-annotations"></span><h1><code class="xref py py-mod docutils literal notranslate"><span class="pre">annotationlib</span></code> — Functionality for introspecting annotations<a class="headerlink" href="#module-annotationlib" title="Link to this heading">¶</a></h1> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| <p><strong>Source code:</strong> <a class="extlink-source reference external" href="https://github.com/python/cpython/tree/main/Lib/annotationlib.py">Lib/annotationlib.py</a></p> | |
| <hr class="docutils" /> | |
| <p>The <code class="xref py py-mod docutils literal notranslate"><span class="pre">annotationlib</span></code> module provides tools for introspecting | |
| <a class="reference internal" href="../glossary.html#term-annotation"><span class="xref std std-term">annotations</span></a> on modules, classes, and functions.</p> | |
| <p>Annotations are <a class="reference internal" href="../reference/executionmodel.html#lazy-evaluation"><span class="std std-ref">lazily evaluated</span></a> and often contain | |
| forward references to objects that are not yet defined when the annotation | |
| is created. This module provides a set of low-level tools that can be used to retrieve annotations in a reliable way, even | |
| in the presence of forward references and other edge cases.</p> | |
| <p>This module supports retrieving annotations in three main formats | |
| (see <a class="reference internal" href="#annotationlib.Format" title="annotationlib.Format"><code class="xref py py-class docutils literal notranslate"><span class="pre">Format</span></code></a>), each of which works best for different use cases:</p> | |
| <ul class="simple"> | |
| <li><p><a class="reference internal" href="#annotationlib.Format.VALUE" title="annotationlib.Format.VALUE"><code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE</span></code></a> evaluates the annotations and returns their value. | |
| This is most straightforward to work with, but it may raise errors, | |
| for example if the annotations contain references to undefined names.</p></li> | |
| <li><p><a class="reference internal" href="#annotationlib.Format.FORWARDREF" title="annotationlib.Format.FORWARDREF"><code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code></a> returns <a class="reference internal" href="#annotationlib.ForwardRef" title="annotationlib.ForwardRef"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code></a> objects | |
| for annotations that cannot be resolved, allowing you to inspect the | |
| annotations without evaluating them. This is useful when you need to | |
| work with annotations that may contain unresolved forward references.</p></li> | |
| <li><p><a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a> returns the annotations as a string, similar | |
| to how it would appear in the source file. This is useful for documentation | |
| generators that want to display annotations in a readable way.</p></li> | |
| </ul> | |
| <p>The <a class="reference internal" href="#annotationlib.get_annotations" title="annotationlib.get_annotations"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code></a> function is the main entry point for | |
| retrieving annotations. Given a function, class, or module, it returns | |
| an annotations dictionary in the requested format. This module also provides | |
| functionality for working directly with the <a class="reference internal" href="../glossary.html#term-annotate-function"><span class="xref std std-term">annotate function</span></a> | |
| that is used to evaluate annotations, such as <a class="reference internal" href="#annotationlib.get_annotate_from_class_namespace" title="annotationlib.get_annotate_from_class_namespace"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotate_from_class_namespace()</span></code></a> | |
| and <a class="reference internal" href="#annotationlib.call_annotate_function" title="annotationlib.call_annotate_function"><code class="xref py py-func docutils literal notranslate"><span class="pre">call_annotate_function()</span></code></a>, as well as the | |
| <a class="reference internal" href="#annotationlib.call_evaluate_function" title="annotationlib.call_evaluate_function"><code class="xref py py-func docutils literal notranslate"><span class="pre">call_evaluate_function()</span></code></a> function for working with | |
| <a class="reference internal" href="../glossary.html#term-evaluate-function"><span class="xref std std-term">evaluate functions</span></a>.</p> | |
| <div class="admonition caution"> | |
| <p class="admonition-title">Caution</p> | |
| <p>Most functionality in this module can execute arbitrary code; see | |
| <a class="reference internal" href="#annotationlib-security"><span class="std std-ref">the security section</span></a> for more information.</p> | |
| </div> | |
| <div class="admonition seealso"> | |
| <p class="admonition-title">See also</p> | |
| <p><span class="target" id="index-0"></span><a class="pep reference external" href="https://peps.python.org/pep-0649/"><strong>PEP 649</strong></a> proposed the current model for how annotations work in Python.</p> | |
| <p><span class="target" id="index-1"></span><a class="pep reference external" href="https://peps.python.org/pep-0749/"><strong>PEP 749</strong></a> expanded on various aspects of <span class="target" id="index-2"></span><a class="pep reference external" href="https://peps.python.org/pep-0649/"><strong>PEP 649</strong></a> and introduced the | |
| <code class="xref py py-mod docutils literal notranslate"><span class="pre">annotationlib</span></code> module.</p> | |
| <p><a class="reference internal" href="../howto/annotations.html#annotations-howto"><span class="std std-ref">Annotations Best Practices</span></a> provides best practices for working with | |
| annotations.</p> | |
| <p><a class="extlink-pypi reference external" href="https://pypi.org/project/typing-extensions/">typing-extensions</a> provides a backport of <a class="reference internal" href="#annotationlib.get_annotations" title="annotationlib.get_annotations"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code></a> | |
| that works on earlier versions of Python.</p> | |
| </div> | |
| <section id="annotation-semantics"> | |
| <h2>Annotation semantics<a class="headerlink" href="#annotation-semantics" title="Link to this heading">¶</a></h2> | |
| <p>The way annotations are evaluated has changed over the history of Python 3, | |
| and currently still depends on a <a class="reference internal" href="../reference/simple_stmts.html#future"><span class="std std-ref">future import</span></a>. | |
| There have been execution models for annotations:</p> | |
| <ul class="simple"> | |
| <li><p><em>Stock semantics</em> (default in Python 3.0 through 3.13; see <span class="target" id="index-3"></span><a class="pep reference external" href="https://peps.python.org/pep-3107/"><strong>PEP 3107</strong></a> | |
| and <span class="target" id="index-4"></span><a class="pep reference external" href="https://peps.python.org/pep-0526/"><strong>PEP 526</strong></a>): Annotations are evaluated eagerly, as they are | |
| encountered in the source code.</p></li> | |
| <li><p><em>Stringified annotations</em> (used with <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 Python 3.7 and newer; see <span class="target" id="index-5"></span><a class="pep reference external" href="https://peps.python.org/pep-0563/"><strong>PEP 563</strong></a>): Annotations are stored as | |
| strings only.</p></li> | |
| <li><p><em>Deferred evaluation</em> (default in Python 3.14 and newer; see <span class="target" id="index-6"></span><a class="pep reference external" href="https://peps.python.org/pep-0649/"><strong>PEP 649</strong></a> and | |
| <span class="target" id="index-7"></span><a class="pep reference external" href="https://peps.python.org/pep-0749/"><strong>PEP 749</strong></a>): Annotations are evaluated lazily, only when they are accessed.</p></li> | |
| </ul> | |
| <p>As an example, consider the following program:</p> | |
| <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">func</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">Cls</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> | |
| <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> | |
| <span class="k">class</span><span class="w"> </span><span class="nc">Cls</span><span class="p">:</span> <span class="k">pass</span> | |
| <span class="nb">print</span><span class="p">(</span><span class="n">func</span><span class="o">.</span><span class="vm">__annotations__</span><span class="p">)</span> | |
| </pre></div> | |
| </div> | |
| <p>This will behave as follows:</p> | |
| <ul class="simple"> | |
| <li><p>Under stock semantics (Python 3.13 and earlier), it will throw a | |
| <a class="reference internal" href="exceptions.html#NameError" title="NameError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">NameError</span></code></a> at the line where <code class="docutils literal notranslate"><span class="pre">func</span></code> is defined, | |
| because <code class="docutils literal notranslate"><span class="pre">Cls</span></code> is an undefined name at that point.</p></li> | |
| <li><p>Under stringified annotations (if <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 used), it will print <code class="docutils literal notranslate"><span class="pre">{'a':</span> <span class="pre">'Cls',</span> <span class="pre">'return':</span> <span class="pre">'None'}</span></code>.</p></li> | |
| <li><p>Under deferred evaluation (Python 3.14 and later), it will print | |
| <code class="docutils literal notranslate"><span class="pre">{'a':</span> <span class="pre"><class</span> <span class="pre">'Cls'>,</span> <span class="pre">'return':</span> <span class="pre">None}</span></code>.</p></li> | |
| </ul> | |
| <p>Stock semantics were used when function annotations were first introduced | |
| in Python 3.0 (by <span class="target" id="index-8"></span><a class="pep reference external" href="https://peps.python.org/pep-3107/"><strong>PEP 3107</strong></a>) because this was the simplest, most obvious | |
| way to implement annotations. The same execution model was used when variable | |
| annotations were introduced in Python 3.6 (by <span class="target" id="index-9"></span><a class="pep reference external" href="https://peps.python.org/pep-0526/"><strong>PEP 526</strong></a>). However, | |
| stock semantics caused problems when using annotations as type hints, | |
| such as a need to refer to names that are not yet defined when the | |
| annotation is encountered. In addition, there were performance problems | |
| with executing annotations at module import time. Therefore, in Python 3.7, | |
| <span class="target" id="index-10"></span><a class="pep reference external" href="https://peps.python.org/pep-0563/"><strong>PEP 563</strong></a> introduced the ability to store annotations as strings using the | |
| <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> syntax. The plan at the time was to | |
| eventually make this behavior the default, but a problem appeared: | |
| stringified annotations are more difficult to process for those who | |
| introspect annotations at runtime. An alternative proposal, <span class="target" id="index-11"></span><a class="pep reference external" href="https://peps.python.org/pep-0649/"><strong>PEP 649</strong></a>, | |
| introduced the third execution model, deferred evaluation, and was implemented | |
| in Python 3.14. Stringified annotations are still used if | |
| <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 present, but this behavior will | |
| eventually be removed.</p> | |
| </section> | |
| <section id="classes"> | |
| <h2>Classes<a class="headerlink" href="#classes" title="Link to this heading">¶</a></h2> | |
| <dl class="py class"> | |
| <dt class="sig sig-object py" id="annotationlib.Format"> | |
| <em class="property"><span class="k"><span class="pre">class</span></span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">annotationlib.</span></span><span class="sig-name descname"><span class="pre">Format</span></span><a class="headerlink" href="#annotationlib.Format" title="Link to this definition">¶</a></dt> | |
| <dd><p>An <a class="reference internal" href="enum.html#enum.IntEnum" title="enum.IntEnum"><code class="xref py py-class docutils literal notranslate"><span class="pre">IntEnum</span></code></a> describing the formats in which annotations | |
| can be returned. Members of the enum, or their equivalent integer values, | |
| can be passed to <a class="reference internal" href="#annotationlib.get_annotations" title="annotationlib.get_annotations"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code></a> and other functions in this | |
| module, as well as to <a class="reference internal" href="../reference/datamodel.html#object.__annotate__" title="object.__annotate__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__annotate__</span></code></a> functions.</p> | |
| <dl class="py attribute"> | |
| <dt class="sig sig-object py" id="annotationlib.Format.VALUE"> | |
| <span class="sig-name descname"><span class="pre">VALUE</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">1</span></em><a class="headerlink" href="#annotationlib.Format.VALUE" title="Link to this definition">¶</a></dt> | |
| <dd><p>Values are the result of evaluating the annotation expressions.</p> | |
| </dd></dl> | |
| <dl class="py attribute"> | |
| <dt class="sig sig-object py" id="annotationlib.Format.VALUE_WITH_FAKE_GLOBALS"> | |
| <span class="sig-name descname"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">2</span></em><a class="headerlink" href="#annotationlib.Format.VALUE_WITH_FAKE_GLOBALS" title="Link to this definition">¶</a></dt> | |
| <dd><p>Special value used to signal that an annotate function is being | |
| evaluated in a special environment with fake globals. When passed this | |
| value, annotate functions should either return the same value as for | |
| the <a class="reference internal" href="#annotationlib.Format.VALUE" title="annotationlib.Format.VALUE"><code class="xref py py-attr docutils literal notranslate"><span class="pre">Format.VALUE</span></code></a> format, or raise <a class="reference internal" href="exceptions.html#NotImplementedError" title="NotImplementedError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">NotImplementedError</span></code></a> | |
| to signal that they do not support execution in this environment. | |
| This format is only used internally and should not be passed to | |
| the functions in this module.</p> | |
| </dd></dl> | |
| <dl class="py attribute"> | |
| <dt class="sig sig-object py" id="annotationlib.Format.FORWARDREF"> | |
| <span class="sig-name descname"><span class="pre">FORWARDREF</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">3</span></em><a class="headerlink" href="#annotationlib.Format.FORWARDREF" title="Link to this definition">¶</a></dt> | |
| <dd><p>Values are real annotation values (as per <a class="reference internal" href="#annotationlib.Format.VALUE" title="annotationlib.Format.VALUE"><code class="xref py py-attr docutils literal notranslate"><span class="pre">Format.VALUE</span></code></a> format) | |
| for defined values, and <a class="reference internal" href="#annotationlib.ForwardRef" title="annotationlib.ForwardRef"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code></a> proxies for undefined | |
| values. Real objects may contain references to <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> | |
| proxy objects.</p> | |
| </dd></dl> | |
| <dl class="py attribute"> | |
| <dt class="sig sig-object py" id="annotationlib.Format.STRING"> | |
| <span class="sig-name descname"><span class="pre">STRING</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">4</span></em><a class="headerlink" href="#annotationlib.Format.STRING" title="Link to this definition">¶</a></dt> | |
| <dd><p>Values are the text string of the annotation as it appears in the | |
| source code, up to modifications including, but not restricted to, | |
| whitespace normalizations and constant values optimizations.</p> | |
| <p>The exact values of these strings may change in future versions of Python.</p> | |
| </dd></dl> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| </dd></dl> | |
| <dl class="py class"> | |
| <dt class="sig sig-object py" id="annotationlib.ForwardRef"> | |
| <em class="property"><span class="k"><span class="pre">class</span></span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">annotationlib.</span></span><span class="sig-name descname"><span class="pre">ForwardRef</span></span><a class="headerlink" href="#annotationlib.ForwardRef" title="Link to this definition">¶</a></dt> | |
| <dd><p>A proxy object for forward references in annotations.</p> | |
| <p>Instances of this class are returned when the <a class="reference internal" href="#annotationlib.Format.FORWARDREF" title="annotationlib.Format.FORWARDREF"><code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code></a> | |
| format is used and annotations contain a name that cannot be resolved. | |
| This can happen when a forward reference is used in an annotation, such as | |
| when a class is referenced before it is defined.</p> | |
| <dl class="py attribute"> | |
| <dt class="sig sig-object py" id="annotationlib.ForwardRef.__forward_arg__"> | |
| <span class="sig-name descname"><span class="pre">__forward_arg__</span></span><a class="headerlink" href="#annotationlib.ForwardRef.__forward_arg__" title="Link to this definition">¶</a></dt> | |
| <dd><p>A string containing the code that was evaluated to produce the | |
| <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code>. The string may not be exactly equivalent | |
| to the original source.</p> | |
| </dd></dl> | |
| <dl class="py method"> | |
| <dt class="sig sig-object py" id="annotationlib.ForwardRef.evaluate"> | |
| <span class="sig-name descname"><span class="pre">evaluate</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="keyword-only-separator o"><abbr title="Keyword-only parameters separator (PEP 3102)"><span class="pre">*</span></abbr></span></em>, <em class="sig-param"><span class="n"><span class="pre">owner</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">globals</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">locals</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">type_params</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">format</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">Format.VALUE</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#annotationlib.ForwardRef.evaluate" title="Link to this definition">¶</a></dt> | |
| <dd><p>Evaluate the forward reference, returning its value.</p> | |
| <p>If the <em>format</em> argument is <a class="reference internal" href="#annotationlib.Format.VALUE" title="annotationlib.Format.VALUE"><code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE</span></code></a> (the default), | |
| this method may throw an exception, such as <a class="reference internal" href="exceptions.html#NameError" title="NameError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">NameError</span></code></a>, if the forward | |
| reference refers to a name that cannot be resolved. The arguments to this | |
| method can be used to provide bindings for names that would otherwise | |
| be undefined. If the <em>format</em> argument is <a class="reference internal" href="#annotationlib.Format.FORWARDREF" title="annotationlib.Format.FORWARDREF"><code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code></a>, | |
| the method will never throw an exception, but may return a <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> | |
| instance. For example, if the forward reference object contains the code | |
| <code class="docutils literal notranslate"><span class="pre">list[undefined]</span></code>, where <code class="docutils literal notranslate"><span class="pre">undefined</span></code> is a name that is not defined, | |
| evaluating it with the <code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code> format will return | |
| <code class="docutils literal notranslate"><span class="pre">list[ForwardRef('undefined')]</span></code>. If the <em>format</em> argument is | |
| <a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a>, the method will return <a class="reference internal" href="#annotationlib.ForwardRef.__forward_arg__" title="annotationlib.ForwardRef.__forward_arg__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__forward_arg__</span></code></a>.</p> | |
| <p>The <em>owner</em> parameter provides the preferred mechanism for passing scope | |
| information to this method. The owner of a <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> is the | |
| object that contains the annotation from which the <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> | |
| derives, such as a module object, type object, or function object.</p> | |
| <p>The <em>globals</em>, <em>locals</em>, and <em>type_params</em> parameters provide a more precise | |
| mechanism for influencing the names that are available when the <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> | |
| is evaluated. <em>globals</em> and <em>locals</em> are passed to <a class="reference internal" href="functions.html#eval" title="eval"><code class="xref py py-func docutils literal notranslate"><span class="pre">eval()</span></code></a>, representing | |
| the global and local namespaces in which the name is evaluated. | |
| The <em>type_params</em> parameter is relevant for objects created using the native | |
| syntax for <a class="reference internal" href="../reference/compound_stmts.html#generic-classes"><span class="std std-ref">generic classes</span></a> and <a class="reference internal" href="../reference/compound_stmts.html#generic-functions"><span class="std std-ref">functions</span></a>. | |
| It is a tuple of <a class="reference internal" href="../reference/compound_stmts.html#type-params"><span class="std std-ref">type parameters</span></a> that are in scope | |
| while the forward reference is being evaluated. For example, if evaluating a | |
| <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> retrieved from an annotation found in the class namespace | |
| of a generic class <code class="docutils literal notranslate"><span class="pre">C</span></code>, <em>type_params</em> should be set to <code class="docutils literal notranslate"><span class="pre">C.__type_params__</span></code>.</p> | |
| <p><code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> instances returned by <a class="reference internal" href="#annotationlib.get_annotations" title="annotationlib.get_annotations"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code></a> | |
| retain references to information about the scope they originated from, | |
| so calling this method with no further arguments may be sufficient to | |
| evaluate such objects. <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> instances created by other | |
| means may not have any information about their scope, so passing | |
| arguments to this method may be necessary to evaluate them successfully.</p> | |
| <p>If no <em>owner</em>, <em>globals</em>, <em>locals</em>, or <em>type_params</em> are provided and the | |
| <code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code> does not contain information about its origin, | |
| empty globals and locals dictionaries are used.</p> | |
| </dd></dl> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| </dd></dl> | |
| </section> | |
| <section id="functions"> | |
| <h2>Functions<a class="headerlink" href="#functions" title="Link to this heading">¶</a></h2> | |
| <dl class="py function"> | |
| <dt class="sig sig-object py" id="annotationlib.annotations_to_string"> | |
| <span class="sig-prename descclassname"><span class="pre">annotationlib.</span></span><span class="sig-name descname"><span class="pre">annotations_to_string</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">annotations</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#annotationlib.annotations_to_string" title="Link to this definition">¶</a></dt> | |
| <dd><p>Convert an annotations dict containing runtime values to a | |
| dict containing only strings. If the values are not already strings, | |
| they are converted using <a class="reference internal" href="#annotationlib.type_repr" title="annotationlib.type_repr"><code class="xref py py-func docutils literal notranslate"><span class="pre">type_repr()</span></code></a>. | |
| This is meant as a helper for user-provided | |
| annotate functions that support the <a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a> format but | |
| do not have access to the code creating the annotations.</p> | |
| <p>For example, this is used to implement the <a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a> for | |
| <a class="reference internal" href="typing.html#typing.TypedDict" title="typing.TypedDict"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypedDict</span></code></a> classes created through the functional syntax:</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">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">TypedDict</span> | |
| <span class="gp">>>> </span><span class="n">Movie</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">(</span><span class="s2">"movie"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="s2">"year"</span><span class="p">:</span> <span class="nb">int</span><span class="p">})</span> | |
| <span class="gp">>>> </span><span class="n">get_annotations</span><span class="p">(</span><span class="n">Movie</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="n">Format</span><span class="o">.</span><span class="n">STRING</span><span class="p">)</span> | |
| <span class="go">{'name': 'str', 'year': 'int'}</span> | |
| </pre></div> | |
| </div> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| </dd></dl> | |
| <dl class="py function"> | |
| <dt class="sig sig-object py" id="annotationlib.call_annotate_function"> | |
| <span class="sig-prename descclassname"><span class="pre">annotationlib.</span></span><span class="sig-name descname"><span class="pre">call_annotate_function</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">annotate</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">format</span></span></em>, <em class="sig-param"><span class="keyword-only-separator o"><abbr title="Keyword-only parameters separator (PEP 3102)"><span class="pre">*</span></abbr></span></em>, <em class="sig-param"><span class="n"><span class="pre">owner</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#annotationlib.call_annotate_function" title="Link to this definition">¶</a></dt> | |
| <dd><p>Call the <a class="reference internal" href="../glossary.html#term-annotate-function"><span class="xref std std-term">annotate function</span></a> <em>annotate</em> with the given <em>format</em>, | |
| a member of the <a class="reference internal" href="#annotationlib.Format" title="annotationlib.Format"><code class="xref py py-class docutils literal notranslate"><span class="pre">Format</span></code></a> enum, and return the annotations | |
| dictionary produced by the function.</p> | |
| <p>This helper function is required because annotate functions generated by | |
| the compiler for functions, classes, and modules only support | |
| the <a class="reference internal" href="#annotationlib.Format.VALUE" title="annotationlib.Format.VALUE"><code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE</span></code></a> format when called directly. | |
| To support other formats, this function calls the annotate function | |
| in a special environment that allows it to produce annotations in the | |
| other formats. This is a useful building block when implementing | |
| functionality that needs to partially evaluate annotations while a class | |
| is being constructed.</p> | |
| <p><em>owner</em> is the object that owns the annotation function, usually | |
| a function, class, or module. If provided, it is used in the | |
| <a class="reference internal" href="#annotationlib.Format.FORWARDREF" title="annotationlib.Format.FORWARDREF"><code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code></a> format to produce a <a class="reference internal" href="#annotationlib.ForwardRef" title="annotationlib.ForwardRef"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code></a> | |
| object that carries more information.</p> | |
| <div class="admonition seealso"> | |
| <p class="admonition-title">See also</p> | |
| <p><span class="target" id="index-12"></span><a class="pep reference external" href="https://peps.python.org/pep-0649/#the-stringizer-and-the-fake-globals-environment"><strong>PEP 649</strong></a> | |
| contains an explanation of the implementation technique used by this | |
| function.</p> | |
| </div> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| </dd></dl> | |
| <dl class="py function"> | |
| <dt class="sig sig-object py" id="annotationlib.call_evaluate_function"> | |
| <span class="sig-prename descclassname"><span class="pre">annotationlib.</span></span><span class="sig-name descname"><span class="pre">call_evaluate_function</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">evaluate</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">format</span></span></em>, <em class="sig-param"><span class="keyword-only-separator o"><abbr title="Keyword-only parameters separator (PEP 3102)"><span class="pre">*</span></abbr></span></em>, <em class="sig-param"><span class="n"><span class="pre">owner</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#annotationlib.call_evaluate_function" title="Link to this definition">¶</a></dt> | |
| <dd><p>Call the <a class="reference internal" href="../glossary.html#term-evaluate-function"><span class="xref std std-term">evaluate function</span></a> <em>evaluate</em> with the given <em>format</em>, | |
| a member of the <a class="reference internal" href="#annotationlib.Format" title="annotationlib.Format"><code class="xref py py-class docutils literal notranslate"><span class="pre">Format</span></code></a> enum, and return the value produced by | |
| the function. This is similar to <a class="reference internal" href="#annotationlib.call_annotate_function" title="annotationlib.call_annotate_function"><code class="xref py py-func docutils literal notranslate"><span class="pre">call_annotate_function()</span></code></a>, | |
| but the latter always returns a dictionary mapping strings to annotations, | |
| while this function returns a single value.</p> | |
| <p>This is intended for use with the evaluate functions generated for lazily | |
| evaluated elements related to type aliases and type parameters:</p> | |
| <ul class="simple"> | |
| <li><p><a class="reference internal" href="typing.html#typing.TypeAliasType.evaluate_value" title="typing.TypeAliasType.evaluate_value"><code class="xref py py-meth docutils literal notranslate"><span class="pre">typing.TypeAliasType.evaluate_value()</span></code></a>, the value of type aliases</p></li> | |
| <li><p><a class="reference internal" href="typing.html#typing.TypeVar.evaluate_bound" title="typing.TypeVar.evaluate_bound"><code class="xref py py-meth docutils literal notranslate"><span class="pre">typing.TypeVar.evaluate_bound()</span></code></a>, the bound of type variables</p></li> | |
| <li><p><a class="reference internal" href="typing.html#typing.TypeVar.evaluate_constraints" title="typing.TypeVar.evaluate_constraints"><code class="xref py py-meth docutils literal notranslate"><span class="pre">typing.TypeVar.evaluate_constraints()</span></code></a>, the constraints of | |
| type variables</p></li> | |
| <li><p><a class="reference internal" href="typing.html#typing.TypeVar.evaluate_default" title="typing.TypeVar.evaluate_default"><code class="xref py py-meth docutils literal notranslate"><span class="pre">typing.TypeVar.evaluate_default()</span></code></a>, the default value of | |
| type variables</p></li> | |
| <li><p><a class="reference internal" href="typing.html#typing.ParamSpec.evaluate_default" title="typing.ParamSpec.evaluate_default"><code class="xref py py-meth docutils literal notranslate"><span class="pre">typing.ParamSpec.evaluate_default()</span></code></a>, the default value of | |
| parameter specifications</p></li> | |
| <li><p><a class="reference internal" href="typing.html#typing.TypeVarTuple.evaluate_default" title="typing.TypeVarTuple.evaluate_default"><code class="xref py py-meth docutils literal notranslate"><span class="pre">typing.TypeVarTuple.evaluate_default()</span></code></a>, the default value of | |
| type variable tuples</p></li> | |
| </ul> | |
| <p><em>owner</em> is the object that owns the evaluate function, such as the type | |
| alias or type variable object.</p> | |
| <p><em>format</em> can be used to control the format in which the value is returned:</p> | |
| <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">type</span> <span class="n">Alias</span> <span class="o">=</span> <span class="n">undefined</span> | |
| <span class="gp">>>> </span><span class="n">call_evaluate_function</span><span class="p">(</span><span class="n">Alias</span><span class="o">.</span><span class="n">evaluate_value</span><span class="p">,</span> <span class="n">Format</span><span class="o">.</span><span class="n">VALUE</span><span class="p">)</span> | |
| <span class="gt">Traceback (most recent call last):</span> | |
| <span class="c">...</span> | |
| <span class="gr">NameError</span>: <span class="n">name 'undefined' is not defined</span> | |
| <span class="gp">>>> </span><span class="n">call_evaluate_function</span><span class="p">(</span><span class="n">Alias</span><span class="o">.</span><span class="n">evaluate_value</span><span class="p">,</span> <span class="n">Format</span><span class="o">.</span><span class="n">FORWARDREF</span><span class="p">)</span> | |
| <span class="go">ForwardRef('undefined')</span> | |
| <span class="gp">>>> </span><span class="n">call_evaluate_function</span><span class="p">(</span><span class="n">Alias</span><span class="o">.</span><span class="n">evaluate_value</span><span class="p">,</span> <span class="n">Format</span><span class="o">.</span><span class="n">STRING</span><span class="p">)</span> | |
| <span class="go">'undefined'</span> | |
| </pre></div> | |
| </div> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| </dd></dl> | |
| <dl class="py function"> | |
| <dt class="sig sig-object py" id="annotationlib.get_annotate_from_class_namespace"> | |
| <span class="sig-prename descclassname"><span class="pre">annotationlib.</span></span><span class="sig-name descname"><span class="pre">get_annotate_from_class_namespace</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">namespace</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#annotationlib.get_annotate_from_class_namespace" title="Link to this definition">¶</a></dt> | |
| <dd><p>Retrieve the <a class="reference internal" href="../glossary.html#term-annotate-function"><span class="xref std std-term">annotate function</span></a> from a class namespace dictionary <em>namespace</em>. | |
| Return <code class="xref py py-const docutils literal notranslate"><span class="pre">None</span></code> if the namespace does not contain an annotate function. | |
| This is primarily useful before the class has been fully created (e.g., in a metaclass); | |
| after the class exists, the annotate function can be retrieved with <code class="docutils literal notranslate"><span class="pre">cls.__annotate__</span></code>. | |
| See <a class="reference internal" href="#annotationlib-metaclass"><span class="std std-ref">below</span></a> for an example using this function in a metaclass.</p> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| </dd></dl> | |
| <dl class="py function"> | |
| <dt class="sig sig-object py" id="annotationlib.get_annotations"> | |
| <span class="sig-prename descclassname"><span class="pre">annotationlib.</span></span><span class="sig-name descname"><span class="pre">get_annotations</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">obj</span></span></em>, <em class="sig-param"><span class="keyword-only-separator o"><abbr title="Keyword-only parameters separator (PEP 3102)"><span class="pre">*</span></abbr></span></em>, <em class="sig-param"><span class="n"><span class="pre">globals</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">locals</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">eval_str</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">format</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">Format.VALUE</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#annotationlib.get_annotations" title="Link to this definition">¶</a></dt> | |
| <dd><p>Compute the annotations dict for an object.</p> | |
| <p><em>obj</em> may be a callable, class, module, or other object with | |
| <a class="reference internal" href="../reference/datamodel.html#object.__annotate__" title="object.__annotate__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__annotate__</span></code></a> or <a class="reference internal" href="../reference/datamodel.html#object.__annotations__" title="object.__annotations__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__annotations__</span></code></a> attributes. | |
| Passing any other object raises <a class="reference internal" href="exceptions.html#TypeError" title="TypeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">TypeError</span></code></a>.</p> | |
| <p>The <em>format</em> parameter controls the format in which annotations are returned, | |
| and must be a member of the <a class="reference internal" href="#annotationlib.Format" title="annotationlib.Format"><code class="xref py py-class docutils literal notranslate"><span class="pre">Format</span></code></a> enum or its integer equivalent. | |
| The different formats work as follows:</p> | |
| <ul class="simple"> | |
| <li><p>VALUE: <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotations__</span></code> is tried first; if that does not exist, | |
| the <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotate__</span></code> function is called if it exists.</p></li> | |
| <li><p>FORWARDREF: If <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotations__</span></code> exists and can be evaluated successfully, | |
| it is used; otherwise, the <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotate__</span></code> function is called. If it | |
| does not exist either, <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotations__</span></code> is tried again and any error | |
| from accessing it is re-raised.</p> | |
| <ul> | |
| <li><p>When calling <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotate__</span></code> it is first called with <a class="reference internal" href="#annotationlib.Format.FORWARDREF" title="annotationlib.Format.FORWARDREF"><code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code></a>. | |
| If this is not implemented, it will then check if <a class="reference internal" href="#annotationlib.Format.VALUE_WITH_FAKE_GLOBALS" title="annotationlib.Format.VALUE_WITH_FAKE_GLOBALS"><code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code></a> | |
| is supported and use that in the fake globals environment. | |
| If neither of these formats are supported, it will fall back to using <a class="reference internal" href="#annotationlib.Format.VALUE" title="annotationlib.Format.VALUE"><code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE</span></code></a>. | |
| If <code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE</span></code> fails, the error from this call will be raised.</p></li> | |
| </ul> | |
| </li> | |
| <li><p>STRING: If <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotate__</span></code> exists, it is called first; | |
| otherwise, <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotations__</span></code> is used and stringified | |
| using <a class="reference internal" href="#annotationlib.annotations_to_string" title="annotationlib.annotations_to_string"><code class="xref py py-func docutils literal notranslate"><span class="pre">annotations_to_string()</span></code></a>.</p> | |
| <ul> | |
| <li><p>When calling <code class="xref py py-attr docutils literal notranslate"><span class="pre">object.__annotate__</span></code> it is first called with <a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a>. | |
| If this is not implemented, it will then check if <a class="reference internal" href="#annotationlib.Format.VALUE_WITH_FAKE_GLOBALS" title="annotationlib.Format.VALUE_WITH_FAKE_GLOBALS"><code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE_WITH_FAKE_GLOBALS</span></code></a> | |
| is supported and use that in the fake globals environment. | |
| If neither of these formats are supported, it will fall back to using <a class="reference internal" href="#annotationlib.Format.VALUE" title="annotationlib.Format.VALUE"><code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE</span></code></a> | |
| with the result converted using <a class="reference internal" href="#annotationlib.annotations_to_string" title="annotationlib.annotations_to_string"><code class="xref py py-func docutils literal notranslate"><span class="pre">annotations_to_string()</span></code></a>. | |
| If <code class="xref py py-attr docutils literal notranslate"><span class="pre">VALUE</span></code> fails, the error from this call will be raised.</p></li> | |
| </ul> | |
| </li> | |
| </ul> | |
| <p>Returns a dict. <code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code> returns a new dict every time | |
| it’s called; calling it twice on the same object will return two | |
| different but equivalent dicts.</p> | |
| <p>This function handles several details for you:</p> | |
| <ul class="simple"> | |
| <li><p>If <em>eval_str</em> is true, values of type <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code> will | |
| be un-stringized using <a class="reference internal" href="functions.html#eval" title="eval"><code class="xref py py-func docutils literal notranslate"><span class="pre">eval()</span></code></a>. This is intended | |
| for use with stringized annotations | |
| (<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>). It is an error | |
| to set <em>eval_str</em> to true with formats other than <a class="reference internal" href="#annotationlib.Format.VALUE" title="annotationlib.Format.VALUE"><code class="xref py py-attr docutils literal notranslate"><span class="pre">Format.VALUE</span></code></a>.</p></li> | |
| <li><p>If <em>obj</em> doesn’t have an annotations dict, returns an | |
| empty dict. (Functions and methods always have an | |
| annotations dict; classes, modules, and other types of | |
| callables may not.)</p></li> | |
| <li><p>Ignores inherited annotations on classes, as well as annotations | |
| on metaclasses. If a class | |
| doesn’t have its own annotations dict, returns an empty dict.</p></li> | |
| <li><p>All accesses to object members and dict values are done | |
| using <code class="docutils literal notranslate"><span class="pre">getattr()</span></code> and <code class="docutils literal notranslate"><span class="pre">dict.get()</span></code> for safety.</p></li> | |
| </ul> | |
| <p><em>eval_str</em> controls whether or not values of type <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code> are | |
| replaced with the result of calling <a class="reference internal" href="functions.html#eval" title="eval"><code class="xref py py-func docutils literal notranslate"><span class="pre">eval()</span></code></a> on those values:</p> | |
| <ul class="simple"> | |
| <li><p>If eval_str is true, <a class="reference internal" href="functions.html#eval" title="eval"><code class="xref py py-func docutils literal notranslate"><span class="pre">eval()</span></code></a> is called on values of type | |
| <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code>. (Note that <code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code> doesn’t catch | |
| exceptions; if <code class="xref py py-func docutils literal notranslate"><span class="pre">eval()</span></code> raises an exception, it will unwind | |
| the stack past the <code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code> call.)</p></li> | |
| <li><p>If <em>eval_str</em> is false (the default), values of type <code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code> are | |
| unchanged.</p></li> | |
| </ul> | |
| <p><em>globals</em> and <em>locals</em> are passed in to <a class="reference internal" href="functions.html#eval" title="eval"><code class="xref py py-func docutils literal notranslate"><span class="pre">eval()</span></code></a>; see the documentation | |
| for <code class="xref py py-func docutils literal notranslate"><span class="pre">eval()</span></code> for more information. If <em>globals</em> or <em>locals</em> | |
| is <code class="xref py py-const docutils literal notranslate"><span class="pre">None</span></code>, this function may replace that value with a | |
| context-specific default, contingent on <code class="docutils literal notranslate"><span class="pre">type(obj)</span></code>:</p> | |
| <ul class="simple"> | |
| <li><p>If <em>obj</em> is a module, <em>globals</em> defaults to <code class="docutils literal notranslate"><span class="pre">obj.__dict__</span></code>.</p></li> | |
| <li><p>If <em>obj</em> is a class, <em>globals</em> defaults to | |
| <code class="docutils literal notranslate"><span class="pre">sys.modules[obj.__module__].__dict__</span></code> and <em>locals</em> defaults | |
| to the <em>obj</em> class namespace.</p></li> | |
| <li><p>If <em>obj</em> is a callable, <em>globals</em> defaults to | |
| <a class="reference internal" href="../reference/datamodel.html#function.__globals__" title="function.__globals__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">obj.__globals__</span></code></a>, | |
| although if <em>obj</em> is a wrapped function (using | |
| <a class="reference internal" href="functools.html#functools.update_wrapper" title="functools.update_wrapper"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.update_wrapper()</span></code></a>) or a <a class="reference internal" href="functools.html#functools.partial" title="functools.partial"><code class="xref py py-class docutils literal notranslate"><span class="pre">functools.partial</span></code></a> object, | |
| it is unwrapped until a non-wrapped function is found.</p></li> | |
| </ul> | |
| <p>Calling <code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code> is best practice for accessing the | |
| annotations dict of any object. See <a class="reference internal" href="../howto/annotations.html#annotations-howto"><span class="std std-ref">Annotations Best Practices</span></a> for | |
| more information on annotations best practices.</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">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span> | |
| <span class="gp">... </span> <span class="k">pass</span> | |
| <span class="gp">>>> </span><span class="n">get_annotations</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> | |
| <span class="go">{'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'float'>}</span> | |
| </pre></div> | |
| </div> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| </dd></dl> | |
| <dl class="py function"> | |
| <dt class="sig sig-object py" id="annotationlib.type_repr"> | |
| <span class="sig-prename descclassname"><span class="pre">annotationlib.</span></span><span class="sig-name descname"><span class="pre">type_repr</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">value</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#annotationlib.type_repr" title="Link to this definition">¶</a></dt> | |
| <dd><p>Convert an arbitrary Python value to a format suitable for use by the | |
| <a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a> format. This calls <a class="reference internal" href="functions.html#repr" title="repr"><code class="xref py py-func docutils literal notranslate"><span class="pre">repr()</span></code></a> for most | |
| objects, but has special handling for some objects, such as type objects.</p> | |
| <p>This is meant as a helper for user-provided | |
| annotate functions that support the <a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a> format but | |
| do not have access to the code creating the annotations. It can also | |
| be used to provide a user-friendly string representation for other | |
| objects that contain values that are commonly encountered in annotations.</p> | |
| <div class="versionadded"> | |
| <p><span class="versionmodified added">Added in version 3.14.</span></p> | |
| </div> | |
| </dd></dl> | |
| </section> | |
| <section id="recipes"> | |
| <h2>Recipes<a class="headerlink" href="#recipes" title="Link to this heading">¶</a></h2> | |
| <section id="using-annotations-in-a-metaclass"> | |
| <span id="annotationlib-metaclass"></span><h3>Using annotations in a metaclass<a class="headerlink" href="#using-annotations-in-a-metaclass" title="Link to this heading">¶</a></h3> | |
| <p>A <a class="reference internal" href="../reference/datamodel.html#metaclasses"><span class="std std-ref">metaclass</span></a> may want to inspect or even modify the annotations | |
| in a class body during class creation. Doing so requires retrieving annotations | |
| from the class namespace dictionary. For classes created with | |
| <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>, the annotations will be in the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> | |
| key of the dictionary. For other classes with annotations, | |
| <a class="reference internal" href="#annotationlib.get_annotate_from_class_namespace" title="annotationlib.get_annotate_from_class_namespace"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotate_from_class_namespace()</span></code></a> can be used to get the | |
| annotate function, and <a class="reference internal" href="#annotationlib.call_annotate_function" title="annotationlib.call_annotate_function"><code class="xref py py-func docutils literal notranslate"><span class="pre">call_annotate_function()</span></code></a> can be used to call it and | |
| retrieve the annotations. Using the <a class="reference internal" href="#annotationlib.Format.FORWARDREF" title="annotationlib.Format.FORWARDREF"><code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code></a> format will usually | |
| be best, because this allows the annotations to refer to names that cannot yet be | |
| resolved when the class is created.</p> | |
| <p>To modify the annotations, it is best to create a wrapper annotate function | |
| that calls the original annotate function, makes any necessary adjustments, and | |
| returns the result.</p> | |
| <p>Below is an example of a metaclass that filters out all <a class="reference internal" href="typing.html#typing.ClassVar" title="typing.ClassVar"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.ClassVar</span></code></a> | |
| annotations from the class and puts them in a separate attribute:</p> | |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">annotationlib</span> | |
| <span class="kn">import</span><span class="w"> </span><span class="nn">typing</span> | |
| <span class="k">class</span><span class="w"> </span><span class="nc">ClassVarSeparator</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span> | |
| <span class="k">def</span><span class="w"> </span><span class="fm">__new__</span><span class="p">(</span><span class="n">mcls</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">ns</span><span class="p">):</span> | |
| <span class="k">if</span> <span class="s2">"__annotations__"</span> <span class="ow">in</span> <span class="n">ns</span><span class="p">:</span> <span class="c1"># from __future__ import annotations</span> | |
| <span class="n">annotations</span> <span class="o">=</span> <span class="n">ns</span><span class="p">[</span><span class="s2">"__annotations__"</span><span class="p">]</span> | |
| <span class="n">classvar_keys</span> <span class="o">=</span> <span class="p">{</span> | |
| <span class="n">key</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">annotations</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> | |
| <span class="c1"># Use string comparison for simplicity; a more robust solution</span> | |
| <span class="c1"># could use annotationlib.ForwardRef.evaluate</span> | |
| <span class="k">if</span> <span class="n">value</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"ClassVar"</span><span class="p">)</span> | |
| <span class="p">}</span> | |
| <span class="n">classvars</span> <span class="o">=</span> <span class="p">{</span><span class="n">key</span><span class="p">:</span> <span class="n">annotations</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">classvar_keys</span><span class="p">}</span> | |
| <span class="n">ns</span><span class="p">[</span><span class="s2">"__annotations__"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> | |
| <span class="n">key</span><span class="p">:</span> <span class="n">value</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">annotations</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> | |
| <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">classvar_keys</span> | |
| <span class="p">}</span> | |
| <span class="n">wrapped_annotate</span> <span class="o">=</span> <span class="kc">None</span> | |
| <span class="k">elif</span> <span class="n">annotate</span> <span class="o">:=</span> <span class="n">annotationlib</span><span class="o">.</span><span class="n">get_annotate_from_class_namespace</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span> | |
| <span class="n">annotations</span> <span class="o">=</span> <span class="n">annotationlib</span><span class="o">.</span><span class="n">call_annotate_function</span><span class="p">(</span> | |
| <span class="n">annotate</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">FORWARDREF</span> | |
| <span class="p">)</span> | |
| <span class="n">classvar_keys</span> <span class="o">=</span> <span class="p">{</span> | |
| <span class="n">key</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">annotations</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> | |
| <span class="k">if</span> <span class="n">typing</span><span class="o">.</span><span class="n">get_origin</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="ow">is</span> <span class="n">typing</span><span class="o">.</span><span class="n">ClassVar</span> | |
| <span class="p">}</span> | |
| <span class="n">classvars</span> <span class="o">=</span> <span class="p">{</span><span class="n">key</span><span class="p">:</span> <span class="n">annotations</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">classvar_keys</span><span class="p">}</span> | |
| <span class="k">def</span><span class="w"> </span><span class="nf">wrapped_annotate</span><span class="p">(</span><span class="nb">format</span><span class="p">):</span> | |
| <span class="n">annos</span> <span class="o">=</span> <span class="n">annotationlib</span><span class="o">.</span><span class="n">call_annotate_function</span><span class="p">(</span><span class="n">annotate</span><span class="p">,</span> <span class="nb">format</span><span class="p">,</span> <span class="n">owner</span><span class="o">=</span><span class="n">typ</span><span class="p">)</span> | |
| <span class="k">return</span> <span class="p">{</span><span class="n">key</span><span class="p">:</span> <span class="n">value</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">annos</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">classvar_keys</span><span class="p">}</span> | |
| <span class="k">else</span><span class="p">:</span> <span class="c1"># no annotations</span> | |
| <span class="n">classvars</span> <span class="o">=</span> <span class="p">{}</span> | |
| <span class="n">wrapped_annotate</span> <span class="o">=</span> <span class="kc">None</span> | |
| <span class="n">typ</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="n">mcls</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span> | |
| <span class="k">if</span> <span class="n">wrapped_annotate</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> | |
| <span class="c1"># Wrap the original __annotate__ with a wrapper that removes ClassVars</span> | |
| <span class="n">typ</span><span class="o">.</span><span class="n">__annotate__</span> <span class="o">=</span> <span class="n">wrapped_annotate</span> | |
| <span class="n">typ</span><span class="o">.</span><span class="n">classvars</span> <span class="o">=</span> <span class="n">classvars</span> <span class="c1"># Store the ClassVars in a separate attribute</span> | |
| <span class="k">return</span> <span class="n">typ</span> | |
| </pre></div> | |
| </div> | |
| </section> | |
| </section> | |
| <section id="limitations-of-the-string-format"> | |
| <h2>Limitations of the <code class="docutils literal notranslate"><span class="pre">STRING</span></code> format<a class="headerlink" href="#limitations-of-the-string-format" title="Link to this heading">¶</a></h2> | |
| <p>The <a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a> format is meant to approximate the source code | |
| of the annotation, but the implementation strategy used means that it is not | |
| always possible to recover the exact source code.</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 compiler.</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">STRING</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">STRING</span><span class="p">)</span> | |
| <span class="go">Hello world</span> | |
| <span class="go">{'x': 'None'}</span> | |
| </pre></div> | |
| </div> | |
| <div class="admonition note"> | |
| <p class="admonition-title">Note</p> | |
| <p>This particular example works as of the time of writing, but it relies on | |
| implementation details and is not guaranteed to work in the future.</p> | |
| </div> | |
| <p>Among the different kinds of expressions that exist in Python, | |
| as represented by the <a class="reference internal" href="ast.html#module-ast" title="ast: Abstract Syntax Tree classes and manipulation."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ast</span></code></a> module, some expressions are supported, | |
| meaning that the <code class="docutils literal notranslate"><span class="pre">STRING</span></code> format can generally recover the original source code; | |
| others are unsupported, meaning that they may result in incorrect output or an error.</p> | |
| <p>The following are supported (sometimes with caveats):</p> | |
| <ul class="simple"> | |
| <li><p><a class="reference internal" href="ast.html#ast.BinOp" title="ast.BinOp"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.BinOp</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.UnaryOp" title="ast.UnaryOp"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.UnaryOp</span></code></a></p> | |
| <ul> | |
| <li><p><a class="reference internal" href="ast.html#ast.Invert" title="ast.Invert"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Invert</span></code></a> (<code class="docutils literal notranslate"><span class="pre">~</span></code>), <a class="reference internal" href="ast.html#ast.UAdd" title="ast.UAdd"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.UAdd</span></code></a> (<code class="docutils literal notranslate"><span class="pre">+</span></code>), and <a class="reference internal" href="ast.html#ast.USub" title="ast.USub"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.USub</span></code></a> (<code class="docutils literal notranslate"><span class="pre">-</span></code>) are supported</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Not" title="ast.Not"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Not</span></code></a> (<code class="docutils literal notranslate"><span class="pre">not</span></code>) is not supported</p></li> | |
| </ul> | |
| </li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Dict" title="ast.Dict"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Dict</span></code></a> (except when using <code class="docutils literal notranslate"><span class="pre">**</span></code> unpacking)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Set" title="ast.Set"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Set</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Compare" title="ast.Compare"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Compare</span></code></a></p> | |
| <ul> | |
| <li><p><a class="reference internal" href="ast.html#ast.Eq" title="ast.Eq"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Eq</span></code></a> and <a class="reference internal" href="ast.html#ast.NotEq" title="ast.NotEq"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.NotEq</span></code></a> are supported</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Lt" title="ast.Lt"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Lt</span></code></a>, <a class="reference internal" href="ast.html#ast.LtE" title="ast.LtE"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.LtE</span></code></a>, <a class="reference internal" href="ast.html#ast.Gt" title="ast.Gt"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Gt</span></code></a>, and <a class="reference internal" href="ast.html#ast.GtE" title="ast.GtE"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.GtE</span></code></a> are supported, but the operand may be flipped</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Is" title="ast.Is"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Is</span></code></a>, <a class="reference internal" href="ast.html#ast.IsNot" title="ast.IsNot"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.IsNot</span></code></a>, <a class="reference internal" href="ast.html#ast.In" title="ast.In"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.In</span></code></a>, and <a class="reference internal" href="ast.html#ast.NotIn" title="ast.NotIn"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.NotIn</span></code></a> are not supported</p></li> | |
| </ul> | |
| </li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Call" title="ast.Call"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Call</span></code></a> (except when using <code class="docutils literal notranslate"><span class="pre">**</span></code> unpacking)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Constant" title="ast.Constant"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Constant</span></code></a> (though not the exact representation of the constant; for example, escape | |
| sequences in strings are lost; hexadecimal numbers are converted to decimal)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Attribute" title="ast.Attribute"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Attribute</span></code></a> (assuming the value is not a constant)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Subscript" title="ast.Subscript"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Subscript</span></code></a> (assuming the value is not a constant)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Starred" title="ast.Starred"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Starred</span></code></a> (<code class="docutils literal notranslate"><span class="pre">*</span></code> unpacking)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Name" title="ast.Name"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Name</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.List" title="ast.List"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.List</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Tuple" title="ast.Tuple"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Tuple</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Slice" title="ast.Slice"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Slice</span></code></a></p></li> | |
| </ul> | |
| <p>The following are unsupported, but throw an informative error when encountered by the | |
| stringifier:</p> | |
| <ul class="simple"> | |
| <li><p><a class="reference internal" href="ast.html#ast.FormattedValue" title="ast.FormattedValue"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.FormattedValue</span></code></a> (f-strings; error is not detected if conversion specifiers like <code class="docutils literal notranslate"><span class="pre">!r</span></code> | |
| are used)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.JoinedStr" title="ast.JoinedStr"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.JoinedStr</span></code></a> (f-strings)</p></li> | |
| </ul> | |
| <p>The following are unsupported and result in incorrect output:</p> | |
| <ul class="simple"> | |
| <li><p><a class="reference internal" href="ast.html#ast.BoolOp" title="ast.BoolOp"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.BoolOp</span></code></a> (<code class="docutils literal notranslate"><span class="pre">and</span></code> and <code class="docutils literal notranslate"><span class="pre">or</span></code>)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.IfExp" title="ast.IfExp"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.IfExp</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Lambda" title="ast.Lambda"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Lambda</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.ListComp" title="ast.ListComp"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.ListComp</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.SetComp" title="ast.SetComp"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.SetComp</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.DictComp" title="ast.DictComp"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.DictComp</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.GeneratorExp" title="ast.GeneratorExp"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.GeneratorExp</span></code></a></p></li> | |
| </ul> | |
| <p>The following are disallowed in annotation scopes and therefore not relevant:</p> | |
| <ul class="simple"> | |
| <li><p><a class="reference internal" href="ast.html#ast.NamedExpr" title="ast.NamedExpr"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.NamedExpr</span></code></a> (<code class="docutils literal notranslate"><span class="pre">:=</span></code>)</p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Await" title="ast.Await"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Await</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.Yield" title="ast.Yield"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.Yield</span></code></a></p></li> | |
| <li><p><a class="reference internal" href="ast.html#ast.YieldFrom" title="ast.YieldFrom"><code class="xref py py-class docutils literal notranslate"><span class="pre">ast.YieldFrom</span></code></a></p></li> | |
| </ul> | |
| </section> | |
| <section id="limitations-of-the-forwardref-format"> | |
| <h2>Limitations of the <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code> format<a class="headerlink" href="#limitations-of-the-forwardref-format" title="Link to this heading">¶</a></h2> | |
| <p>The <a class="reference internal" href="#annotationlib.Format.FORWARDREF" title="annotationlib.Format.FORWARDREF"><code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code></a> format aims to produce real values as much | |
| as possible, with anything that cannot be resolved replaced with | |
| <a class="reference internal" href="#annotationlib.ForwardRef" title="annotationlib.ForwardRef"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code></a> objects. It is affected by broadly the same Limitations | |
| as the <a class="reference internal" href="#annotationlib.Format.STRING" title="annotationlib.Format.STRING"><code class="xref py py-attr docutils literal notranslate"><span class="pre">STRING</span></code></a> format: annotations that perform operations on | |
| literals or that use unsupported expression types may raise exceptions when | |
| evaluated using the <code class="xref py py-attr docutils literal notranslate"><span class="pre">FORWARDREF</span></code> format.</p> | |
| <p>Below are a few examples of the behavior with unsupported expressions:</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">annotationlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_annotations</span><span class="p">,</span> <span class="n">Format</span> | |
| <span class="gp">>>> </span><span class="k">def</span><span class="w"> </span><span class="nf">zerodiv</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">0</span><span class="p">):</span> <span class="o">...</span> | |
| <span class="gp">>>> </span><span class="n">get_annotations</span><span class="p">(</span><span class="n">zerodiv</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="n">Format</span><span class="o">.</span><span class="n">STRING</span><span class="p">)</span> | |
| <span class="gt">Traceback (most recent call last):</span> | |
| <span class="w"> </span><span class="c">...</span> | |
| <span class="gr">ZeroDivisionError</span>: <span class="n">division by zero</span> | |
| <span class="gp">>>> </span><span class="n">get_annotations</span><span class="p">(</span><span class="n">zerodiv</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="n">Format</span><span class="o">.</span><span class="n">FORWARDREF</span><span class="p">)</span> | |
| <span class="gt">Traceback (most recent call last):</span> | |
| <span class="w"> </span><span class="c">...</span> | |
| <span class="gr">ZeroDivisionError</span>: <span class="n">division by zero</span> | |
| <span class="gp">>>> </span><span class="k">def</span><span class="w"> </span><span class="nf">ifexp</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="mi">1</span> <span class="k">if</span> <span class="n">y</span> <span class="k">else</span> <span class="mi">0</span><span class="p">):</span> <span class="o">...</span> | |
| <span class="gp">>>> </span><span class="n">get_annotations</span><span class="p">(</span><span class="n">ifexp</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="n">Format</span><span class="o">.</span><span class="n">STRING</span><span class="p">)</span> | |
| <span class="go">{'x': '1'}</span> | |
| </pre></div> | |
| </div> | |
| </section> | |
| <section id="security-implications-of-introspecting-annotations"> | |
| <span id="annotationlib-security"></span><h2>Security implications of introspecting annotations<a class="headerlink" href="#security-implications-of-introspecting-annotations" title="Link to this heading">¶</a></h2> | |
| <p>Much of the functionality in this module involves executing code related to annotations, | |
| which can then do arbitrary things. For example, | |
| <a class="reference internal" href="#annotationlib.get_annotations" title="annotationlib.get_annotations"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_annotations()</span></code></a> may call an arbitrary <a class="reference internal" href="../glossary.html#term-annotate-function"><span class="xref std std-term">annotate function</span></a>, and | |
| <a class="reference internal" href="#annotationlib.ForwardRef.evaluate" title="annotationlib.ForwardRef.evaluate"><code class="xref py py-meth docutils literal notranslate"><span class="pre">ForwardRef.evaluate()</span></code></a> may call <a class="reference internal" href="functions.html#eval" title="eval"><code class="xref py py-func docutils literal notranslate"><span class="pre">eval()</span></code></a> on an arbitrary string. Code contained | |
| in an annotation might make arbitrary system calls, enter an infinite loop, or perform any | |
| other operation. This is also true for any access of the <a class="reference internal" href="../reference/datamodel.html#object.__annotations__" title="object.__annotations__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__annotations__</span></code></a> attribute, | |
| and for various functions in the <a class="reference internal" href="typing.html#module-typing" title="typing: Support for type hints (see :pep:`484`)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code></a> module that work with annotations, such as | |
| <a class="reference internal" href="typing.html#typing.get_type_hints" title="typing.get_type_hints"><code class="xref py py-func docutils literal notranslate"><span class="pre">typing.get_type_hints()</span></code></a>.</p> | |
| <p>Any security issue arising from this also applies immediately after importing | |
| code that may contain untrusted annotations: importing code can always cause arbitrary operations | |
| to be performed. However, it is unsafe to accept strings or other input from an untrusted source and | |
| pass them to any of the APIs for introspecting annotations, for example by editing an | |
| <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> dictionary or directly creating a <a class="reference internal" href="#annotationlib.ForwardRef" title="annotationlib.ForwardRef"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForwardRef</span></code></a> object.</p> | |
| </section> | |
| </section> | |
| <div class="clearer"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="sphinxsidebar" role="navigation" aria-label="Main"> | |
| <div class="sphinxsidebarwrapper"> | |
| <div> | |
| <h3><a href="../contents.html">Table of Contents</a></h3> | |
| <ul> | |
| <li><a class="reference internal" href="#"><code class="xref py py-mod docutils literal notranslate"><span class="pre">annotationlib</span></code> — Functionality for introspecting annotations</a><ul> | |
| <li><a class="reference internal" href="#annotation-semantics">Annotation semantics</a></li> | |
| <li><a class="reference internal" href="#classes">Classes</a></li> | |
| <li><a class="reference internal" href="#functions">Functions</a></li> | |
| <li><a class="reference internal" href="#recipes">Recipes</a><ul> | |
| <li><a class="reference internal" href="#using-annotations-in-a-metaclass">Using annotations in a metaclass</a></li> | |
| </ul> | |
| </li> | |
| <li><a class="reference internal" href="#limitations-of-the-string-format">Limitations of the <code class="docutils literal notranslate"><span class="pre">STRING</span></code> format</a></li> | |
| <li><a class="reference internal" href="#limitations-of-the-forwardref-format">Limitations of the <code class="docutils literal notranslate"><span class="pre">FORWARDREF</span></code> format</a></li> | |
| <li><a class="reference internal" href="#security-implications-of-introspecting-annotations">Security implications of introspecting annotations</a></li> | |
| </ul> | |
| </li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h4>Previous topic</h4> | |
| <p class="topless"><a href="inspect.html" | |
| title="previous chapter"><code class="xref py py-mod docutils literal notranslate"><span class="pre">inspect</span></code> — Inspect live objects</a></p> | |
| </div> | |
| <div> | |
| <h4>Next topic</h4> | |
| <p class="topless"><a href="site.html" | |
| title="next chapter"><code class="xref py py-mod docutils literal notranslate"><span class="pre">site</span></code> — Site-specific configuration hook</a></p> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const title = document.querySelector('meta[property="og:title"]').content; | |
| const elements = document.querySelectorAll('.improvepage'); | |
| const pageurl = window.location.href.split('?')[0]; | |
| elements.forEach(element => { | |
| const url = new URL(element.href.split('?')[0].replace("-nojs", "")); | |
| url.searchParams.set('pagetitle', title); | |
| url.searchParams.set('pageurl', pageurl); | |
| url.searchParams.set('pagesource', "library/annotationlib.rst"); | |
| element.href = url.toString(); | |
| }); | |
| }); | |
| </script> | |
| <div role="note" aria-label="source link"> | |
| <h3>This page</h3> | |
| <ul class="this-page-menu"> | |
| <li><a href="../bugs.html">Report a bug</a></li> | |
| <li><a class="improvepage" href="../improve-page-nojs.html">Improve this page</a></li> | |
| <li> | |
| <a href="https://github.com/python/cpython/blob/main/Doc/library/annotationlib.rst?plain=1" | |
| rel="nofollow">Show source | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div id="sidebarbutton" title="Collapse sidebar"> | |
| <span>«</span> | |
| </div> | |
| </div> | |
| <div class="clearer"></div> | |
| </div> | |
| <div class="related" role="navigation" aria-label="Related"> | |
| <h3>Navigation</h3> | |
| <ul> | |
| <li class="right" style="margin-right: 10px"> | |
| <a href="../genindex.html" title="General Index" | |
| >index</a></li> | |
| <li class="right" > | |
| <a href="../py-modindex.html" title="Python Module Index" | |
| >modules</a> |</li> | |
| <li class="right" > | |
| <a href="site.html" title="site — Site-specific configuration hook" | |
| >next</a> |</li> | |
| <li class="right" > | |
| <a href="inspect.html" title="inspect — Inspect live objects" | |
| >previous</a> |</li> | |
| <li><img src="../_static/py.svg" alt="Python logo" style="vertical-align: middle; margin-top: -1px"></li> | |
| <li><a href="https://www.python.org/">Python</a> »</li> | |
| <li class="switchers"> | |
| <div class="language_switcher_placeholder"></div> | |
| <div class="version_switcher_placeholder"></div> | |
| </li> | |
| <li> | |
| </li> | |
| <li id="cpython-language-and-version"> | |
| <a href="../index.html">3.15.0a6 Documentation</a> » | |
| </li> | |
| <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li> | |
| <li class="nav-item nav-item-2"><a href="python.html" >Python Runtime Services</a> »</li> | |
| <li class="nav-item nav-item-this"><a href=""><code class="xref py py-mod docutils literal notranslate"><span class="pre">annotationlib</span></code> — Functionality for introspecting annotations</a></li> | |
| <li class="right"> | |
| <div class="inline-search" role="search"> | |
| <form class="inline-search" action="../search.html" method="get"> | |
| <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" id="search-box"> | |
| <input type="submit" value="Go"> | |
| </form> | |
| </div> | |
| | | |
| </li> | |
| <li class="right"> | |
| <label class="theme-selector-label"> | |
| Theme | |
| <select class="theme-selector" oninput="activateTheme(this.value)"> | |
| <option value="auto" selected>Auto</option> | |
| <option value="light">Light</option> | |
| <option value="dark">Dark</option> | |
| </select> | |
| </label> |</li> | |
| </ul> | |
| </div> | |
| <div class="footer"> | |
| © <a href="../copyright.html">Copyright</a> 2001 Python Software Foundation. | |
| <br> | |
| This page is licensed under the Python Software Foundation License Version 2. | |
| <br> | |
| Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License. | |
| <br> | |
| See <a href="/license.html">History and License</a> for more information.<br> | |
| <br> | |
| The Python Software Foundation is a non-profit corporation. | |
| <a href="https://www.python.org/psf/donations/">Please donate.</a> | |
| <br> | |
| <br> | |
| Last updated on Mar 10, 2026 (08:58 UTC). | |
| <a href="/bugs.html">Found a bug</a>? | |
| <br> | |
| Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3. | |
| </div> | |
| </body> | |
| </html> |