CINXE.COM
PEP 490 – Chain exceptions at C level | 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 490 – Chain exceptions at C level | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0490/"> <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 490 – Chain exceptions at C level | peps.python.org'> <meta property="og:description" content="Chain exceptions at C level, as already done at Python level."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0490/"> <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="Chain exceptions at C level, as already done at Python level."> <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 490</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 490 – Chain exceptions at C level</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Victor Stinner <vstinner at python.org></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</abbr></dd> <dt class="field-odd">Type<span class="colon">:</span></dt> <dd class="field-odd"><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-even">Created<span class="colon">:</span></dt> <dd class="field-even">25-Mar-2015</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.6</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="#rationale">Rationale</a></li> <li><a class="reference internal" href="#proposal">Proposal</a><ul> <li><a class="reference internal" href="#modify-pyerr-functions-to-chain-exceptions">Modify PyErr_*() functions to chain exceptions</a></li> <li><a class="reference internal" href="#modify-functions-to-not-chain-exceptions">Modify functions to not chain exceptions</a></li> <li><a class="reference internal" href="#modify-functions-to-chain-exceptions">Modify functions to chain exceptions</a></li> </ul> </li> <li><a class="reference internal" href="#backward-compatibility">Backward compatibility</a></li> <li><a class="reference internal" href="#alternatives">Alternatives</a><ul> <li><a class="reference internal" href="#no-change">No change</a></li> <li><a class="reference internal" href="#new-helpers-to-chain-exceptions">New helpers to chain exceptions</a></li> </ul> </li> <li><a class="reference internal" href="#appendix">Appendix</a><ul> <li><a class="reference internal" href="#peps">PEPs</a></li> <li><a class="reference internal" href="#python-c-api">Python C API</a></li> <li><a class="reference internal" href="#python-issues">Python Issues</a></li> </ul> </li> <li><a class="reference internal" href="#rejection">Rejection</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>Chain exceptions at C level, as already done at Python level.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Python 3 introduced a new killer feature: exceptions are chained by default, <a class="pep reference internal" href="../pep-3134/" title="PEP 3134 – Exception Chaining and Embedded Tracebacks">PEP 3134</a>.</p> <p>Example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">"err1"</span><span class="p">)</span> <span class="k">except</span> <span class="ne">TypeError</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"err2"</span><span class="p">)</span> </pre></div> </div> <p>Output:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span> <span class="n">File</span> <span class="s2">"test.py"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">2</span><span class="p">,</span> <span class="ow">in</span> <span class="o"><</span><span class="n">module</span><span class="o">></span> <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">"err1"</span><span class="p">)</span> <span class="ne">TypeError</span><span class="p">:</span> <span class="n">err1</span> <span class="n">During</span> <span class="n">handling</span> <span class="n">of</span> <span class="n">the</span> <span class="n">above</span> <span class="n">exception</span><span class="p">,</span> <span class="n">another</span> <span class="n">exception</span> <span class="n">occurred</span><span class="p">:</span> <span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span> <span class="n">File</span> <span class="s2">"test.py"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">4</span><span class="p">,</span> <span class="ow">in</span> <span class="o"><</span><span class="n">module</span><span class="o">></span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"err2"</span><span class="p">)</span> <span class="ne">ValueError</span><span class="p">:</span> <span class="n">err2</span> </pre></div> </div> <p>Exceptions are chained by default in Python code, but not in extensions written in C.</p> <p>A new private <code class="docutils literal notranslate"><span class="pre">_PyErr_ChainExceptions()</span></code> function was introduced in Python 3.4.3 and 3.5 to chain exceptions. Currently, it must be called explicitly to chain exceptions and its usage is not trivial.</p> <p>Example of <code class="docutils literal notranslate"><span class="pre">_PyErr_ChainExceptions()</span></code> usage from the <code class="docutils literal notranslate"><span class="pre">zipimport</span></code> module to chain the previous <code class="docutils literal notranslate"><span class="pre">OSError</span></code> to a new <code class="docutils literal notranslate"><span class="pre">ZipImportError</span></code> exception:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span> <span class="o">*</span><span class="n">exc</span><span class="p">,</span> <span class="o">*</span><span class="n">val</span><span class="p">,</span> <span class="o">*</span><span class="n">tb</span><span class="p">;</span> <span class="n">PyErr_Fetch</span><span class="p">(</span><span class="o">&</span><span class="n">exc</span><span class="p">,</span> <span class="o">&</span><span class="n">val</span><span class="p">,</span> <span class="o">&</span><span class="n">tb</span><span class="p">);</span> <span class="n">PyErr_Format</span><span class="p">(</span><span class="n">ZipImportError</span><span class="p">,</span> <span class="s2">"can't open Zip file: %R"</span><span class="p">,</span> <span class="n">archive</span><span class="p">);</span> <span class="n">_PyErr_ChainExceptions</span><span class="p">(</span><span class="n">exc</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="n">tb</span><span class="p">);</span> </pre></div> </div> <p>This PEP proposes to also chain exceptions automatically at C level to stay consistent and give more information on failures to help debugging. The previous example becomes simply:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyErr_Format</span><span class="p">(</span><span class="n">ZipImportError</span><span class="p">,</span> <span class="s2">"can't open Zip file: %R"</span><span class="p">,</span> <span class="n">archive</span><span class="p">);</span> </pre></div> </div> </section> <section id="proposal"> <h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2> <section id="modify-pyerr-functions-to-chain-exceptions"> <h3><a class="toc-backref" href="#modify-pyerr-functions-to-chain-exceptions" role="doc-backlink">Modify PyErr_*() functions to chain exceptions</a></h3> <p>Modify C functions raising exceptions of the Python C API to automatically chain exceptions: modify <code class="docutils literal notranslate"><span class="pre">PyErr_SetString()</span></code>, <code class="docutils literal notranslate"><span class="pre">PyErr_Format()</span></code>, <code class="docutils literal notranslate"><span class="pre">PyErr_SetNone()</span></code>, etc.</p> </section> <section id="modify-functions-to-not-chain-exceptions"> <h3><a class="toc-backref" href="#modify-functions-to-not-chain-exceptions" role="doc-backlink">Modify functions to not chain exceptions</a></h3> <p>Keeping the previous exception is not always interesting when the new exception contains information of the previous exception or even more information, especially when the two exceptions have the same type.</p> <p>Example of an useless exception chain with <code class="docutils literal notranslate"><span class="pre">int(str)</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="ne">TypeError</span><span class="p">:</span> <span class="n">a</span> <span class="nb">bytes</span><span class="o">-</span><span class="n">like</span> <span class="nb">object</span> <span class="ow">is</span> <span class="n">required</span><span class="p">,</span> <span class="ow">not</span> <span class="s1">'type'</span> <span class="n">During</span> <span class="n">handling</span> <span class="n">of</span> <span class="n">the</span> <span class="n">above</span> <span class="n">exception</span><span class="p">,</span> <span class="n">another</span> <span class="n">exception</span> <span class="n">occurred</span><span class="p">:</span> <span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span> <span class="n">File</span> <span class="s2">"<stdin>"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o"><</span><span class="n">module</span><span class="o">></span> <span class="ne">TypeError</span><span class="p">:</span> <span class="nb">int</span><span class="p">()</span> <span class="n">argument</span> <span class="n">must</span> <span class="n">be</span> <span class="n">a</span> <span class="n">string</span><span class="p">,</span> <span class="n">a</span> <span class="nb">bytes</span><span class="o">-</span><span class="n">like</span> <span class="nb">object</span> <span class="ow">or</span> <span class="n">a</span> <span class="n">number</span><span class="p">,</span> <span class="ow">not</span> <span class="s1">'type'</span> </pre></div> </div> <p>The new <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> exception contains more information than the previous exception. The previous exception should be hidden.</p> <p>The <code class="docutils literal notranslate"><span class="pre">PyErr_Clear()</span></code> function can be called to clear the current exception before raising a new exception, to not chain the current exception with a new exception.</p> </section> <section id="modify-functions-to-chain-exceptions"> <h3><a class="toc-backref" href="#modify-functions-to-chain-exceptions" role="doc-backlink">Modify functions to chain exceptions</a></h3> <p>Some functions save and then restore the current exception. If a new exception is raised, the exception is currently displayed into sys.stderr or ignored depending on the function. Some of these functions should be modified to chain exceptions instead.</p> <p>Examples of function ignoring the new exception(s):</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">ptrace_enter_call()</span></code>: ignore exception</li> <li><code class="docutils literal notranslate"><span class="pre">subprocess_fork_exec()</span></code>: ignore exception raised by enable_gc()</li> <li><code class="docutils literal notranslate"><span class="pre">t_bootstrap()</span></code> of the <code class="docutils literal notranslate"><span class="pre">_thread</span></code> module: ignore exception raised by trying to display the bootstrap function to <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyDict_GetItem()</span></code>, <code class="docutils literal notranslate"><span class="pre">_PyDict_GetItem_KnownHash()</span></code>: ignore exception raised by looking for a key in the dictionary</li> <li><code class="docutils literal notranslate"><span class="pre">_PyErr_TrySetFromCause()</span></code>: ignore exception</li> <li><code class="docutils literal notranslate"><span class="pre">PyFrame_LocalsToFast()</span></code>: ignore exception raised by <code class="docutils literal notranslate"><span class="pre">dict_to_map()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">_PyObject_Dump()</span></code>: ignore exception. <code class="docutils literal notranslate"><span class="pre">_PyObject_Dump()</span></code> is used to debug, to inspect a running process, it should not modify the Python state.</li> <li><code class="docutils literal notranslate"><span class="pre">Py_ReprLeave()</span></code>: ignore exception “because there is no way to report them”</li> <li><code class="docutils literal notranslate"><span class="pre">type_dealloc()</span></code>: ignore exception raised by <code class="docutils literal notranslate"><span class="pre">remove_all_subclasses()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyObject_ClearWeakRefs()</span></code>: ignore exception?</li> <li><code class="docutils literal notranslate"><span class="pre">call_exc_trace()</span></code>, <code class="docutils literal notranslate"><span class="pre">call_trace_protected()</span></code>: ignore exception</li> <li><code class="docutils literal notranslate"><span class="pre">remove_importlib_frames()</span></code>: ignore exception</li> <li><code class="docutils literal notranslate"><span class="pre">do_mktuple()</span></code>, helper used by <code class="docutils literal notranslate"><span class="pre">Py_BuildValue()</span></code> for example: ignore exception?</li> <li><code class="docutils literal notranslate"><span class="pre">flush_io()</span></code>: ignore exception</li> <li><code class="docutils literal notranslate"><span class="pre">sys_write()</span></code>, <code class="docutils literal notranslate"><span class="pre">sys_format()</span></code>: ignore exception</li> <li><code class="docutils literal notranslate"><span class="pre">_PyTraceback_Add()</span></code>: ignore exception</li> <li><code class="docutils literal notranslate"><span class="pre">PyTraceBack_Print()</span></code>: ignore exception</li> </ul> <p>Examples of function displaying the new exception to <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code>:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">atexit_callfuncs()</span></code>: display exceptions with <code class="docutils literal notranslate"><span class="pre">PyErr_Display()</span></code> and return the latest exception, the function calls multiple callbacks and only returns the latest exception</li> <li><code class="docutils literal notranslate"><span class="pre">sock_dealloc()</span></code>: log the <code class="docutils literal notranslate"><span class="pre">ResourceWarning</span></code> exception with <code class="docutils literal notranslate"><span class="pre">PyErr_WriteUnraisable()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">slot_tp_del()</span></code>: display exception with <code class="docutils literal notranslate"><span class="pre">PyErr_WriteUnraisable()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">_PyGen_Finalize()</span></code>: display <code class="docutils literal notranslate"><span class="pre">gen_close()</span></code> exception with <code class="docutils literal notranslate"><span class="pre">PyErr_WriteUnraisable()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">slot_tp_finalize()</span></code>: display exception raised by the <code class="docutils literal notranslate"><span class="pre">__del__()</span></code> method with <code class="docutils literal notranslate"><span class="pre">PyErr_WriteUnraisable()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_GivenExceptionMatches()</span></code>: display exception raised by <code class="docutils literal notranslate"><span class="pre">PyType_IsSubtype()</span></code> with <code class="docutils literal notranslate"><span class="pre">PyErr_WriteUnraisable()</span></code></li> </ul> </section> </section> <section id="backward-compatibility"> <h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward compatibility</a></h2> <p>A side effect of chaining exceptions is that exceptions store traceback objects which store frame objects which store local variables. Local variables are kept alive by exceptions. A common issue is a reference cycle between local variables and exceptions: an exception is stored in a local variable and the frame indirectly stored in the exception. The cycle only impacts applications storing exceptions.</p> <p>The reference cycle can now be fixed with the new <code class="docutils literal notranslate"><span class="pre">traceback.TracebackException</span></code> object introduced in Python 3.5. It stores information required to format a full textual traceback without storing local variables.</p> <p>The <code class="docutils literal notranslate"><span class="pre">asyncio</span></code> is impacted by the reference cycle issue. This module is also maintained outside Python standard library to release a version for Python 3.3. <code class="docutils literal notranslate"><span class="pre">traceback.TracebackException</span></code> will maybe be backported in a private <code class="docutils literal notranslate"><span class="pre">asyncio</span></code> module to fix reference cycle issues.</p> </section> <section id="alternatives"> <h2><a class="toc-backref" href="#alternatives" role="doc-backlink">Alternatives</a></h2> <section id="no-change"> <h3><a class="toc-backref" href="#no-change" role="doc-backlink">No change</a></h3> <p>A new private <code class="docutils literal notranslate"><span class="pre">_PyErr_ChainExceptions()</span></code> function is enough to chain manually exceptions.</p> <p>Exceptions will only be chained explicitly where it makes sense.</p> </section> <section id="new-helpers-to-chain-exceptions"> <h3><a class="toc-backref" href="#new-helpers-to-chain-exceptions" role="doc-backlink">New helpers to chain exceptions</a></h3> <p>Functions like <code class="docutils literal notranslate"><span class="pre">PyErr_SetString()</span></code> don’t chain automatically exceptions. To make the usage of <code class="docutils literal notranslate"><span class="pre">_PyErr_ChainExceptions()</span></code> easier, new private functions are added:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">_PyErr_SetStringChain(exc_type,</span> <span class="pre">message)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">_PyErr_FormatChain(exc_type,</span> <span class="pre">format,</span> <span class="pre">...)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">_PyErr_SetNoneChain(exc_type)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">_PyErr_SetObjectChain(exc_type,</span> <span class="pre">exc_value)</span></code></li> </ul> <p>Helper functions to raise specific exceptions like <code class="docutils literal notranslate"><span class="pre">_PyErr_SetKeyError(key)</span></code> or <code class="docutils literal notranslate"><span class="pre">PyErr_SetImportError(message,</span> <span class="pre">name,</span> <span class="pre">path)</span></code> don’t chain exceptions. The generic <code class="docutils literal notranslate"><span class="pre">_PyErr_ChainExceptions(exc_type,</span> <span class="pre">exc_value,</span> <span class="pre">exc_tb)</span></code> should be used to chain exceptions with these helper functions.</p> </section> </section> <section id="appendix"> <h2><a class="toc-backref" href="#appendix" role="doc-backlink">Appendix</a></h2> <section id="peps"> <h3><a class="toc-backref" href="#peps" role="doc-backlink">PEPs</a></h3> <ul class="simple"> <li><a class="pep reference internal" href="../pep-3134/" title="PEP 3134 – Exception Chaining and Embedded Tracebacks">PEP 3134</a> – Exception Chaining and Embedded Tracebacks (Python 3.0): new <code class="docutils literal notranslate"><span class="pre">__context__</span></code> and <code class="docutils literal notranslate"><span class="pre">__cause__</span></code> attributes for exceptions</li> <li><a class="pep reference internal" href="../pep-0415/" title="PEP 415 – Implement context suppression with exception attributes">PEP 415</a> – Implement context suppression with exception attributes (Python 3.3): <code class="docutils literal notranslate"><span class="pre">raise</span> <span class="pre">exc</span> <span class="pre">from</span> <span class="pre">None</span></code></li> <li><a class="pep reference internal" href="../pep-0409/" title="PEP 409 – Suppressing exception context">PEP 409</a> – Suppressing exception context (superseded by the <a class="pep reference internal" href="../pep-0415/" title="PEP 415 – Implement context suppression with exception attributes">PEP 415</a>)</li> </ul> </section> <section id="python-c-api"> <h3><a class="toc-backref" href="#python-c-api" role="doc-backlink">Python C API</a></h3> <p>The header file <code class="docutils literal notranslate"><span class="pre">Include/pyerror.h</span></code> declares functions related to exceptions.</p> <p>Functions raising exceptions:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">PyErr_SetNone(exc_type)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_SetObject(exc_type,</span> <span class="pre">exc_value)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_SetString(exc_type,</span> <span class="pre">message)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_Format(exc,</span> <span class="pre">format,</span> <span class="pre">...)</span></code></li> </ul> <p>Helpers to raise specific exceptions:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">PyErr_BadArgument()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_BadInternalCall()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_NoMemory()</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_SetFromErrno(exc)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_SetFromWindowsErr(err)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_SetImportError(message,</span> <span class="pre">name,</span> <span class="pre">path)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">_PyErr_SetKeyError(key)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">_PyErr_TrySetFromCause(prefix_format,</span> <span class="pre">...)</span></code></li> </ul> <p>Manage the current exception:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">PyErr_Clear()</span></code>: clear the current exception, like <code class="docutils literal notranslate"><span class="pre">except:</span> <span class="pre">pass</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_Fetch(exc_type,</span> <span class="pre">exc_value,</span> <span class="pre">exc_tb)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_Restore(exc_type,</span> <span class="pre">exc_value,</span> <span class="pre">exc_tb)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_GetExcInfo(exc_type,</span> <span class="pre">exc_value,</span> <span class="pre">exc_tb)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_SetExcInfo(exc_type,</span> <span class="pre">exc_value,</span> <span class="pre">exc_tb)</span></code></li> </ul> <p>Others function to handle exceptions:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">PyErr_ExceptionMatches(exc)</span></code>: check to implement <code class="docutils literal notranslate"><span class="pre">except</span> <span class="pre">exc:</span>  <span class="pre">...</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_GivenExceptionMatches(exc1,</span> <span class="pre">exc2)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">PyErr_NormalizeException(exc_type,</span> <span class="pre">exc_value,</span> <span class="pre">exc_tb)</span></code></li> <li><code class="docutils literal notranslate"><span class="pre">_PyErr_ChainExceptions(exc_type,</span> <span class="pre">exc_value,</span> <span class="pre">exc_tb)</span></code></li> </ul> </section> <section id="python-issues"> <h3><a class="toc-backref" href="#python-issues" role="doc-backlink">Python Issues</a></h3> <p>Chain exceptions:</p> <ul class="simple"> <li><a class="reference external" href="http://bugs.python.org/issue23763">Issue #23763: Chain exceptions in C</a></li> <li><a class="reference external" href="http://bugs.python.org/issue23696">Issue #23696: zipimport: chain ImportError to OSError</a></li> <li><a class="reference external" href="http://bugs.python.org/issue21715">Issue #21715: Chaining exceptions at C level</a>: added <code class="docutils literal notranslate"><span class="pre">_PyErr_ChainExceptions()</span></code></li> <li><a class="reference external" href="http://bugs.python.org/issue18488">Issue #18488: sqlite: finalize() method of user function may be called with an exception set if a call to step() method failed</a></li> <li><a class="reference external" href="http://bugs.python.org/issue23781">Issue #23781: Add private _PyErr_ReplaceException() in 2.7</a></li> <li><a class="reference external" href="http://bugs.python.org/issue23782">Issue #23782: Leak in _PyTraceback_Add</a></li> </ul> <p>Changes preventing to loose exceptions:</p> <ul class="simple"> <li><a class="reference external" href="http://bugs.python.org/issue23571">Issue #23571: Raise SystemError if a function returns a result with an exception set</a></li> <li><a class="reference external" href="http://bugs.python.org/issue18408">Issue #18408: Fixes crashes found by pyfailmalloc</a></li> </ul> </section> </section> <section id="rejection"> <h2><a class="toc-backref" href="#rejection" role="doc-backlink">Rejection</a></h2> <p>The PEP was rejected on 2017-09-12 by Victor Stinner. It was decided in the python-dev discussion to not chain C exceptions by default, but instead chain them explicitly only where it makes sense.</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document has been placed in the public domain.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0490.rst">https://github.com/python/peps/blob/main/peps/pep-0490.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0490.rst">2025-02-01 08:59:27 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="#rationale">Rationale</a></li> <li><a class="reference internal" href="#proposal">Proposal</a><ul> <li><a class="reference internal" href="#modify-pyerr-functions-to-chain-exceptions">Modify PyErr_*() functions to chain exceptions</a></li> <li><a class="reference internal" href="#modify-functions-to-not-chain-exceptions">Modify functions to not chain exceptions</a></li> <li><a class="reference internal" href="#modify-functions-to-chain-exceptions">Modify functions to chain exceptions</a></li> </ul> </li> <li><a class="reference internal" href="#backward-compatibility">Backward compatibility</a></li> <li><a class="reference internal" href="#alternatives">Alternatives</a><ul> <li><a class="reference internal" href="#no-change">No change</a></li> <li><a class="reference internal" href="#new-helpers-to-chain-exceptions">New helpers to chain exceptions</a></li> </ul> </li> <li><a class="reference internal" href="#appendix">Appendix</a><ul> <li><a class="reference internal" href="#peps">PEPs</a></li> <li><a class="reference internal" href="#python-c-api">Python C API</a></li> <li><a class="reference internal" href="#python-issues">Python Issues</a></li> </ul> </li> <li><a class="reference internal" href="#rejection">Rejection</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-0490.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>