CINXE.COM
PEP 702 – Marking deprecations using the type system | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 702 – Marking deprecations using the type system | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0702/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 702 – Marking deprecations using the type system | peps.python.org'> <meta property="og:description" content="This PEP adds an @warnings.deprecated() decorator that marks a class or function as deprecated, enabling static checkers to warn when it is used. By default, this decorator will also raise a runtime DeprecationWarning."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0702/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="This PEP adds an @warnings.deprecated() decorator that marks a class or function as deprecated, enabling static checkers to warn when it is used. By default, this decorator will also raise a runtime DeprecationWarning."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 702</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 702 – Marking deprecations using the type system</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Jelle Zijlstra <jelle.zijlstra at gmail.com></dd> <dt class="field-even">Discussions-To<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/pep-702-marking-deprecations-using-the-type-system/23036">Discourse thread</a></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-odd">Topic<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="../topic/typing/">Typing</a></dd> <dt class="field-even">Created<span class="colon">:</span></dt> <dd class="field-even">30-Dec-2022</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.13</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/thread/AKTFUYW3WDT7R7PGRIJQZMYHMDJNE4QH/" title="Typing-SIG thread">01-Jan-2023</a>, <a class="reference external" href="https://discuss.python.org/t/pep-702-marking-deprecations-using-the-type-system/23036" title="Discourse thread">22-Jan-2023</a></dd> <dt class="field-odd">Resolution<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/pep-702-marking-deprecations-using-the-type-system/23036/61">07-Nov-2023</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#example">Example</a></li> <li><a class="reference internal" href="#runtime-behavior">Runtime behavior</a></li> <li><a class="reference internal" href="#type-checker-behavior">Type checker behavior</a></li> <li><a class="reference internal" href="#deprecation-policy">Deprecation policy</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards compatibility</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to teach this</a></li> <li><a class="reference internal" href="#reference-implementation">Reference implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected ideas</a><ul> <li><a class="reference internal" href="#deprecation-of-modules-and-attributes">Deprecation of modules and attributes</a></li> <li><a class="reference internal" href="#placing-the-decorator-in-the-typing-module">Placing the decorator in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module</a></li> </ul> </li> <li><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <div class="pep-banner canonical-typing-spec sticky-banner admonition important"> <p class="admonition-title">Important</p> <p>This PEP is a historical document: see <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/directives.html#deprecated" title="(in typing)"><span>@deprecated</span></a> and <a class="reference external" href="https://docs.python.org/3.13/library/warnings.html#warnings.deprecated" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">@warnings.deprecated</span></code></a> for up-to-date specs and documentation. Canonical typing specs are maintained at the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/">typing specs site</a>; runtime typing behaviour is described in the CPython documentation.</p> <p class="close-button">×</p> <p>See the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/meta.html">typing specification update process</a> for how to propose changes to the typing spec.</p> </div> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP adds an <code class="docutils literal notranslate"><span class="pre">@warnings.deprecated()</span></code> decorator that marks a class or function as deprecated, enabling static checkers to warn when it is used. By default, this decorator will also raise a runtime <code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code>.</p> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>As software evolves, new functionality is added and old functionality becomes obsolete. Library developers want to work towards removing obsolete code while giving their users time to migrate to new APIs. Python provides a mechanism for achieving these goals: the <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#DeprecationWarning" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">DeprecationWarning</span></code></a> warning class, which is used to show warnings when deprecated functionality is used. This mechanism is widely used: as of the writing of this PEP, the CPython main branch contains about 150 distinct code paths that raise <code class="xref py py-exc docutils literal notranslate"><span class="pre">DeprecationWarning</span></code>. Many third-party libraries also use <code class="xref py py-exc docutils literal notranslate"><span class="pre">DeprecationWarning</span></code> to mark deprecations. In the <a class="reference external" href="https://dev.to/hugovk/how-to-search-5000-python-projects-31gk">top 5000 PyPI packages</a>, there are:</p> <ul class="simple"> <li>1911 matches for the regex <code class="docutils literal notranslate"><span class="pre">warnings\.warn.*\bDeprecationWarning\b</span></code>, indicating use of <code class="xref py py-exc docutils literal notranslate"><span class="pre">DeprecationWarning</span></code> (not including cases where the warning is split over multiple lines);</li> <li>1661 matches for the regex <code class="docutils literal notranslate"><span class="pre">^\s*@deprecated</span></code>, indicating use of some sort of deprecation decorator.</li> </ul> <p>However, the current mechanism is often insufficient to ensure that users of deprecated functionality update their code in time. For example, the removal of various long-deprecated <a class="reference external" href="https://docs.python.org/3/library/unittest.html#module-unittest" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">unittest</span></code></a> features had to be <a class="reference external" href="https://github.com/python/cpython/commit/b50322d20337ca468f2070eedb051a16ee1eba94">reverted</a> from Python 3.11 to give users more time to update their code. Users may run their test suite with warnings disabled for practical reasons, or deprecations may be triggered in code paths that are not covered by tests.</p> <p>Providing more ways for users to find out about deprecated functionality can speed up the migration process. This PEP proposes to leverage static type checkers to communicate deprecations to users. Such checkers have a thorough semantic understanding of user code, enabling them to detect and report deprecations that a single <code class="docutils literal notranslate"><span class="pre">grep</span></code> invocation could not find. In addition, many type checkers integrate with IDEs, enabling users to see deprecation warnings right in their editors.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>At first glance, deprecations may not seem like a topic that type checkers should touch. After all, type checkers are concerned with checking whether code will work as is, not with potential future changes. However, the analysis that type checkers perform on code to find type errors is very similar to the analysis that would be needed to detect usage of many deprecations. Therefore, type checkers are well placed to find and report deprecations.</p> <p>Other languages already have similar functionality:</p> <ul class="simple"> <li>GCC supports a <code class="docutils literal notranslate"><span class="pre">deprecated</span></code> <a class="reference external" href="https://gcc.gnu.org/onlinedocs/gcc-3.1.1/gcc/Type-Attributes.html">attribute</a> on function declarations. This powers CPython’s <code class="docutils literal notranslate"><span class="pre">Py_DEPRECATED</span></code> macro.</li> <li>GraphQL <a class="reference external" href="https://spec.graphql.org/June2018/#sec-Field-Deprecation">supports</a> marking fields as <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code>.</li> <li>Kotlin <a class="reference external" href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-deprecated/">supports</a> a <code class="docutils literal notranslate"><span class="pre">Deprecated</span></code> annotation.</li> <li>Scala <a class="reference external" href="https://www.scala-lang.org/api/2.12.5/scala/deprecated.html">supports</a> an <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> annotation.</li> <li>Swift <a class="reference external" href="https://docs.swift.org/swift-book/ReferenceManual/Attributes.html">supports</a> using the <code class="docutils literal notranslate"><span class="pre">@available</span></code> attribute to mark APIs as deprecated.</li> <li>TypeScript <a class="reference external" href="https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#deprecated">uses</a> the <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> JSDoc tag to issue a hint marking use of deprecated functionality.</li> </ul> <p>Several users have requested support for such a feature:</p> <ul class="simple"> <li><a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/thread/E24WTMQUTGKPFKEXVCGGEFFMG7LDF3WT/">typing-sig thread</a></li> <li><a class="reference external" href="https://github.com/microsoft/pyright/discussions/2300">Pyright feature request</a></li> <li><a class="reference external" href="https://github.com/python/mypy/issues/11439">mypy feature request</a></li> </ul> <p>There are similar existing third-party tools:</p> <ul class="simple"> <li><a class="reference external" href="https://pypi.org/project/Deprecated/">Deprecated</a> provides a decorator to mark classes, functions, or methods as deprecated. Access to decorated objects raises a runtime warning, but is not detected by type checkers.</li> <li><a class="reference external" href="https://pypi.org/project/flake8-deprecated/">flake8-deprecated</a> is a linter plugin that warns about use of deprecated features. However, it is limited to a short, hard-coded list of deprecations.</li> </ul> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <p>A new decorator <code class="docutils literal notranslate"><span class="pre">@deprecated()</span></code> is added to the <a class="reference external" href="https://docs.python.org/3/library/warnings.html#module-warnings" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">warnings</span></code></a> module. This decorator can be used on a class, function or method to mark it as deprecated. This includes <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypedDict</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.NamedTuple" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.NamedTuple</span></code></a> definitions. With overloaded functions, the decorator may be applied to individual overloads, indicating that the particular overload is deprecated. The decorator may also be applied to the overload implementation function, indicating that the entire function is deprecated.</p> <p>The decorator takes the following arguments:</p> <ul class="simple"> <li>A required positional-only argument representing the deprecation message.</li> <li>Two keyword-only arguments, <code class="docutils literal notranslate"><span class="pre">category</span></code> and <code class="docutils literal notranslate"><span class="pre">stacklevel</span></code>, controlling runtime behavior (see under “Runtime behavior” below).</li> </ul> <p>The positional-only argument is of type <code class="docutils literal notranslate"><span class="pre">str</span></code> and contains a message that should be shown by the type checker when it encounters a usage of the decorated object. Tools may clean up the deprecation message for display, for example by using <a class="reference external" href="https://docs.python.org/3/library/inspect.html#inspect.cleandoc" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">inspect.cleandoc()</span></code></a> or equivalent logic. The message must be a string literal. The content of deprecation messages is up to the user, but it may include the version in which the deprecated object is to be removed, and information about suggested replacement APIs.</p> <p>Type checkers should produce a diagnostic whenever they encounter a usage of an object marked as deprecated. For deprecated overloads, this includes all calls that resolve to the deprecated overload. For deprecated classes and functions, this includes:</p> <ul class="simple"> <li>References through module, class, or instance attributes (<code class="docutils literal notranslate"><span class="pre">module.deprecated_object</span></code>, <code class="docutils literal notranslate"><span class="pre">module.SomeClass.deprecated_method</span></code>, <code class="docutils literal notranslate"><span class="pre">module.SomeClass().deprecated_method</span></code>)</li> <li>Any usage of deprecated objects in their defining module (<code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">deprecated_object()</span></code> in <code class="docutils literal notranslate"><span class="pre">module.py</span></code>)</li> <li>If <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">*</span></code> is used, usage of deprecated objects from the module (<code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">module</span> <span class="pre">import</span> <span class="pre">*;</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">deprecated_object()</span></code>)</li> <li><code class="docutils literal notranslate"><span class="pre">from</span></code> imports (<code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">module</span> <span class="pre">import</span> <span class="pre">deprecated_object</span></code>)</li> <li>Any syntax that indirectly triggers a call to the function. For example, if the <code class="docutils literal notranslate"><span class="pre">__add__</span></code> method of a class <code class="docutils literal notranslate"><span class="pre">C</span></code> is deprecated, then the code <code class="docutils literal notranslate"><span class="pre">C()</span> <span class="pre">+</span> <span class="pre">C()</span></code> should trigger a diagnostic. Similarly, if the setter of a property is marked deprecated, attempts to set the property should trigger a diagnostic.</li> </ul> <p>If a method is marked with the <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.override" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">typing.override()</span></code></a> decorator from <a class="pep reference internal" href="../pep-0698/" title="PEP 698 – Override Decorator for Static Typing">PEP 698</a> and the base class method it overrides is deprecated, the type checker should produce a diagnostic.</p> <p>There are additional scenarios where deprecations could come into play. For example, an object may implement a <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Protocol" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.Protocol</span></code></a>, but one of the methods required for protocol compliance is deprecated. As scenarios such as this one appear complex and relatively unlikely to come up in practice, this PEP does not mandate that type checkers detect them.</p> <section id="example"> <h3><a class="toc-backref" href="#example" role="doc-backlink">Example</a></h3> <p>As an example, consider this library stub named <code class="docutils literal notranslate"><span class="pre">library.pyi</span></code>:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">warnings</span><span class="w"> </span><span class="kn">import</span> <span class="n">deprecated</span> <span class="nd">@deprecated</span><span class="p">(</span><span class="s2">"Use Spam instead"</span><span class="p">)</span> <span class="k">class</span><span class="w"> </span><span class="nc">Ham</span><span class="p">:</span> <span class="o">...</span> <span class="nd">@deprecated</span><span class="p">(</span><span class="s2">"It is pining for the fiords"</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">norwegian_blue</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span> <span class="o">...</span> <span class="nd">@overload</span> <span class="nd">@deprecated</span><span class="p">(</span><span class="s2">"Only str will be allowed"</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="o">...</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="o">...</span> <span class="k">class</span><span class="w"> </span><span class="nc">Spam</span><span class="p">:</span> <span class="nd">@deprecated</span><span class="p">(</span><span class="s2">"There is enough spam in the world"</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="nb">object</span><span class="p">:</span> <span class="o">...</span> <span class="nd">@property</span> <span class="nd">@deprecated</span><span class="p">(</span><span class="s2">"All spam will be equally greasy"</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">greasy</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span> <span class="o">...</span> <span class="nd">@property</span> <span class="k">def</span><span class="w"> </span><span class="nf">shape</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="o">...</span> <span class="nd">@shape</span><span class="o">.</span><span class="n">setter</span> <span class="nd">@deprecated</span><span class="p">(</span><span class="s2">"Shapes are becoming immutable"</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">shape</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> <p>Here is how type checkers should handle usage of this library:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">library</span><span class="w"> </span><span class="kn">import</span> <span class="n">Ham</span> <span class="c1"># error: Use of deprecated class Ham. Use Spam instead.</span> <span class="kn">import</span><span class="w"> </span><span class="nn">library</span> <span class="n">library</span><span class="o">.</span><span class="n">norwegian_blue</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># error: Use of deprecated function norwegian_blue. It is pining for the fiords.</span> <span class="nb">map</span><span class="p">(</span><span class="n">library</span><span class="o">.</span><span class="n">norwegian_blue</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span> <span class="c1"># error: Use of deprecated function norwegian_blue. It is pining for the fiords.</span> <span class="n">library</span><span class="o">.</span><span class="n">foo</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># error: Use of deprecated overload for foo. Only str will be allowed.</span> <span class="n">library</span><span class="o">.</span><span class="n">foo</span><span class="p">(</span><span class="s2">"x"</span><span class="p">)</span> <span class="c1"># no error</span> <span class="n">ham</span> <span class="o">=</span> <span class="n">Ham</span><span class="p">()</span> <span class="c1"># no error (already reported above)</span> <span class="n">spam</span> <span class="o">=</span> <span class="n">library</span><span class="o">.</span><span class="n">Spam</span><span class="p">()</span> <span class="n">spam</span> <span class="o">+</span> <span class="mi">1</span> <span class="c1"># error: Use of deprecated method Spam.__add__. There is enough spam in the world.</span> <span class="n">spam</span><span class="o">.</span><span class="n">greasy</span> <span class="c1"># error: Use of deprecated property Spam.greasy. All spam will be equally greasy.</span> <span class="n">spam</span><span class="o">.</span><span class="n">shape</span> <span class="c1"># no error</span> <span class="n">spam</span><span class="o">.</span><span class="n">shape</span> <span class="o">=</span> <span class="s2">"cube"</span> <span class="c1"># error: Use of deprecated property setter Spam.shape. Shapes are becoming immutable.</span> </pre></div> </div> <p>The exact wording of the diagnostics is up to the type checker and is not part of the specification.</p> </section> <section id="runtime-behavior"> <h3><a class="toc-backref" href="#runtime-behavior" role="doc-backlink">Runtime behavior</a></h3> <p>In addition to the positional-only <code class="docutils literal notranslate"><span class="pre">message</span></code> argument, the <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> decorator takes two keyword-only arguments:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">category</span></code>: A warning class. Defaults to <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#DeprecationWarning" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">DeprecationWarning</span></code></a>. If this is set to <code class="docutils literal notranslate"><span class="pre">None</span></code>, no warning is issued at runtime and the decorator returns the original object, except for setting the <code class="docutils literal notranslate"><span class="pre">__deprecated__</span></code> attribute (see below).</li> <li><code class="docutils literal notranslate"><span class="pre">stacklevel</span></code>: The number of stack frames to skip when issuing the warning. Defaults to 1, indicating that the warning should be issued at the site where the deprecated object is called. Internally, the implementation will add the number of stack frames it uses in wrapper code.</li> </ul> <p>If the decorated object is a class, the decorator wraps the <code class="docutils literal notranslate"><span class="pre">__new__</span></code> method such that instantiating the class issues a warning. If the decorated object is a callable, the decorator returns a new callable that wraps the original callable but raises a warning when called. Otherwise, the decorator raises a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> (unless <code class="docutils literal notranslate"><span class="pre">category=None</span></code> is passed).</p> <p>There are several scenarios where use of the decorated object cannot issue a warning, including overloads, <code class="docutils literal notranslate"><span class="pre">Protocol</span></code> classes, and abstract methods. Type checkers may show a warning if <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> is used without <code class="docutils literal notranslate"><span class="pre">category=None</span></code> in these cases.</p> <p>To accommodate runtime introspection, the decorator sets an attribute <code class="docutils literal notranslate"><span class="pre">__deprecated__</span></code> on the object it is passed, as well as on the wrapper callables it generates for deprecated classes and functions. The value of the attribute is the message passed to the decorator. Decorating objects that do not allow setting this attribute is not supported.</p> <p>If a <code class="docutils literal notranslate"><span class="pre">Protocol</span></code> with the <code class="docutils literal notranslate"><span class="pre">@runtime_checkable</span></code> decorator is marked as deprecated, the <code class="docutils literal notranslate"><span class="pre">__deprecated__</span></code> attribute should not be considered a member of the protocol, so its presence should not affect <code class="docutils literal notranslate"><span class="pre">isinstance</span></code> checks.</p> <p>For compatibility with <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.get_overloads" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">typing.get_overloads()</span></code></a>, the <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> decorator should be placed after the <code class="docutils literal notranslate"><span class="pre">@overload</span></code> decorator.</p> </section> <section id="type-checker-behavior"> <h3><a class="toc-backref" href="#type-checker-behavior" role="doc-backlink">Type checker behavior</a></h3> <p>This PEP does not specify exactly how type checkers should present deprecation diagnostics to their users. However, some users (e.g., application developers targeting only a specific version of Python) may not care about deprecations, while others (e.g., library developers who want their library to remain compatible with future versions of Python) would want to catch any use of deprecated functionality in their CI pipeline. Therefore, it is recommended that type checkers provide configuration options that cover both use cases. As with any other type checker error, it is also possible to ignore deprecations using <code class="docutils literal notranslate"><span class="pre">#</span> <span class="pre">type:</span> <span class="pre">ignore</span></code> comments.</p> </section> <section id="deprecation-policy"> <h3><a class="toc-backref" href="#deprecation-policy" role="doc-backlink">Deprecation policy</a></h3> <p>We propose that CPython’s deprecation policy (<a class="pep reference internal" href="../pep-0387/" title="PEP 387 – Backwards Compatibility Policy">PEP 387</a>) is updated to require that new deprecations use the functionality in this PEP to alert users about the deprecation, if possible. Concretely, this means that new deprecations should be accompanied by a change to the <code class="docutils literal notranslate"><span class="pre">typeshed</span></code> repo to add the <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> decorator in the appropriate place. This requirement does not apply to deprecations that cannot be expressed using this PEP’s functionality.</p> </section> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards compatibility</a></h2> <p>Creating a new decorator poses no backwards compatibility concerns. As with all new typing functionality, the <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> decorator will be added to the <code class="docutils literal notranslate"><span class="pre">typing_extensions</span></code> module, enabling its use in older versions of Python.</p> </section> <section id="how-to-teach-this"> <h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How to teach this</a></h2> <p>For users who encounter deprecation warnings in their IDE or type checker output, the messages they receive should be clear and self-explanatory. Usage of the <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> decorator will be an advanced feature mostly relevant to library authors. The decorator should be mentioned in relevant documentation (e.g., <a class="pep reference internal" href="../pep-0387/" title="PEP 387 – Backwards Compatibility Policy">PEP 387</a> and the <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#DeprecationWarning" title="(in Python v3.13)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">DeprecationWarning</span></code></a> documentation) as an additional way to mark deprecated functionality.</p> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference implementation</a></h2> <p>A runtime implementation of the <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> decorator is available in the <a class="reference external" href="https://pypi.org/project/typing-extensions/">typing-extensions</a> library since version 4.5.0. The <code class="docutils literal notranslate"><span class="pre">pyanalyze</span></code> type checker has <a class="reference external" href="https://github.com/quora/pyanalyze/pull/578">prototype support</a> for emitting deprecation errors, as does <a class="reference external" href="https://github.com/microsoft/pyright/issues/4456">Pyright</a>.</p> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected ideas</a></h2> <section id="deprecation-of-modules-and-attributes"> <h3><a class="toc-backref" href="#deprecation-of-modules-and-attributes" role="doc-backlink">Deprecation of modules and attributes</a></h3> <p>This PEP covers deprecations of classes, functions and overloads. This allows type checkers to detect many but not all possible deprecations. To evaluate whether additional functionality would be worthwhile, I <a class="reference external" href="https://gist.github.com/JelleZijlstra/ff459edc5ff0918e22b56740bb28eb8b">examined</a> all current deprecations in the CPython standard library.</p> <p>I found:</p> <ul class="simple"> <li>74 deprecations of functions, methods and classes (supported by this PEP)</li> <li>28 deprecations of whole modules (largely due to <a class="pep reference internal" href="../pep-0594/" title="PEP 594 – Removing dead batteries from the standard library">PEP 594</a>)</li> <li>9 deprecations of function parameters (supported by this PEP through decorating overloads)</li> <li>1 deprecation of a constant</li> <li>38 deprecations that are not easily detectable in the type system (for example, for calling <a class="reference external" href="https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.get_event_loop" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">asyncio.get_event_loop()</span></code></a> without an active event loop)</li> </ul> <p>Modules could be marked as deprecated by adding a <code class="docutils literal notranslate"><span class="pre">__deprecated__</span></code> module-level constant. However, the need for this is limited, and it is relatively easy to detect usage of deprecated modules simply by grepping. Therefore, this PEP omits support for whole-module deprecations. As a workaround, users could mark all module-level classes and functions with <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code>.</p> <p>For deprecating module-level constants, object attributes, and function parameters, a <code class="docutils literal notranslate"><span class="pre">Deprecated[type,</span> <span class="pre">message]</span></code> type modifier, similar to <code class="docutils literal notranslate"><span class="pre">Annotated</span></code> could be added. However, this would create a new place in the type system where strings are just strings, not forward references, complicating the implementation of type checkers. In addition, my data show that this feature is not commonly needed.</p> <p>Features for deprecating more kinds of objects could be added in a future PEP.</p> </section> <section id="placing-the-decorator-in-the-typing-module"> <h3><a class="toc-backref" href="#placing-the-decorator-in-the-typing-module" role="doc-backlink">Placing the decorator in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module</a></h3> <p>An earlier version of this PEP proposed placing the <code class="docutils literal notranslate"><span class="pre">@deprecated</span></code> decorator in the <a class="reference external" href="https://docs.python.org/3/library/typing.html#module-typing" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code></a> module. However, there was feedback that it would be unexpected for a decorator in the <a class="reference external" href="https://docs.python.org/3/library/typing.html#module-typing" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code></a> module to have runtime behavior. Therefore, the PEP now proposes adding the decorator the <a class="reference external" href="https://docs.python.org/3/library/warnings.html#module-warnings" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">warnings</span></code></a> module instead.</p> </section> </section> <section id="acknowledgments"> <h2><a class="toc-backref" href="#acknowledgments" role="doc-backlink">Acknowledgments</a></h2> <p>A call with the typing-sig meetup group led to useful feedback on this proposal.</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0702.rst">https://github.com/python/peps/blob/main/peps/pep-0702.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0702.rst">2024-10-16 16:05:18 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#example">Example</a></li> <li><a class="reference internal" href="#runtime-behavior">Runtime behavior</a></li> <li><a class="reference internal" href="#type-checker-behavior">Type checker behavior</a></li> <li><a class="reference internal" href="#deprecation-policy">Deprecation policy</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards compatibility</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to teach this</a></li> <li><a class="reference internal" href="#reference-implementation">Reference implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected ideas</a><ul> <li><a class="reference internal" href="#deprecation-of-modules-and-attributes">Deprecation of modules and attributes</a></li> <li><a class="reference internal" href="#placing-the-decorator-in-the-typing-module">Placing the decorator in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module</a></li> </ul> </li> <li><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0702.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>