479 lines
39 KiB
HTML
479 lines
39 KiB
HTML
|
||
<!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> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </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 <mark at hotpy.org></dd>
|
||
<dt class="field-even">BDFL-Delegate<span class="colon">:</span></dt>
|
||
<dd class="field-even">Pablo Galindo <pablogsal at python.org></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">"line"</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">"line"</span> <span class="mi">1</span>
|
||
<span class="s2">"line"</span> <span class="mi">2</span>
|
||
<span class="s2">"line"</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">"line"</span> <span class="mi">2</span> <span class="c1"># evaluate [1]</span>
|
||
<span class="s2">"line"</span> <span class="mi">1</span> <span class="c1"># for</span>
|
||
<span class="s2">"line"</span> <span class="mi">2</span> <span class="c1"># store to x</span>
|
||
<span class="s2">"line"</span> <span class="mi">3</span> <span class="c1"># pass</span>
|
||
<span class="s2">"line"</span> <span class="mi">1</span> <span class="c1"># for</span>
|
||
<span class="s2">"line"</span> <span class="mi">4</span> <span class="c1"># return</span>
|
||
<span class="s2">"return"</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">>=</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">"line"</span> <span class="mi">1</span>
|
||
<span class="s2">"line"</span> <span class="mi">2</span>
|
||
<span class="s2">"line"</span> <span class="mi">4</span>
|
||
<span class="s2">"return"</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">"line"</span> <span class="mi">1</span>
|
||
<span class="s2">"line"</span> <span class="mi">2</span>
|
||
<span class="s2">"return"</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">"line"</span> <span class="mi">3</span>
|
||
<span class="s2">"return"</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">"line"</span> <span class="mi">1</span>
|
||
<span class="s2">"line"</span> <span class="mi">2</span>
|
||
<span class="s2">"line"</span> <span class="mi">3</span>
|
||
<span class="s2">"return"</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">&</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">&</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">"Bytecodes from </span><span class="si">%d</span><span class="s2"> (inclusive) to </span><span class="si">%d</span><span class="s2"> (exclusive) "</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"><</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"><</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">"have no line number</span><span class="se">\n</span><span class="s2">"</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">"have line number </span><span class="si">%d</span><span class="se">\n</span><span class="s2">"</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> |