peps/pep-0501/index.html

687 lines
62 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!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 501 General purpose string interpolation | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0501/">
<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 501 General purpose string interpolation | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0501/">
<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 Enhancement Proposals (PEPs)">
<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 501</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 501 General purpose string interpolation</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Alyssa Coghlan &lt;ncoghlan&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Inactive draft that may be taken up again at a later time">Deferred</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">Requires<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="../pep-0498/">498</a></dd>
<dt class="field-odd">Created<span class="colon">:</span></dt>
<dd class="field-odd">08-Aug-2015</dd>
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
<dd class="field-even">3.6</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd">08-Aug-2015, 23-Aug-2015, 30-Aug-2015</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="#pep-deferral">PEP Deferral</a></li>
<li><a class="reference internal" href="#summary-of-differences-from-pep-498">Summary of differences from PEP 498</a></li>
<li><a class="reference internal" href="#proposal">Proposal</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="#conversion-specifiers">Conversion specifiers</a></li>
<li><a class="reference internal" href="#writing-custom-renderers">Writing custom renderers</a></li>
<li><a class="reference internal" href="#expression-evaluation">Expression evaluation</a></li>
<li><a class="reference internal" href="#handling-code-injection-attacks">Handling code injection attacks</a></li>
<li><a class="reference internal" href="#format-specifiers">Format specifiers</a></li>
<li><a class="reference internal" href="#error-handling">Error handling</a></li>
</ul>
</li>
<li><a class="reference internal" href="#possible-integration-with-the-logging-module">Possible integration with the logging module</a></li>
<li><a class="reference internal" href="#discussion">Discussion</a><ul>
<li><a class="reference internal" href="#deferring-support-for-binary-interpolation">Deferring support for binary interpolation</a></li>
<li><a class="reference internal" href="#interoperability-with-str-only-interfaces">Interoperability with str-only interfaces</a></li>
<li><a class="reference internal" href="#preserving-the-raw-template-string">Preserving the raw template string</a></li>
<li><a class="reference internal" href="#creating-a-rich-object-rather-than-a-global-name-lookup">Creating a rich object rather than a global name lookup</a></li>
<li><a class="reference internal" href="#building-atop-pep-498-rather-than-competing-with-it">Building atop PEP 498, rather than competing with it</a></li>
<li><a class="reference internal" href="#deferring-consideration-of-possible-use-in-i18n-use-cases">Deferring consideration of possible use in i18n use cases</a></li>
</ul>
</li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#references">References</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><a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a> proposes new syntactic support for string interpolation that is
transparent to the compiler, allow name references from the interpolation
operation full access to containing namespaces (as with any other expression),
rather than being limited to explicit name references. These are referred
to in the PEP as “f-strings” (a mnemonic for “formatted strings”).</p>
<p>However, it only offers this capability for string formatting, making it likely
we will see code like the following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;echo </span><span class="si">{</span><span class="n">message_from_user</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This kind of code is superficially elegant, but poses a significant problem
if the interpolated value <code class="docutils literal notranslate"><span class="pre">message_from_user</span></code> is in fact provided by an
untrusted user: its an opening for a form of code injection attack, where
the supplied user data has not been properly escaped before being passed to
the <code class="docutils literal notranslate"><span class="pre">os.system</span></code> call.</p>
<p>To address that problem (and a number of other concerns), this PEP proposes
the complementary introduction of “i-strings” (a mnemonic for “interpolation
template strings”), where <code class="docutils literal notranslate"><span class="pre">f&quot;Message</span> <span class="pre">with</span> <span class="pre">{data}&quot;</span></code> would produce the same
result as <code class="docutils literal notranslate"><span class="pre">format(i&quot;Message</span> <span class="pre">with</span> <span class="pre">{data}&quot;)</span></code>.</p>
<p>Some possible examples of the proposed syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mycommand</span> <span class="o">=</span> <span class="n">sh</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;cat </span><span class="si">{filename}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">myquery</span> <span class="o">=</span> <span class="n">sql</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;SELECT </span><span class="si">{column}</span><span class="s2"> FROM </span><span class="si">{table}</span><span class="s2">;&quot;</span><span class="p">)</span>
<span class="n">myresponse</span> <span class="o">=</span> <span class="n">html</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;&lt;html&gt;&lt;body&gt;</span><span class="si">{response.body}</span><span class="s2">&lt;/body&gt;&lt;/html&gt;&quot;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;Message with </span><span class="si">{detailed}</span><span class="s2"> </span><span class="si">{debugging}</span><span class="s2"> </span><span class="si">{info}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="pep-deferral">
<h2><a class="toc-backref" href="#pep-deferral" role="doc-backlink">PEP Deferral</a></h2>
<p>This PEP is currently deferred pending further experience with <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>s
simpler approach of only supporting eager rendering without the additional
complexity of also supporting deferred rendering.</p>
</section>
<section id="summary-of-differences-from-pep-498">
<h2><a class="toc-backref" href="#summary-of-differences-from-pep-498" role="doc-backlink">Summary of differences from PEP 498</a></h2>
<p>The key additions this proposal makes relative to <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>:</p>
<ul class="simple">
<li>the “i” (interpolation template) prefix indicates delayed rendering, but
otherwise uses the same syntax and semantics as formatted strings</li>
<li>interpolation templates are available at runtime as a new kind of object
(<code class="docutils literal notranslate"><span class="pre">types.InterpolationTemplate</span></code>)</li>
<li>the default rendering used by formatted strings is invoked on an
interpolation template object by calling <code class="docutils literal notranslate"><span class="pre">format(template)</span></code> rather than
implicitly</li>
<li>while f-string <code class="docutils literal notranslate"><span class="pre">f&quot;Message</span> <span class="pre">{here}&quot;</span></code> would be <em>semantically</em> equivalent to
<code class="docutils literal notranslate"><span class="pre">format(i&quot;Message</span> <span class="pre">{here}&quot;)</span></code>, it is expected that the explicit syntax would
avoid the runtime overhead of using the delayed rendering machinery</li>
</ul>
<p>NOTE: This proposal spells out a draft API for <code class="docutils literal notranslate"><span class="pre">types.InterpolationTemplate</span></code>.
The precise details of the structures and methods exposed by this type would
be informed by the reference implementation of <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>, so it makes sense to
gain experience with that as an internal API before locking down a public API
(if this extension proposal is accepted).</p>
</section>
<section id="proposal">
<h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2>
<p>This PEP proposes the introduction of a new string prefix that declares the
string to be an interpolation template rather than an ordinary string:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">template</span> <span class="o">=</span> <span class="n">i</span><span class="s2">&quot;Substitute </span><span class="si">{names}</span><span class="s2"> and {expressions()} at runtime&quot;</span>
</pre></div>
</div>
<p>This would be effectively interpreted as:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_raw_template</span> <span class="o">=</span> <span class="s2">&quot;Substitute </span><span class="si">{names}</span><span class="s2"> and {expressions()} at runtime&quot;</span>
<span class="n">_parsed_template</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span><span class="s2">&quot;Substitute &quot;</span><span class="p">,</span> <span class="s2">&quot;names&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot; and &quot;</span><span class="p">,</span> <span class="s2">&quot;expressions()&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot; at runtime&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">_field_values</span> <span class="o">=</span> <span class="p">(</span><span class="n">names</span><span class="p">,</span> <span class="n">expressions</span><span class="p">())</span>
<span class="n">_format_specifiers</span> <span class="o">=</span> <span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="n">template</span> <span class="o">=</span> <span class="n">types</span><span class="o">.</span><span class="n">InterpolationTemplate</span><span class="p">(</span><span class="n">_raw_template</span><span class="p">,</span>
<span class="n">_parsed_template</span><span class="p">,</span>
<span class="n">_field_values</span><span class="p">,</span>
<span class="n">_format_specifiers</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">__format__</span></code> method on <code class="docutils literal notranslate"><span class="pre">types.InterpolationTemplate</span></code> would then
implement the following <code class="docutils literal notranslate"><span class="pre">str.format</span></code> inspired semantics:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">datetime</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">name</span> <span class="o">=</span> <span class="s1">&#39;Jane&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">age</span> <span class="o">=</span> <span class="mi">50</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">anniversary</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">(</span><span class="mi">1991</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">format</span><span class="p">(</span><span class="n">i</span><span class="s1">&#39;My name is </span><span class="si">{name}</span><span class="s1">, my age next year is {age+1}, my anniversary is {anniversary:%A, %B </span><span class="si">%d</span><span class="s1">, %Y}.&#39;</span><span class="p">)</span>
<span class="go">&#39;My name is Jane, my age next year is 51, my anniversary is Saturday, October 12, 1991.&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">format</span><span class="p">(</span><span class="n">i</span><span class="s1">&#39;She said her name is {repr(name)}.&#39;</span><span class="p">)</span>
<span class="go">&quot;She said her name is &#39;Jane&#39;.&quot;</span>
</pre></div>
</div>
<p>As with formatted strings, the interpolation template prefix can be combined with single-quoted, double-quoted and triple quoted strings, including raw strings.
It does not support combination with bytes literals.</p>
<p>Similarly, this PEP does not propose to remove or deprecate any of the existing
string formatting mechanisms, as those will remain valuable when formatting
strings that are not present directly in the source code of the application.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p><a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a> makes interpolating values into strings with full access to Pythons
lexical namespace semantics simpler, but it does so at the cost of creating a
situation where interpolating values into sensitive targets like SQL queries,
shell commands and HTML templates will enjoy a much cleaner syntax when handled
without regard for code injection attacks than when they are handled correctly.</p>
<p>This PEP proposes to provide the option of delaying the actual rendering
of an interpolation template to its <code class="docutils literal notranslate"><span class="pre">__format__</span></code> method, allowing the use of
other template renderers by passing the template around as a first class object.</p>
<p>While very different in the technical details, the
<code class="docutils literal notranslate"><span class="pre">types.InterpolationTemplate</span></code> interface proposed in this PEP is
conceptually quite similar to the <code class="docutils literal notranslate"><span class="pre">FormattableString</span></code> type underlying the
<a class="reference external" href="https://msdn.microsoft.com/en-us/library/dn961160.aspx">native interpolation</a> support introduced in C# 6.0.</p>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>This PEP proposes the introduction of <code class="docutils literal notranslate"><span class="pre">i</span></code> as a new string prefix that
results in the creation of an instance of a new type,
<code class="docutils literal notranslate"><span class="pre">types.InterpolationTemplate</span></code>.</p>
<p>Interpolation template literals are Unicode strings (bytes literals are not
permitted), and string literal concatenation operates as normal, with the
entire combined literal forming the interpolation template.</p>
<p>The template string is parsed into literals, expressions and format specifiers
as described for f-strings in <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>. Conversion specifiers are handled
by the compiler, and appear as part of the field text in interpolation
templates.</p>
<p>However, rather than being rendered directly into a formatted strings, these
components are instead organised into an instance of a new type with the
following semantics:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">InterpolationTemplate</span><span class="p">:</span>
<span class="vm">__slots__</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&quot;raw_template&quot;</span><span class="p">,</span> <span class="s2">&quot;parsed_template&quot;</span><span class="p">,</span>
<span class="s2">&quot;field_values&quot;</span><span class="p">,</span> <span class="s2">&quot;format_specifiers&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">raw_template</span><span class="p">,</span> <span class="n">parsed_template</span><span class="p">,</span>
<span class="n">field_values</span><span class="p">,</span> <span class="n">format_specifiers</span><span class="p">):</span>
<span class="bp">self</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">raw_template</span> <span class="o">=</span> <span class="n">raw_template</span>
<span class="bp">self</span><span class="o">.</span><span class="n">parsed_template</span> <span class="o">=</span> <span class="n">parsed_template</span>
<span class="bp">self</span><span class="o">.</span><span class="n">field_values</span> <span class="o">=</span> <span class="n">field_values</span>
<span class="bp">self</span><span class="o">.</span><span class="n">format_specifiers</span> <span class="o">=</span> <span class="n">format_specifiers</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&lt;</span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="vm">__qualname__</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="nb">repr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_raw_template</span><span class="p">)</span><span class="si">}</span><span class="s2"> &quot;</span>
<span class="sa">f</span><span class="s2">&quot;at </span><span class="si">{</span><span class="nb">id</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="si">:</span><span class="s2">#x</span><span class="si">}</span><span class="s2">&gt;&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__format__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">format_specifier</span><span class="p">):</span>
<span class="c1"># When formatted, render to a string, and use string formatting</span>
<span class="k">return</span> <span class="nb">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">render</span><span class="p">(),</span> <span class="n">format_specifier</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">render_template</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">,</span>
<span class="n">render_field</span><span class="o">=</span><span class="nb">format</span><span class="p">):</span>
<span class="c1"># See definition of the template rendering semantics below</span>
</pre></div>
</div>
<p>The result of an interpolation template expression is an instance of this
type, rather than an already rendered string - rendering only takes
place when the instances <code class="docutils literal notranslate"><span class="pre">render</span></code> method is called (either directly, or
indirectly via <code class="docutils literal notranslate"><span class="pre">__format__</span></code>).</p>
<p>The compiler will pass the following details to the interpolation template for
later use:</p>
<ul class="simple">
<li>a string containing the raw template as written in the source code</li>
<li>a parsed template tuple that allows the renderer to render the
template without needing to reparse the raw string template for substitution
fields</li>
<li>a tuple containing the evaluated field values, in field substitution order</li>
<li>a tuple containing the field format specifiers, in field substitution order</li>
</ul>
<p>This structure is designed to take full advantage of compile time constant
folding by ensuring the parsed template is always constant, even when the
field values and format specifiers include variable substitution expressions.</p>
<p>The raw template is just the interpolation template as a string. By default,
it is used to provide a human readable representation for the interpolation
template.</p>
<p>The parsed template consists of a tuple of 2-tuples, with each 2-tuple
containing the following fields:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">leading_text</span></code>: a leading string literal. This will be the empty string if
the current field is at the start of the string, or immediately follows the
preceding field.</li>
<li><code class="docutils literal notranslate"><span class="pre">field_expr</span></code>: the text of the expression element in the substitution field.
This will be None for a final trailing text segment.</li>
</ul>
<p>The tuple of evaluated field values holds the <em>results</em> of evaluating the
substitution expressions in the scope where the interpolation template appears.</p>
<p>The tuple of field specifiers holds the <em>results</em> of evaluating the field
specifiers as f-strings in the scope where the interpolation template appears.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">InterpolationTemplate.render</span></code> implementation then defines the rendering
process in terms of the following renderers:</p>
<ul class="simple">
<li>an overall <code class="docutils literal notranslate"><span class="pre">render_template</span></code> operation that defines how the sequence of
literal template sections and rendered fields are composed into a fully
rendered result. The default template renderer is string concatenation
using <code class="docutils literal notranslate"><span class="pre">''.join</span></code>.</li>
<li>a per field <code class="docutils literal notranslate"><span class="pre">render_field</span></code> operation that receives the field value and
format specifier for substitution fields within the template. The default
field renderer is the <code class="docutils literal notranslate"><span class="pre">format</span></code> builtin.</li>
</ul>
<p>Given an appropriate parsed template representation and internal methods of
iterating over it, the semantics of template rendering would then be equivalent
to the following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">render_template</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">,</span>
<span class="n">render_field</span><span class="o">=</span><span class="nb">format</span><span class="p">):</span>
<span class="n">iter_fields</span> <span class="o">=</span> <span class="nb">enumerate</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">parsed_template</span><span class="p">)</span>
<span class="n">values</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">field_values</span>
<span class="n">specifiers</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">format_specifiers</span>
<span class="n">template_parts</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">field_pos</span><span class="p">,</span> <span class="p">(</span><span class="n">leading_text</span><span class="p">,</span> <span class="n">field_expr</span><span class="p">)</span> <span class="ow">in</span> <span class="n">iter_fields</span><span class="p">:</span>
<span class="n">template_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">leading_text</span><span class="p">)</span>
<span class="k">if</span> <span class="n">field_expr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">values</span><span class="p">[</span><span class="n">field_pos</span><span class="p">]</span>
<span class="n">specifier</span> <span class="o">=</span> <span class="n">specifiers</span><span class="p">[</span><span class="n">field_pos</span><span class="p">]</span>
<span class="n">rendered_field</span> <span class="o">=</span> <span class="n">render_field</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">specifier</span><span class="p">)</span>
<span class="n">template_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">rendered_field</span><span class="p">)</span>
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="n">template_parts</span><span class="p">)</span>
</pre></div>
</div>
<section id="conversion-specifiers">
<h3><a class="toc-backref" href="#conversion-specifiers" role="doc-backlink">Conversion specifiers</a></h3>
<p>NOTE:</p>
<blockquote>
<div>Appropriate handling of conversion specifiers is currently an open question.
Exposing them more directly to custom renderers would increase the
complexity of the <code class="docutils literal notranslate"><span class="pre">InterpolationTemplate</span></code> definition without providing an
increase in expressiveness (since theyre redundant with calling the builtins
directly). At the same time, they <em>are</em> made available as arbitrary strings
when writing custom <code class="docutils literal notranslate"><span class="pre">string.Formatter</span></code> implementations, so it may be
desirable to offer similar levels of flexibility of interpretation in
interpolation templates.</div></blockquote>
<p>The <code class="docutils literal notranslate"><span class="pre">!a</span></code>, <code class="docutils literal notranslate"><span class="pre">!r</span></code> and <code class="docutils literal notranslate"><span class="pre">!s</span></code> conversion specifiers supported by <code class="docutils literal notranslate"><span class="pre">str.format</span></code>
and hence <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a> are handled in interpolation templates as follows:</p>
<ul class="simple">
<li>theyre included unmodified in the raw template to ensure no information is
lost</li>
<li>theyre <em>replaced</em> in the parsed template with the corresponding builtin
calls, in order to ensure that <code class="docutils literal notranslate"><span class="pre">field_expr</span></code> always contains a valid
Python expression</li>
<li>the corresponding field value placed in the field values tuple is
converted appropriately <em>before</em> being passed to the interpolation
template</li>
</ul>
<p>This means that, for most purposes, the difference between the use of
conversion specifiers and calling the corresponding builtins in the
original interpolation template will be transparent to custom renderers. The
difference will only be apparent if reparsing the raw template, or attempting
to reconstruct the original template from the parsed template.</p>
</section>
<section id="writing-custom-renderers">
<h3><a class="toc-backref" href="#writing-custom-renderers" role="doc-backlink">Writing custom renderers</a></h3>
<p>Writing a custom renderer doesnt requiring any special syntax. Instead,
custom renderers are ordinary callables that process an interpolation
template directly either by calling the <code class="docutils literal notranslate"><span class="pre">render()</span></code> method with alternate <code class="docutils literal notranslate"><span class="pre">render_template</span></code> or <code class="docutils literal notranslate"><span class="pre">render_field</span></code> implementations, or by accessing the
templates data attributes directly.</p>
<p>For example, the following function would render a template using objects
<code class="docutils literal notranslate"><span class="pre">repr</span></code> implementations rather than their native formatting support:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">reprformat</span><span class="p">(</span><span class="n">template</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">render_field</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">specifier</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">format</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="n">specifier</span><span class="p">)</span>
<span class="k">return</span> <span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">render_field</span><span class="o">=</span><span class="n">render_field</span><span class="p">)</span>
</pre></div>
</div>
<p>When writing custom renderers, note that the return type of the overall
rendering operation is determined by the return type of the passed in <code class="docutils literal notranslate"><span class="pre">render_template</span></code> callable. While this is expected to be a string in most
cases, producing non-string objects <em>is</em> permitted. For example, a custom
template renderer could involve an <code class="docutils literal notranslate"><span class="pre">sqlalchemy.sql.text</span></code> call that produces
an <a class="reference external" href="http://docs.sqlalchemy.org/en/rel_1_0/core/tutorial.html#using-textual-sql">SQL Alchemy query object</a>.</p>
<p>Non-strings may also be returned from <code class="docutils literal notranslate"><span class="pre">render_field</span></code>, as long as it is paired
with a <code class="docutils literal notranslate"><span class="pre">render_template</span></code> implementation that expects that behaviour.</p>
</section>
<section id="expression-evaluation">
<h3><a class="toc-backref" href="#expression-evaluation" role="doc-backlink">Expression evaluation</a></h3>
<p>As with f-strings, the subexpressions that are extracted from the interpolation
template are evaluated in the context where the interpolation template
appears. This means the expression has full access to local, nonlocal and global variables. Any valid Python expression can be used inside <code class="docutils literal notranslate"><span class="pre">{}</span></code>, including
function and method calls.</p>
<p>Because the substitution expressions are evaluated where the string appears in
the source code, there are no additional security concerns related to the
contents of the expression itself, as you could have also just written the
same expression and used runtime field parsing:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">bar</span><span class="o">=</span><span class="mi">10</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
<span class="gp">... </span> <span class="k">return</span> <span class="n">data</span> <span class="o">+</span> <span class="mi">20</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="s1">&#39;input=</span><span class="si">{bar}</span><span class="s1">, output={foo(bar)}&#39;</span><span class="p">)</span>
<span class="go">&#39;input=10, output=30&#39;</span>
</pre></div>
</div>
<p>Is essentially equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="s1">&#39;input=</span><span class="si">{}</span><span class="s1">, output=</span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">bar</span><span class="p">,</span> <span class="n">foo</span><span class="p">(</span><span class="n">bar</span><span class="p">))</span>
<span class="go">&#39;input=10, output=30&#39;</span>
</pre></div>
</div>
</section>
<section id="handling-code-injection-attacks">
<h3><a class="toc-backref" href="#handling-code-injection-attacks" role="doc-backlink">Handling code injection attacks</a></h3>
<p>The <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a> formatted string syntax makes it potentially attractive to write
code like the following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">runquery</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;SELECT </span><span class="si">{</span><span class="n">column</span><span class="si">}</span><span class="s2"> FROM </span><span class="si">{</span><span class="n">table</span><span class="si">}</span><span class="s2">;&quot;</span><span class="p">)</span>
<span class="n">runcommand</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;cat </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">return_response</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&lt;html&gt;&lt;body&gt;</span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">body</span><span class="si">}</span><span class="s2">&lt;/body&gt;&lt;/html&gt;&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>These all represent potential vectors for code injection attacks, if any of the
variables being interpolated happen to come from an untrusted source. The
specific proposal in this PEP is designed to make it straightforward to write
use case specific renderers that take care of quoting interpolated values
appropriately for the relevant security context:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">runquery</span><span class="p">(</span><span class="n">sql</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;SELECT </span><span class="si">{column}</span><span class="s2"> FROM </span><span class="si">{table}</span><span class="s2">;&quot;</span><span class="p">))</span>
<span class="n">runcommand</span><span class="p">(</span><span class="n">sh</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;cat </span><span class="si">{filename}</span><span class="s2">&quot;</span><span class="p">))</span>
<span class="n">return_response</span><span class="p">(</span><span class="n">html</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;&lt;html&gt;&lt;body&gt;</span><span class="si">{response.body}</span><span class="s2">&lt;/body&gt;&lt;/html&gt;&quot;</span><span class="p">))</span>
</pre></div>
</div>
<p>This PEP does not cover adding such renderers to the standard library
immediately, but rather proposes to ensure that they can be readily provided by
third party libraries, and potentially incorporated into the standard library
at a later date.</p>
<p>For example, a renderer that aimed to offer a POSIX shell style experience for
accessing external programs, without the significant risks posed by running
<code class="docutils literal notranslate"><span class="pre">os.system</span></code> or enabling the system shell when using the <code class="docutils literal notranslate"><span class="pre">subprocess</span></code> module
APIs, might provide an interface for running external programs similar to that
offered by the
<a class="reference external" href="http://julia.readthedocs.org/en/latest/manual/running-external-programs/">Julia programming language</a>,
only with the backtick based <code class="docutils literal notranslate"><span class="pre">\`cat</span> <span class="pre">$filename\`</span></code> syntax replaced by
<code class="docutils literal notranslate"><span class="pre">i&quot;cat</span> <span class="pre">{filename}&quot;</span></code> style interpolation templates.</p>
</section>
<section id="format-specifiers">
<h3><a class="toc-backref" href="#format-specifiers" role="doc-backlink">Format specifiers</a></h3>
<p>Aside from separating them out from the substitution expression during parsing,
format specifiers are otherwise treated as opaque strings by the interpolation
template parser - assigning semantics to those (or, alternatively,
prohibiting their use) is handled at runtime by the field renderer.</p>
</section>
<section id="error-handling">
<h3><a class="toc-backref" href="#error-handling" role="doc-backlink">Error handling</a></h3>
<p>Either compile time or run time errors can occur when processing interpolation
expressions. Compile time errors are limited to those errors that can be
detected when parsing a template string into its component tuples. These
errors all raise SyntaxError.</p>
<p>Unmatched braces:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">i</span><span class="s1">&#39;x={x&#39;</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>
<span class="gr">SyntaxError</span>: <span class="n">missing &#39;}&#39; in interpolation expression</span>
</pre></div>
</div>
<p>Invalid expressions:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&gt;&gt;&gt; i&#39;x={!x}&#39;
File &quot;&lt;fstring&gt;&quot;, line 1
!x
^
SyntaxError: invalid syntax
</pre></div>
</div>
<p>Run time errors occur when evaluating the expressions inside a
template string before creating the interpolation template object. See <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>
for some examples.</p>
<p>Different renderers may also impose additional runtime
constraints on acceptable interpolated expressions and other formatting
details, which will be reported as runtime exceptions.</p>
</section>
</section>
<section id="possible-integration-with-the-logging-module">
<h2><a class="toc-backref" href="#possible-integration-with-the-logging-module" role="doc-backlink">Possible integration with the logging module</a></h2>
<p>One of the challenges with the logging module has been that we have previously
been unable to devise a reasonable migration strategy away from the use of
printf-style formatting. The runtime parsing and interpolation overhead for
logging messages also poses a problem for extensive logging of runtime events
for monitoring purposes.</p>
<p>While beyond the scope of this initial PEP, interpolation template support
could potentially be added to the logging modules event reporting APIs,
permitting relevant details to be captured using forms like:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;Event: </span><span class="si">{event}</span><span class="s2">; Details: </span><span class="si">{data}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;Error: </span><span class="si">{error}</span><span class="s2">; Details: </span><span class="si">{data}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Rather than the current mod-formatting style:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Event: </span><span class="si">%s</span><span class="s2">; Details: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">event</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s2">&quot;Error: </span><span class="si">%s</span><span class="s2">; Details: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">event</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</pre></div>
</div>
<p>As the interpolation template is passed in as an ordinary argument, other
keyword arguments would also remain available:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">logging</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;Error: </span><span class="si">{error}</span><span class="s2">; Details: </span><span class="si">{data}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">exc_info</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>As part of any such integration, a recommended approach would need to be
defined for “lazy evaluation” of interpolated fields, as the <code class="docutils literal notranslate"><span class="pre">logging</span></code>
modules existing delayed interpolation support provides access to
<a class="reference external" href="https://docs.python.org/3/library/logging.html#logrecord-attributes">various attributes</a> of the event <code class="docutils literal notranslate"><span class="pre">LogRecord</span></code> instance.</p>
<p>For example, since interpolation expressions are arbitrary Python expressions,
string literals could be used to indicate cases where evaluation itself is
being deferred, not just rendering:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;Logger: {&#39;record.name&#39;}; Event: </span><span class="si">{event}</span><span class="s2">; Details: </span><span class="si">{data}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This could be further extended with idioms like using inline tuples to indicate
deferred function calls to be made only if the log message is actually
going to be rendered at current logging levels:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">i</span><span class="s2">&quot;Event: </span><span class="si">{event}</span><span class="s2">; Details: {expensive_call, raw_data}&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This kind of approach would be possible as having access to the actual <em>text</em>
of the field expression would allow the logging renderer to distinguish
between inline tuples that appear in the field expression itself, and tuples
that happen to be passed in as data values in a normal field.</p>
</section>
<section id="discussion">
<h2><a class="toc-backref" href="#discussion" role="doc-backlink">Discussion</a></h2>
<p>Refer to <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a> for additional discussion, as several of the points there
also apply to this PEP.</p>
<section id="deferring-support-for-binary-interpolation">
<h3><a class="toc-backref" href="#deferring-support-for-binary-interpolation" role="doc-backlink">Deferring support for binary interpolation</a></h3>
<p>Supporting binary interpolation with this syntax would be relatively
straightforward (the elements in the parsed fields tuple would just be
byte strings rather than text strings, and the default renderer would be
markedly less useful), but poses a significant likelihood of producing
confusing type errors when a text renderer was presented with
binary input.</p>
<p>Since the proposed syntax is useful without binary interpolation support, and
such support can be readily added later, further consideration of binary
interpolation is considered out of scope for the current PEP.</p>
</section>
<section id="interoperability-with-str-only-interfaces">
<h3><a class="toc-backref" href="#interoperability-with-str-only-interfaces" role="doc-backlink">Interoperability with str-only interfaces</a></h3>
<p>For interoperability with interfaces that only accept strings, interpolation
templates can still be prerendered with <code class="docutils literal notranslate"><span class="pre">format</span></code>, rather than delegating the
rendering to the called function.</p>
<p>This reflects the key difference from <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>, which <em>always</em> eagerly applies
the default rendering, without any way to delegate the choice of renderer to
another section of the code.</p>
</section>
<section id="preserving-the-raw-template-string">
<h3><a class="toc-backref" href="#preserving-the-raw-template-string" role="doc-backlink">Preserving the raw template string</a></h3>
<p>Earlier versions of this PEP failed to make the raw template string available
on the interpolation template. Retaining it makes it possible to provide a more
attractive template representation, as well as providing the ability to
precisely reconstruct the original string, including both the expression text
and the details of any eagerly rendered substitution fields in format specifiers.</p>
</section>
<section id="creating-a-rich-object-rather-than-a-global-name-lookup">
<h3><a class="toc-backref" href="#creating-a-rich-object-rather-than-a-global-name-lookup" role="doc-backlink">Creating a rich object rather than a global name lookup</a></h3>
<p>Earlier versions of this PEP used an <code class="docutils literal notranslate"><span class="pre">__interpolate__</span></code> builtin, rather than
a creating a new kind of object for later consumption by interpolation
functions. Creating a rich descriptive object with a useful default renderer
made it much easier to support customisation of the semantics of interpolation.</p>
</section>
<section id="building-atop-pep-498-rather-than-competing-with-it">
<h3><a class="toc-backref" href="#building-atop-pep-498-rather-than-competing-with-it" role="doc-backlink">Building atop PEP 498, rather than competing with it</a></h3>
<p>Earlier versions of this PEP attempted to serve as a complete substitute for
<a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>, rather than building a more flexible delayed rendering capability on
top of <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>s eager rendering.</p>
<p>Assuming the presence of f-strings as a supporting capability simplified a
number of aspects of the proposal in this PEP (such as how to handle substitution
fields in format specifiers)</p>
</section>
<section id="deferring-consideration-of-possible-use-in-i18n-use-cases">
<h3><a class="toc-backref" href="#deferring-consideration-of-possible-use-in-i18n-use-cases" role="doc-backlink">Deferring consideration of possible use in i18n use cases</a></h3>
<p>The initial motivating use case for this PEP was providing a cleaner syntax
for i18n translation, as that requires access to the original unmodified
template. As such, it focused on compatibility with the substitution syntax used
in Pythons <code class="docutils literal notranslate"><span class="pre">string.Template</span></code> formatting and Mozillas l20n project.</p>
<p>However, subsequent discussion revealed there are significant additional
considerations to be taken into account in the i18n use case, which dont
impact the simpler cases of handling interpolation into security sensitive
contexts (like HTML, system shells, and database queries), or producing
application debugging messages in the preferred language of the development
team (rather than the native language of end users).</p>
<p>Due to the original design of the <code class="docutils literal notranslate"><span class="pre">str.format</span></code> substitution syntax in <a class="pep reference internal" href="../pep-3101/" title="PEP 3101 Advanced String Formatting">PEP 3101</a>
being inspired by C#s string formatting syntax, the specific field
substitution syntax used in <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a> is consistent not only with Pythons own <code class="docutils literal notranslate"><span class="pre">str.format</span></code> syntax, but also with string formatting in C#, including the
native “$-string” interpolation syntax introduced in C# 6.0 (released in July
2015). The related <code class="docutils literal notranslate"><span class="pre">IFormattable</span></code> interface in C# forms the basis of a
<a class="reference external" href="https://msdn.microsoft.com/en-us/library/system.iformattable.aspx">number of elements</a> of C#s internationalization and localization
support.</p>
<p>This means that while this particular substitution syntax may not
currently be widely used for translation of <em>Python</em> applications (losing out
to traditional %-formatting and the designed-specifically-for-i18n
<code class="docutils literal notranslate"><span class="pre">string.Template</span></code> formatting), it <em>is</em> a popular translation format in the
wider software development ecosystem (since it is already the preferred
format for translating C# applications).</p>
</section>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<ul class="simple">
<li>Eric V. Smith for creating <a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a> and demonstrating the feasibility of
arbitrary expression substitution in string interpolation</li>
<li>Barry Warsaw, Armin Ronacher, and Mike Miller for their contributions to
exploring the feasibility of using this model of delayed rendering in i18n
use cases (even though the ultimate conclusion was that it was a poor fit,
at least for current approaches to i18n in Python)</li>
</ul>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<ul class="simple">
<li><a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting">%-formatting</a></li>
<li><a class="reference external" href="https://docs.python.org/3/library/string.html#formatstrings">str.format</a></li>
<li><a class="reference external" href="https://docs.python.org/3/library/string.html#template-strings">string.Template documentation</a></li>
<li><a class="pep reference internal" href="../pep-0215/" title="PEP 215 String Interpolation">PEP 215</a>: String Interpolation</li>
<li><a class="pep reference internal" href="../pep-0292/" title="PEP 292 Simpler String Substitutions">PEP 292</a>: Simpler String Substitutions</li>
<li><a class="pep reference internal" href="../pep-3101/" title="PEP 3101 Advanced String Formatting">PEP 3101</a>: Advanced String Formatting</li>
<li><a class="pep reference internal" href="../pep-0498/" title="PEP 498 Literal String Interpolation">PEP 498</a>: Literal string formatting</li>
<li><a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated">FormattableString and C# native string interpolation</a></li>
<li><a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/api/system.iformattable">IFormattable interface in C# (see remarks for globalization notes)</a></li>
<li><a class="reference external" href="https://docs.julialang.org/en/v1/manual/running-external-programs/">Running external commands in Julia</a></li>
</ul>
</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-0501.rst">https://github.com/python/peps/blob/main/peps/pep-0501.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0501.rst">2023-10-11 12:05:51 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="#pep-deferral">PEP Deferral</a></li>
<li><a class="reference internal" href="#summary-of-differences-from-pep-498">Summary of differences from PEP 498</a></li>
<li><a class="reference internal" href="#proposal">Proposal</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="#conversion-specifiers">Conversion specifiers</a></li>
<li><a class="reference internal" href="#writing-custom-renderers">Writing custom renderers</a></li>
<li><a class="reference internal" href="#expression-evaluation">Expression evaluation</a></li>
<li><a class="reference internal" href="#handling-code-injection-attacks">Handling code injection attacks</a></li>
<li><a class="reference internal" href="#format-specifiers">Format specifiers</a></li>
<li><a class="reference internal" href="#error-handling">Error handling</a></li>
</ul>
</li>
<li><a class="reference internal" href="#possible-integration-with-the-logging-module">Possible integration with the logging module</a></li>
<li><a class="reference internal" href="#discussion">Discussion</a><ul>
<li><a class="reference internal" href="#deferring-support-for-binary-interpolation">Deferring support for binary interpolation</a></li>
<li><a class="reference internal" href="#interoperability-with-str-only-interfaces">Interoperability with str-only interfaces</a></li>
<li><a class="reference internal" href="#preserving-the-raw-template-string">Preserving the raw template string</a></li>
<li><a class="reference internal" href="#creating-a-rich-object-rather-than-a-global-name-lookup">Creating a rich object rather than a global name lookup</a></li>
<li><a class="reference internal" href="#building-atop-pep-498-rather-than-competing-with-it">Building atop PEP 498, rather than competing with it</a></li>
<li><a class="reference internal" href="#deferring-consideration-of-possible-use-in-i18n-use-cases">Deferring consideration of possible use in i18n use cases</a></li>
</ul>
</li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#references">References</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-0501.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>