python-peps/pep-0626/index.html

479 lines
39 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 626 Precise line numbers for debugging and other tools. | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0626/">
<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 626 Precise line numbers for debugging and other tools. | peps.python.org'>
<meta property="og:description" content="Python should guarantee that when tracing is turned on, “line” tracing events are generated for all lines of code executed and only for lines of code that are executed.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0626/">
<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="Python should guarantee that when tracing is turned on, “line” tracing events are generated for all lines of code executed and only for lines of code that are executed.">
<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> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 626</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 626 Precise line numbers for debugging and other tools.</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Mark Shannon &lt;mark&#32;&#97;t&#32;hotpy.org&gt;</dd>
<dt class="field-even">BDFL-Delegate<span class="colon">:</span></dt>
<dd class="field-even">Pablo Galindo &lt;pablogsal&#32;&#97;t&#32;python.org&gt;</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">Created<span class="colon">:</span></dt>
<dd class="field-odd">15-Jul-2020</dd>
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
<dd class="field-even">3.10</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd">17-Jul-2020</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="#tracing">Tracing</a></li>
<li><a class="reference internal" href="#what-is-considered-to-be-code-for-the-purposes-of-tracing">What is considered to be code for the purposes of tracing</a></li>
<li><a class="reference internal" href="#example-event-sequences">Example event sequences</a></li>
<li><a class="reference internal" href="#the-f-lineno-attribute">The f_lineno attribute</a></li>
<li><a class="reference internal" href="#the-new-co-lines-method-of-code-objects">The new co_lines() method of code objects</a><ul>
<li><a class="reference internal" href="#zero-width-ranges">Zero width ranges</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-co-linetable-attribute">The co_linetable attribute</a></li>
<li><a class="reference internal" href="#the-co-lnotab-attribute">The co_lnotab attribute</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
<li><a class="reference internal" href="#examples-of-code-for-which-the-sequence-of-trace-events-will-change">Examples of code for which the sequence of trace events will change</a><ul>
<li><a class="reference internal" href="#pass-statement-in-an-if-statement"><code class="docutils literal notranslate"><span class="pre">pass</span></code> statement in an <code class="docutils literal notranslate"><span class="pre">if</span></code> statement.</a></li>
<li><a class="reference internal" href="#multiple-pass-statements">Multiple <code class="docutils literal notranslate"><span class="pre">pass</span></code> statements.</a></li>
</ul>
</li>
<li><a class="reference internal" href="#c-api">C API</a></li>
<li><a class="reference internal" href="#out-of-process-debuggers-and-profilers">Out of process debuggers and profilers</a></li>
</ul>
</li>
<li><a class="reference internal" href="#performance-implications">Performance Implications</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
<li><a class="reference internal" href="#references">References</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>Python should guarantee that when tracing is turned on, “line” tracing events are generated for <em>all</em> lines of code executed and <em>only</em> for lines of
code that are executed.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> attribute of frame objects should always contain the expected line number.
During frame execution, the expected line number is the line number of source code currently being executed.
After a frame has completed, either by returning or by raising an exception,
the expected line number is the line number of the last line of source that was executed.</p>
<p>A side effect of ensuring correct line numbers, is that some bytecodes will need to be marked as artificial, and not have a meaningful line number.
To assist tools, a new <code class="docutils literal notranslate"><span class="pre">co_lines</span></code> attribute will be added that describes the mapping from bytecode to source.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>Users of <code class="docutils literal notranslate"><span class="pre">sys.settrace</span></code> and associated tools should be able to rely on tracing events being
generated for all lines of code, and only for actual code.
They should also be able to assume that the line number in <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> is correct.</p>
<p>The current implementation mostly does this, but fails in a few cases.
This requires workarounds in tooling and is a nuisance for alternative Python implementations.</p>
<p>Having this guarantee also benefits implementers of CPython in the long term, as the current behaviour is not obvious and has some odd corner cases.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>In order to guarantee that line events are generated when expected, the <code class="docutils literal notranslate"><span class="pre">co_lnotab</span></code> attribute, in its current form,
can no longer be the source of truth for line number information.</p>
<p>Rather than attempt to fix the <code class="docutils literal notranslate"><span class="pre">co_lnotab</span></code> attribute, a new method
<code class="docutils literal notranslate"><span class="pre">co_lines()</span></code> will be added, which returns an iterator over bytecode offsets and source code lines.</p>
<p>Ensuring that the bytecode is annotated correctly to enable accurate line number information means that
some bytecodes must be marked as artificial, and not have a line number.</p>
<p>Some care must be taken not to break existing tooling.
To minimize breakage, the <code class="docutils literal notranslate"><span class="pre">co_lnotab</span></code> attribute will be retained, but lazily generated on demand.</p>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>Line events and the <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> attribute should act as an experienced Python user would expect in <em>all</em> cases.</p>
<section id="tracing">
<h3><a class="toc-backref" href="#tracing" role="doc-backlink">Tracing</a></h3>
<p>Tracing generates events for calls, returns, exceptions, lines of source code executed, and, under some circumstances, instructions executed.</p>
<p>Only line events are covered by this PEP.</p>
<p>When tracing is turned on, line events will be generated when:</p>
<ul class="simple">
<li>A new line of source code is reached.</li>
<li>A backwards jump occurs, even if it jumps to the same line, as may happen in list comprehensions.</li>
</ul>
<p>Additionally, line events will <em>never</em> be generated for source code lines that are not executed.</p>
</section>
<section id="what-is-considered-to-be-code-for-the-purposes-of-tracing">
<h3><a class="toc-backref" href="#what-is-considered-to-be-code-for-the-purposes-of-tracing" role="doc-backlink">What is considered to be code for the purposes of tracing</a></h3>
<p>All expressions and parts of expressions are considered to be executable code.</p>
<p>In general, all statements are also considered to be executable code. However, when a statement is spread over several lines,
we must consider which parts of a statement are considered to be executable code.</p>
<p>Statements are made up of keywords and expressions. Not all keywords have a direct runtime effect, so not all keywords are considered to be executable code.
For example, <code class="docutils literal notranslate"><span class="pre">else</span></code>, is a necessary part of an <code class="docutils literal notranslate"><span class="pre">if</span></code> statement, but there is no runtime effect associated with an <code class="docutils literal notranslate"><span class="pre">else</span></code>.</p>
<p>For the purposes of tracing, the following keywords will <em>not</em> be considered to be executable code:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">del</span></code> The expression to be deleted is treated as the executable code.</li>
<li><code class="docutils literal notranslate"><span class="pre">else</span></code> No runtime effect</li>
<li><code class="docutils literal notranslate"><span class="pre">finally</span></code> No runtime effect</li>
<li><code class="docutils literal notranslate"><span class="pre">global</span></code> Purely declarative</li>
<li><code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> Purely declarative</li>
</ul>
<p>All other keywords are considered to be executable code.</p>
</section>
<section id="example-event-sequences">
<h3><a class="toc-backref" href="#example-event-sequences" role="doc-backlink">Example event sequences</a></h3>
<p>In the following examples, events are listed as “name”, <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> pairs.</p>
<p>The code</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">1.</span> <span class="k">global</span> <span class="n">x</span>
<span class="mf">2.</span> <span class="n">x</span> <span class="o">=</span> <span class="n">a</span>
</pre></div>
</div>
<p>generates the following event:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;line&quot;</span> <span class="mi">2</span>
</pre></div>
</div>
<p>The code</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">1.</span> <span class="k">try</span><span class="p">:</span>
<span class="mf">2.</span> <span class="k">pass</span>
<span class="mf">3.</span> <span class="k">finally</span><span class="p">:</span>
<span class="mf">4.</span> <span class="k">pass</span>
</pre></div>
</div>
<p>generates the following events:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;line&quot;</span> <span class="mi">1</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">2</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">4</span>
</pre></div>
</div>
<p>The code</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">1.</span> <span class="k">for</span> <span class="p">(</span>
<span class="mf">2.</span> <span class="n">x</span><span class="p">)</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="mf">3.</span> <span class="k">pass</span>
<span class="mf">4.</span> <span class="k">return</span>
</pre></div>
</div>
<p>generates the following events:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;line&quot;</span> <span class="mi">2</span> <span class="c1"># evaluate [1]</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">1</span> <span class="c1"># for</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">2</span> <span class="c1"># store to x</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">3</span> <span class="c1"># pass</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">1</span> <span class="c1"># for</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">4</span> <span class="c1"># return</span>
<span class="s2">&quot;return&quot;</span> <span class="mi">1</span>
</pre></div>
</div>
</section>
<section id="the-f-lineno-attribute">
<h3><a class="toc-backref" href="#the-f-lineno-attribute" role="doc-backlink">The f_lineno attribute</a></h3>
<ul class="simple">
<li>When a frame object is created, the <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> attribute will be set to the line
at which the function or class is defined; that is the line on which the <code class="docutils literal notranslate"><span class="pre">def</span></code> or <code class="docutils literal notranslate"><span class="pre">class</span></code> keyword appears.
For modules it will be set to zero.</li>
<li>The <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> attribute will be updated to match the line number about to be executed,
even if tracing is turned off and no event is generated.</li>
</ul>
</section>
<section id="the-new-co-lines-method-of-code-objects">
<h3><a class="toc-backref" href="#the-new-co-lines-method-of-code-objects" role="doc-backlink">The new co_lines() method of code objects</a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">co_lines()</span></code> method will return an iterator which yields tuples of values,
each representing the line number of a range of bytecodes. Each tuple will consist of three values:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">start</span></code> The offset (inclusive) of the start of the bytecode range</li>
<li><code class="docutils literal notranslate"><span class="pre">end</span></code> The offset (exclusive) of the end of the bytecode range</li>
<li><code class="docutils literal notranslate"><span class="pre">line</span></code> The line number, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if the bytecodes in the given range do not have a line number.</li>
</ul>
<p>The sequence generated will have the following properties:</p>
<ul class="simple">
<li>The first range in the sequence with have a <code class="docutils literal notranslate"><span class="pre">start</span></code> of <code class="docutils literal notranslate"><span class="pre">0</span></code></li>
<li>The <code class="docutils literal notranslate"><span class="pre">(start,</span> <span class="pre">end)</span></code> ranges will be non-decreasing and consecutive.
That is, for any pair of tuples the <code class="docutils literal notranslate"><span class="pre">start</span></code> of the second
will equal to the <code class="docutils literal notranslate"><span class="pre">end</span></code> of the first.</li>
<li>No range will be backwards, that is <code class="docutils literal notranslate"><span class="pre">end</span> <span class="pre">&gt;=</span> <span class="pre">start</span></code> for all triples.</li>
<li>The final range in the sequence with have <code class="docutils literal notranslate"><span class="pre">end</span></code> equal to the size of the bytecode.</li>
<li><code class="docutils literal notranslate"><span class="pre">line</span></code> will either be a positive integer, or <code class="docutils literal notranslate"><span class="pre">None</span></code></li>
</ul>
<section id="zero-width-ranges">
<h4><a class="toc-backref" href="#zero-width-ranges" role="doc-backlink">Zero width ranges</a></h4>
<p>Zero width range, that is ranges where <code class="docutils literal notranslate"><span class="pre">start</span> <span class="pre">==</span> <span class="pre">end</span></code> are allowed.
Zero width ranges are used for lines that are present in the source code,
but have been eliminated by the bytecode compiler.</p>
</section>
</section>
<section id="the-co-linetable-attribute">
<h3><a class="toc-backref" href="#the-co-linetable-attribute" role="doc-backlink">The co_linetable attribute</a></h3>
<p>The co_linetable attribute will hold the line number information.
The format is opaque, unspecified and may be changed without notice.
The attribute is public only to support creation of new code objects.</p>
</section>
<section id="the-co-lnotab-attribute">
<h3><a class="toc-backref" href="#the-co-lnotab-attribute" role="doc-backlink">The co_lnotab attribute</a></h3>
<p>Historically the <code class="docutils literal notranslate"><span class="pre">co_lnotab</span></code> attribute held a mapping from bytecode offset to line number, but does not support bytecodes without a line number.
For backward compatibility, the <code class="docutils literal notranslate"><span class="pre">co_lnotab</span></code> bytes object will be lazily created when needed.
For ranges of bytecodes without a line number, the line number of the previous bytecode range will be used.</p>
<p>Tools that parse the <code class="docutils literal notranslate"><span class="pre">co_lnotab</span></code> table should move to using the new <code class="docutils literal notranslate"><span class="pre">co_lines()</span></code> method as soon as is practical.</p>
</section>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">co_lnotab</span></code> attribute will be deprecated in 3.10 and removed in 3.12.</p>
<p>Any tools that parse the <code class="docutils literal notranslate"><span class="pre">co_lnotab</span></code> attribute of code objects will need to move to using <code class="docutils literal notranslate"><span class="pre">co_lines()</span></code> before 3.12 is released.
Tools that use <code class="docutils literal notranslate"><span class="pre">sys.settrace</span></code> will be unaffected, except in cases where the “line” events they receive are more accurate.</p>
<section id="examples-of-code-for-which-the-sequence-of-trace-events-will-change">
<h3><a class="toc-backref" href="#examples-of-code-for-which-the-sequence-of-trace-events-will-change" role="doc-backlink">Examples of code for which the sequence of trace events will change</a></h3>
<p>In the following examples, events are listed as “name”, <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> pairs.</p>
<section id="pass-statement-in-an-if-statement">
<h4><a class="toc-backref" href="#pass-statement-in-an-if-statement" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">pass</span></code> statement in an <code class="docutils literal notranslate"><span class="pre">if</span></code> statement.</a></h4>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">0.</span> <span class="k">def</span> <span class="nf">spam</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
<span class="mf">1.</span> <span class="k">if</span> <span class="n">a</span><span class="p">:</span>
<span class="mf">2.</span> <span class="n">eggs</span><span class="p">()</span>
<span class="mf">3.</span> <span class="k">else</span><span class="p">:</span>
<span class="mf">4.</span> <span class="k">pass</span>
</pre></div>
</div>
<p>If <code class="docutils literal notranslate"><span class="pre">a</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code>, then the sequence of events generated by Python 3.9 is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;line&quot;</span> <span class="mi">1</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">2</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">4</span>
<span class="s2">&quot;return&quot;</span> <span class="mi">4</span>
</pre></div>
</div>
<p>From 3.10 the sequence will be:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;line&quot;</span> <span class="mi">1</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">2</span>
<span class="s2">&quot;return&quot;</span> <span class="mi">2</span>
</pre></div>
</div>
</section>
<section id="multiple-pass-statements">
<h4><a class="toc-backref" href="#multiple-pass-statements" role="doc-backlink">Multiple <code class="docutils literal notranslate"><span class="pre">pass</span></code> statements.</a></h4>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mf">0.</span> <span class="k">def</span> <span class="nf">bar</span><span class="p">():</span>
<span class="mf">1.</span> <span class="k">pass</span>
<span class="mf">2.</span> <span class="k">pass</span>
<span class="mf">3.</span> <span class="k">pass</span>
</pre></div>
</div>
<p>The sequence of events generated by Python 3.9 is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;line&quot;</span> <span class="mi">3</span>
<span class="s2">&quot;return&quot;</span> <span class="mi">3</span>
</pre></div>
</div>
<p>From 3.10 the sequence will be:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;line&quot;</span> <span class="mi">1</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">2</span>
<span class="s2">&quot;line&quot;</span> <span class="mi">3</span>
<span class="s2">&quot;return&quot;</span> <span class="mi">3</span>
</pre></div>
</div>
</section>
</section>
<section id="c-api">
<h3><a class="toc-backref" href="#c-api" role="doc-backlink">C API</a></h3>
<p>Access to the <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> attribute of frame objects through C API functions is unchanged.
<code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> can be read by <code class="docutils literal notranslate"><span class="pre">PyFrame_GetLineNumber</span></code>. <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> can only be set via <code class="docutils literal notranslate"><span class="pre">PyObject_SetAttr</span></code> and similar functions.</p>
<p>Accessing <code class="docutils literal notranslate"><span class="pre">f_lineno</span></code> directly through the underlying data structure is forbidden.</p>
</section>
<section id="out-of-process-debuggers-and-profilers">
<h3><a class="toc-backref" href="#out-of-process-debuggers-and-profilers" role="doc-backlink">Out of process debuggers and profilers</a></h3>
<p>Out of process tools, such as py-spy <a class="footnote-reference brackets" href="#id2" id="id1">[1]</a>, cannot use the C-API, and must parse the line number table themselves.
Although the line number table format may change without warning,
it will not change during a release unless absolutely necessary for a bug fix.</p>
<p>To reduce the work required to implement these tools, the following C struct and utility functions are provided.
Note that these functions are not part of the C-API, so will be need to be linked into any code that needs to use them.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">typedef</span> <span class="n">struct</span> <span class="n">addressrange</span> <span class="p">{</span>
<span class="nb">int</span> <span class="n">ar_start</span><span class="p">;</span>
<span class="nb">int</span> <span class="n">ar_end</span><span class="p">;</span>
<span class="nb">int</span> <span class="n">ar_line</span><span class="p">;</span>
<span class="n">struct</span> <span class="n">_opaque</span> <span class="n">opaque</span><span class="p">;</span>
<span class="p">}</span> <span class="n">PyCodeAddressRange</span><span class="p">;</span>
<span class="n">void</span> <span class="n">PyLineTable_InitAddressRange</span><span class="p">(</span><span class="n">char</span> <span class="o">*</span><span class="n">linetable</span><span class="p">,</span> <span class="n">Py_ssize_t</span> <span class="n">length</span><span class="p">,</span> <span class="nb">int</span> <span class="n">firstlineno</span><span class="p">,</span> <span class="n">PyCodeAddressRange</span> <span class="o">*</span><span class="nb">range</span><span class="p">);</span>
<span class="nb">int</span> <span class="n">PyLineTable_NextAddressRange</span><span class="p">(</span><span class="n">PyCodeAddressRange</span> <span class="o">*</span><span class="nb">range</span><span class="p">);</span>
<span class="nb">int</span> <span class="n">PyLineTable_PreviousAddressRange</span><span class="p">(</span><span class="n">PyCodeAddressRange</span> <span class="o">*</span><span class="nb">range</span><span class="p">);</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">PyLineTable_InitAddressRange</span></code> initializes the <code class="docutils literal notranslate"><span class="pre">PyCodeAddressRange</span></code> struct from the line number table and first line number.</p>
<p><code class="docutils literal notranslate"><span class="pre">PyLineTable_NextAddressRange</span></code> advances the range to the next entry, returning non-zero if valid.</p>
<p><code class="docutils literal notranslate"><span class="pre">PyLineTable_PreviousAddressRange</span></code> retreats the range to the previous entry, returning non-zero if valid.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The data in <code class="docutils literal notranslate"><span class="pre">linetable</span></code> is immutable, but its lifetime depends on its code object.
For reliable operation, <code class="docutils literal notranslate"><span class="pre">linetable</span></code> should be copied into a local buffer before calling <code class="docutils literal notranslate"><span class="pre">PyLineTable_InitAddressRange</span></code>.</p>
</div>
<p>Although these functions are not part of C-API, they will provided by all future versions of CPython.
The <code class="docutils literal notranslate"><span class="pre">PyLineTable_</span></code> functions do not call into the C-API, so can be safely copied into any tool that needs to use them.
The <code class="docutils literal notranslate"><span class="pre">PyCodeAddressRange</span></code> struct will not be changed, but the <code class="docutils literal notranslate"><span class="pre">_opaque</span></code> struct is not part of the specification and may change.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The <code class="docutils literal notranslate"><span class="pre">PyCodeAddressRange</span></code> struct has changed from the original version of this PEP, where the addition fields were defined, but
were liable to change.</p>
</div>
<p>For example, the following code prints out all the address ranges:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">void</span> <span class="n">print_address_ranges</span><span class="p">(</span><span class="n">char</span> <span class="o">*</span><span class="n">linetable</span><span class="p">,</span> <span class="n">Py_ssize_t</span> <span class="n">length</span><span class="p">,</span> <span class="nb">int</span> <span class="n">firstlineno</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">PyCodeAddressRange</span> <span class="nb">range</span><span class="p">;</span>
<span class="n">PyLineTable_InitAddressRange</span><span class="p">(</span><span class="n">linetable</span><span class="p">,</span> <span class="n">length</span><span class="p">,</span> <span class="n">firstlineno</span><span class="p">,</span> <span class="o">&amp;</span><span class="nb">range</span><span class="p">);</span>
<span class="k">while</span> <span class="p">(</span><span class="n">PyLineTable_NextAddressRange</span><span class="p">(</span><span class="o">&amp;</span><span class="nb">range</span><span class="p">))</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s2">&quot;Bytecodes from </span><span class="si">%d</span><span class="s2"> (inclusive) to </span><span class="si">%d</span><span class="s2"> (exclusive) &quot;</span><span class="p">,</span>
<span class="nb">range</span><span class="o">.</span><span class="n">start</span><span class="p">,</span> <span class="nb">range</span><span class="o">.</span><span class="n">end</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">range</span><span class="o">.</span><span class="n">line</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="o">/*</span> <span class="n">line</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="n">means</span> <span class="n">no</span> <span class="n">line</span> <span class="n">number</span> <span class="o">*/</span>
<span class="n">printf</span><span class="p">(</span><span class="s2">&quot;have no line number</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s2">&quot;have line number </span><span class="si">%d</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span> <span class="nb">range</span><span class="o">.</span><span class="n">line</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</section>
</section>
<section id="performance-implications">
<h2><a class="toc-backref" href="#performance-implications" role="doc-backlink">Performance Implications</a></h2>
<p>In general, there should be no change in performance.
When tracing, programs should run a little faster as the new table format can be designed with line number calculation speed in mind.
Code with long sequences of <code class="docutils literal notranslate"><span class="pre">pass</span></code> statements will probably become a bit slower.</p>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p><a class="reference external" href="https://github.com/markshannon/cpython/tree/new-linetable-format-version-2">https://github.com/markshannon/cpython/tree/new-linetable-format-version-2</a></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 id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id2" role="doc-footnote">
<dt class="label" id="id2">[<a href="#id1">1</a>]</dt>
<dd>py-spy: Sampling profiler for Python programs
(<a class="reference external" href="https://github.com/benfred/py-spy">https://github.com/benfred/py-spy</a>)</aside>
</aside>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0626.rst">https://github.com/python/peps/blob/main/peps/pep-0626.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0626.rst">2024-08-20 10:29:32 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="#tracing">Tracing</a></li>
<li><a class="reference internal" href="#what-is-considered-to-be-code-for-the-purposes-of-tracing">What is considered to be code for the purposes of tracing</a></li>
<li><a class="reference internal" href="#example-event-sequences">Example event sequences</a></li>
<li><a class="reference internal" href="#the-f-lineno-attribute">The f_lineno attribute</a></li>
<li><a class="reference internal" href="#the-new-co-lines-method-of-code-objects">The new co_lines() method of code objects</a><ul>
<li><a class="reference internal" href="#zero-width-ranges">Zero width ranges</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-co-linetable-attribute">The co_linetable attribute</a></li>
<li><a class="reference internal" href="#the-co-lnotab-attribute">The co_lnotab attribute</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
<li><a class="reference internal" href="#examples-of-code-for-which-the-sequence-of-trace-events-will-change">Examples of code for which the sequence of trace events will change</a><ul>
<li><a class="reference internal" href="#pass-statement-in-an-if-statement"><code class="docutils literal notranslate"><span class="pre">pass</span></code> statement in an <code class="docutils literal notranslate"><span class="pre">if</span></code> statement.</a></li>
<li><a class="reference internal" href="#multiple-pass-statements">Multiple <code class="docutils literal notranslate"><span class="pre">pass</span></code> statements.</a></li>
</ul>
</li>
<li><a class="reference internal" href="#c-api">C API</a></li>
<li><a class="reference internal" href="#out-of-process-debuggers-and-profilers">Out of process debuggers and profilers</a></li>
</ul>
</li>
<li><a class="reference internal" href="#performance-implications">Performance Implications</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
<li><a class="reference internal" href="#references">References</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0626.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>