CINXE.COM

PEP 437 – A DSL for specifying signatures, annotations and argument converters | peps.python.org

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 437 – A DSL for specifying signatures, annotations and argument converters | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0437/"> <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 437 – A DSL for specifying signatures, annotations and argument converters | peps.python.org'> <meta property="og:description" content="The Python C-API currently has no mechanism for specifying and auto-generating function signatures, annotations or custom argument converters."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0437/"> <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="The Python C-API currently has no mechanism for specifying and auto-generating function signatures, annotations or custom argument converters."> <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 437</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 437 – A DSL for specifying signatures, annotations and argument converters</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Stefan Krah &lt;skrah&#32;&#97;t&#32;bytereef.org&gt;</dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</abbr></dd> <dt class="field-odd">Type<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-even">Created<span class="colon">:</span></dt> <dd class="field-even">11-Mar-2013</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.4</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even"><p></p></dd> <dt class="field-odd">Resolution<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2013-May/126117.html">Python-Dev message</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rejection-notice">Rejection Notice</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#scope">Scope</a></li> <li><a class="reference internal" href="#dsl-overview">DSL overview</a><ul> <li><a class="reference internal" href="#type-safety-and-annotations">Type safety and annotations</a></li> <li><a class="reference internal" href="#include-converters-h">Include/converters.h</a></li> <li><a class="reference internal" href="#function-specifications">Function specifications</a><ul> <li><a class="reference internal" href="#keyword-arguments">Keyword arguments</a><ul> <li><a class="reference internal" href="#define-block">Define block</a></li> <li><a class="reference internal" href="#declaration">Declaration</a></li> <li><a class="reference internal" href="#c-declarations">C-declarations</a></li> <li><a class="reference internal" href="#cleanup">Cleanup</a></li> <li><a class="reference internal" href="#output">Output</a></li> </ul> </li> <li><a class="reference internal" href="#positional-only-arguments">Positional-only arguments</a></li> <li><a class="reference internal" href="#left-and-right-optional-arguments">Left and right optional arguments</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#flexibility-in-formatting">Flexibility in formatting</a></li> <li><a class="reference internal" href="#benefits-of-a-compact-notation">Benefits of a compact notation</a></li> <li><a class="reference internal" href="#easy-validation-of-the-definition">Easy validation of the definition</a></li> <li><a class="reference internal" href="#reference-implementation">Reference implementation</a></li> <li><a class="reference internal" href="#grammar">Grammar</a></li> <li><a class="reference internal" href="#comparison-with-pep-436">Comparison with PEP 436</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>The Python C-API currently has no mechanism for specifying and auto-generating function signatures, annotations or custom argument converters.</p> <p>There are several possible approaches to the problem. Cython uses <em>cdef</em> definitions in <em>.pyx</em> files to generate the required information. However, CPython’s C-API functions often require additional initialization and cleanup snippets that would be hard to specify in a <em>cdef</em>.</p> <p><a class="pep reference internal" href="../pep-0436/" title="PEP 436 – The Argument Clinic DSL">PEP 436</a> proposes a domain specific language (DSL) enclosed in C comments that largely resembles a per-parameter configuration file. A preprocessor reads the comment and emits an argument parsing function, docstrings and a header for the function that utilizes the results of the parsing step.</p> <p>The latter function is subsequently referred to as the <em>implementation function</em>.</p> </section> <section id="rejection-notice"> <h2><a class="toc-backref" href="#rejection-notice" role="doc-backlink">Rejection Notice</a></h2> <p>This PEP was rejected by Guido van Rossum at PyCon US 2013. However, several of the specific issues raised by this PEP were taken into account when designing the <a class="reference external" href="http://hg.python.org/peps/rev/a2fa10b2424b">second iteration of the PEP 436 DSL</a>.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Opinions differ regarding the suitability of the <a class="pep reference internal" href="../pep-0436/" title="PEP 436 – The Argument Clinic DSL">PEP 436</a> DSL in the context of a C file. This PEP proposes an alternative DSL. The specific issues with <a class="pep reference internal" href="../pep-0436/" title="PEP 436 – The Argument Clinic DSL">PEP 436</a> that spurred the counter proposal will be explained in the final section of this PEP.</p> </section> <section id="scope"> <h2><a class="toc-backref" href="#scope" role="doc-backlink">Scope</a></h2> <p>The PEP focuses exclusively on the DSL. Topics like the output locations of docstrings or the generated code are outside the scope of this PEP.</p> <p>It is however vital that the DSL is suitable for generating custom argument parsers, a feature that is already implemented in Cython. Therefore, one of the goals of this PEP is to keep the DSL close to existing solutions, thus facilitating a possible inclusion of the relevant parts of Cython into the CPython source tree.</p> </section> <section id="dsl-overview"> <h2><a class="toc-backref" href="#dsl-overview" role="doc-backlink">DSL overview</a></h2> <section id="type-safety-and-annotations"> <h3><a class="toc-backref" href="#type-safety-and-annotations" role="doc-backlink">Type safety and annotations</a></h3> <p>A conversion from a Python to a C value is fully defined by the type of the converter function. The PyArg_Parse* family of functions accepts custom converters in addition to the well-known default converters “i”, “f”, etc.</p> <p>This PEP views the default converters as abstract functions, regardless of how they are actually implemented.</p> </section> <section id="include-converters-h"> <h3><a class="toc-backref" href="#include-converters-h" role="doc-backlink">Include/converters.h</a></h3> <p>Converter functions must be forward-declared. All converter functions shall be entered into the file Include/converters.h. The file is read by the preprocessor prior to translating .c files. This is an excerpt:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/*</span><span class="p">[</span><span class="n">converter</span><span class="p">]</span> <span class="c1">##### Default converters #####</span> <span class="s2">&quot;s&quot;</span><span class="p">:</span> <span class="nb">str</span> <span class="o">-&gt;</span> <span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">res</span><span class="p">;</span> <span class="s2">&quot;s*&quot;</span><span class="p">:</span> <span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">,</span> <span class="n">rw_buffer</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="n">Py_buffer</span> <span class="o">&amp;</span><span class="n">res</span><span class="p">;</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span> <span class="s2">&quot;es#&quot;</span><span class="p">:</span> <span class="nb">str</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">res_encoding</span><span class="p">,</span> <span class="n">char</span> <span class="o">**</span><span class="n">res</span><span class="p">,</span> <span class="n">Py_ssize_t</span> <span class="o">*</span><span class="n">res_length</span><span class="p">);</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span> <span class="c1">##### Custom converters #####</span> <span class="n">path_converter</span><span class="p">:</span> <span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="n">path_t</span> <span class="o">&amp;</span><span class="n">res</span><span class="p">;</span> <span class="n">OS_STAT_DIR_FD_CONVERTER</span><span class="p">:</span> <span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="nb">int</span> <span class="n">res</span><span class="p">;</span> <span class="p">[</span><span class="n">converter_end</span><span class="p">]</span><span class="o">*/</span> </pre></div> </div> <p>Converters are specified by their name, Python input type(s) and C output type(s). Default converters must have quoted names, custom converters must have regular names. A Python type is given by its name. If a function accepts multiple Python types, the set is written in list form.</p> <p>Since the default converters may have multiple implicit return values, the C output type(s) are written according to the following convention:</p> <p>The main return value must be named <em>res</em>. This is a placeholder for the actual variable name given later in the DSL. Additional implicit return values must be prefixed by <em>res_</em>.</p> <p>By default the variables are passed by value to the implementation function. If the address should be passed instead, <em>res</em> must be prefixed with an ampersand.</p> <p>Additional declarations may be placed into .c files. Duplicate declarations are allowed as long as the function types are identical.</p> <p>It is encouraged to declare custom converter types a second time right above the converter function definition. The preprocessor will then catch any mismatch between the declarations.</p> <p>In order to keep the converter complexity manageable, PY_SSIZE_T_CLEAN will be deprecated and Py_ssize_t will be assumed for all length arguments.</p> <p>TBD: Make a list of fantasy types like <em>rw_buffer</em>.</p> </section> <section id="function-specifications"> <h3><a class="toc-backref" href="#function-specifications" role="doc-backlink">Function specifications</a></h3> <section id="keyword-arguments"> <h4><a class="toc-backref" href="#keyword-arguments" role="doc-backlink">Keyword arguments</a></h4> <p>This example contains the definition of os.stat. The individual sections will be explained in detail. Grammatically, the whole define block consists of a function specification and an output section. The function specification in turn consists of a declaration section, an optional C-declaration section and an optional cleanup code section. Sections within the function specification are separated in yacc style by ‘%%’:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/*</span><span class="p">[</span><span class="n">define</span> <span class="n">posix_stat</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">os</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">path_converter</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">dir_fd</span><span class="p">:</span> <span class="n">OS_STAT_DIR_FD_CONVERTER</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">follow_symlinks</span><span class="p">:</span> <span class="s2">&quot;p&quot;</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">os</span><span class="o">.</span><span class="n">stat_result</span><span class="p">:</span> <span class="k">pass</span> <span class="o">%%</span> <span class="n">path_t</span> <span class="n">path</span> <span class="o">=</span> <span class="n">PATH_T_INITIALIZE</span><span class="p">(</span><span class="s2">&quot;stat&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="nb">int</span> <span class="n">dir_fd</span> <span class="o">=</span> <span class="n">DEFAULT_DIR_FD</span><span class="p">;</span> <span class="nb">int</span> <span class="n">follow_symlinks</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="o">%%</span> <span class="n">path_cleanup</span><span class="p">(</span><span class="o">&amp;</span><span class="n">path</span><span class="p">);</span> <span class="p">[</span><span class="n">define_end</span><span class="p">]</span><span class="o">*/</span> <span class="o">&lt;</span><span class="n">literal</span> <span class="n">C</span> <span class="n">output</span><span class="o">&gt;</span> <span class="o">/*</span><span class="p">[</span><span class="n">define_output_end</span><span class="p">]</span><span class="o">*/</span> </pre></div> </div> <section id="define-block"> <h5><a class="toc-backref" href="#define-block" role="doc-backlink">Define block</a></h5> <p>The function specification block starts with a <code class="docutils literal notranslate"><span class="pre">/*[define</span></code> token, followed by an optional C function name, followed by a right bracket. If the C function name is not given, it is generated from the declaration name. In the example, omitting the name <em>posix_stat</em> would result in a C function name of <em>os_stat</em>.</p> </section> <section id="declaration"> <h5><a class="toc-backref" href="#declaration" role="doc-backlink">Declaration</a></h5> <p>The required declaration is (almost) a valid Python function definition. The ‘def’ keyword and the function body are redundant, but the author of this PEP finds the definition more readable if they are present.</p> <p>The function name may be a path instead of a plain identifier. Each argument is annotated with the name of the converter function that will be applied to it.</p> <p>Default values are given in the usual Python manner and may be any valid Python expression.</p> <p>The return value may be any Python expression. Usually it will be the name of an object, but alternative return values could be specified in list form.</p> </section> <section id="c-declarations"> <h5><a class="toc-backref" href="#c-declarations" role="doc-backlink">C-declarations</a></h5> <p>This optional section contains C variable declarations. Since the converter functions have been declared beforehand, the preprocessor can type-check the declarations.</p> </section> <section id="cleanup"> <h5><a class="toc-backref" href="#cleanup" role="doc-backlink">Cleanup</a></h5> <p>The optional cleanup section contains literal C code that will be inserted unmodified after the implementation function.</p> </section> <section id="output"> <h5><a class="toc-backref" href="#output" role="doc-backlink">Output</a></h5> <p>The output section contains the code emitted by the preprocessor.</p> </section> </section> <section id="positional-only-arguments"> <h4><a class="toc-backref" href="#positional-only-arguments" role="doc-backlink">Positional-only arguments</a></h4> <p>Functions that do not take keyword arguments are indicated by the presence of the <em>slash</em> special parameter:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/*</span><span class="p">[</span><span class="n">define</span> <span class="n">stat_float_times</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">os</span><span class="o">.</span><span class="n">stat_float_times</span><span class="p">(</span><span class="o">/</span><span class="p">,</span> <span class="n">newval</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">os</span><span class="o">.</span><span class="n">stat_result</span><span class="p">:</span> <span class="k">pass</span> <span class="o">%%</span> <span class="nb">int</span> <span class="n">newval</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">[</span><span class="n">define_end</span><span class="p">]</span><span class="o">*/</span> </pre></div> </div> <p>The preprocessor translates this definition to a PyArg_ParseTuple() call. All arguments to the right of the slash are optional arguments.</p> </section> <section id="left-and-right-optional-arguments"> <h4><a class="toc-backref" href="#left-and-right-optional-arguments" role="doc-backlink">Left and right optional arguments</a></h4> <p>Some legacy functions contain optional arguments groups both to the left and right of a central parameter. It is debatable whether a new tool should support such functions. For completeness’ sake, this is the proposed syntax:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/*</span><span class="p">[</span><span class="n">define</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">curses</span><span class="o">.</span><span class="n">window</span><span class="o">.</span><span class="n">addch</span><span class="p">(</span><span class="n">y</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">ch</span><span class="p">:</span> <span class="s2">&quot;O&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="p">:</span> <span class="s2">&quot;l&quot;</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="k">pass</span> <span class="n">where</span> <span class="n">groups</span> <span class="o">=</span> <span class="p">[[</span><span class="n">ch</span><span class="p">],</span> <span class="p">[</span><span class="n">ch</span><span class="p">,</span> <span class="n">attr</span><span class="p">],</span> <span class="p">[</span><span class="n">y</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">ch</span><span class="p">],</span> <span class="p">[</span><span class="n">y</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">ch</span><span class="p">,</span> <span class="n">attr</span><span class="p">]]</span> <span class="p">[</span><span class="n">define_end</span><span class="p">]</span><span class="o">*/</span> </pre></div> </div> <p>Here <em>ch</em> is the central parameter, <em>attr</em> can optionally be added on the right, and the group [y, x] can optionally be added on the left.</p> <p>Essentially the rule is that all ordered combinations of the central parameter and the optional groups must be possible such that no two combinations have the same length.</p> <p>This is concisely expressed by putting the central parameter first in the list and subsequently adding the optional arguments groups to the left and right.</p> </section> </section> </section> <section id="flexibility-in-formatting"> <h2><a class="toc-backref" href="#flexibility-in-formatting" role="doc-backlink">Flexibility in formatting</a></h2> <p>If the above os.stat example is considered too compact, it can easily be formatted this way:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/*</span><span class="p">[</span><span class="n">define</span> <span class="n">posix_stat</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">os</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">path_converter</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">dir_fd</span><span class="p">:</span> <span class="n">OS_STAT_DIR_FD_CONVERTER</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">follow_symlinks</span><span class="p">:</span> <span class="s2">&quot;p&quot;</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">os</span><span class="o">.</span><span class="n">stat_result</span><span class="p">:</span> <span class="k">pass</span> <span class="o">%%</span> <span class="n">path_t</span> <span class="n">path</span> <span class="o">=</span> <span class="n">PATH_T_INITIALIZE</span><span class="p">(</span><span class="s2">&quot;stat&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="nb">int</span> <span class="n">dir_fd</span> <span class="o">=</span> <span class="n">DEFAULT_DIR_FD</span><span class="p">;</span> <span class="nb">int</span> <span class="n">follow_symlinks</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="o">%%</span> <span class="n">path_cleanup</span><span class="p">(</span><span class="o">&amp;</span><span class="n">path</span><span class="p">);</span> <span class="p">[</span><span class="n">define_end</span><span class="p">]</span><span class="o">*/</span> <span class="o">&lt;</span><span class="n">literal</span> <span class="n">C</span> <span class="n">output</span><span class="o">&gt;</span> <span class="o">/*</span><span class="p">[</span><span class="n">define_output_end</span><span class="p">]</span><span class="o">*/</span> </pre></div> </div> </section> <section id="benefits-of-a-compact-notation"> <h2><a class="toc-backref" href="#benefits-of-a-compact-notation" role="doc-backlink">Benefits of a compact notation</a></h2> <p>The advantages of a concise notation are especially obvious when a large number of parameters is involved. The argument parsing part of <code class="docutils literal notranslate"><span class="pre">_posixsubprocess.fork_exec</span></code> is fully specified by this definition:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/*</span><span class="p">[</span><span class="n">define</span> <span class="n">subprocess_fork_exec</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">_posixsubprocess</span><span class="o">.</span><span class="n">fork_exec</span><span class="p">(</span> <span class="n">process_args</span><span class="p">:</span> <span class="s2">&quot;O&quot;</span><span class="p">,</span> <span class="n">executable_list</span><span class="p">:</span> <span class="s2">&quot;O&quot;</span><span class="p">,</span> <span class="n">close_fds</span><span class="p">:</span> <span class="s2">&quot;p&quot;</span><span class="p">,</span> <span class="n">py_fds_to_keep</span><span class="p">:</span> <span class="s2">&quot;O&quot;</span><span class="p">,</span> <span class="n">cwd_obj</span><span class="p">:</span> <span class="s2">&quot;O&quot;</span><span class="p">,</span> <span class="n">env_list</span><span class="p">:</span> <span class="s2">&quot;O&quot;</span><span class="p">,</span> <span class="n">p2cread</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">p2cwrite</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">c2pread</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">c2pwrite</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">errread</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">errwrite</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">errpipe_read</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">errpipe_write</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">restore_signals</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">call_setsid</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="n">preexec_fn</span><span class="p">:</span> <span class="s2">&quot;i&quot;</span><span class="p">,</span> <span class="o">/</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span> <span class="k">pass</span> <span class="p">[</span><span class="n">define_end</span><span class="p">]</span><span class="o">*/</span> </pre></div> </div> <p>Note that the <em>preprocess</em> tool currently emits a redundant C-declaration section for this example, so the output is longer than necessary.</p> </section> <section id="easy-validation-of-the-definition"> <h2><a class="toc-backref" href="#easy-validation-of-the-definition" role="doc-backlink">Easy validation of the definition</a></h2> <p>How can an inexperienced user validate a definition like os.stat? Simply by changing os.stat to os_stat, defining missing converters and pasting the definition into the Python interactive interpreter!</p> <p>In fact, a converters.py module could be auto-generated from converters.h.</p> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference implementation</a></h2> <p>A reference implementation is available at <a class="reference external" href="http://bugs.python.org/issue16612">issue 16612</a>. Since this PEP was written under time constraints and the author is unfamiliar with the PLY toolchain, the software is written in Standard ML and utilizes the ml-yacc/ml-lex toolchain.</p> <p>The grammar is conflict-free and available in ml-yacc readable BNF form.</p> <p>Two tools are available:</p> <ul class="simple"> <li><em>printsemant</em> reads a converter header and a .c file and dumps the semantically checked parse tree to stdout.</li> <li><em>preprocess</em> reads a converter header and a .c file and dumps the preprocessed .c file to stdout.</li> </ul> <p>Known deficiencies:</p> <ul class="simple"> <li>The Python ‘test’ expression is not semantically checked. The syntax however is checked since it is part of the grammar.</li> <li>The lexer does not handle triple quoted strings.</li> <li>C declarations are parsed in a primitive way. The final implementation should utilize ‘declarator’ and ‘init-declarator’ from the C grammar.</li> <li>The <em>preprocess</em> tool does not emit code for the left-and-right optional arguments case. The <em>printsemant</em> tool can deal with this case.</li> <li>Since the <em>preprocess</em> tool generates the output from the parse tree, the original indentation of the define block is lost.</li> </ul> </section> <section id="grammar"> <h2><a class="toc-backref" href="#grammar" role="doc-backlink">Grammar</a></h2> <blockquote> <div>TBD: The grammar exists in ml-yacc readable form, but should probably be included here in EBNF notation.</div></blockquote> </section> <section id="comparison-with-pep-436"> <h2><a class="toc-backref" href="#comparison-with-pep-436" role="doc-backlink">Comparison with PEP 436</a></h2> <p>The author of this PEP has the following concerns about the DSL proposed in <a class="pep reference internal" href="../pep-0436/" title="PEP 436 – The Argument Clinic DSL">PEP 436</a>:</p> <ul> <li>The whitespace sensitive configuration file like syntax looks out of place in a C file.</li> <li>The structure of the function definition gets lost in the per-parameter specifications. Keywords like positional-only, required and keyword-only are scattered across too many different places.<p>By contrast, in the alternative DSL the structure of the function definition can be understood at a single glance.</p> </li> <li>The <a class="pep reference internal" href="../pep-0436/" title="PEP 436 – The Argument Clinic DSL">PEP 436</a> DSL has 14 documented flags and at least one undocumented (allow_fd) flag. Figuring out which of the 2**15 possible combinations are valid places an unnecessary burden on the user.<p>Experience with the <a class="pep reference internal" href="../pep-3118/" title="PEP 3118 – Revising the buffer protocol">PEP 3118</a> buffer flags has shown that sorting out (and exhaustively testing!) valid combinations is an extremely tedious task. The <a class="pep reference internal" href="../pep-3118/" title="PEP 3118 – Revising the buffer protocol">PEP 3118</a> flags are still not well understood by many people.</p> <p>By contrast, the alternative DSL has a central file Include/converters.h that can be quickly searched for the desired converter. Many of the converters are already known, perhaps even memorized by people (due to frequent use).</p> </li> <li>The <a class="pep reference internal" href="../pep-0436/" title="PEP 436 – The Argument Clinic DSL">PEP 436</a> DSL allows too much freedom. Types can apparently be omitted, the preprocessor accepts (and ignores) unknown keywords, sometimes adding white space after a docstring results in an assertion error.<p>The alternative DSL on the other hand allows no such freedoms. Omitting converter or return value annotations is plainly a syntax error. The LALR(1) grammar is unambiguous and specified for the complete translation unit.</p> </li> </ul> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is licensed under the <a class="reference external" href="http://www.opencontent.org/openpub/">Open Publication License</a>.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0437.rst">https://github.com/python/peps/blob/main/peps/pep-0437.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0437.rst">2025-02-01 08:59:27 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rejection-notice">Rejection Notice</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#scope">Scope</a></li> <li><a class="reference internal" href="#dsl-overview">DSL overview</a><ul> <li><a class="reference internal" href="#type-safety-and-annotations">Type safety and annotations</a></li> <li><a class="reference internal" href="#include-converters-h">Include/converters.h</a></li> <li><a class="reference internal" href="#function-specifications">Function specifications</a><ul> <li><a class="reference internal" href="#keyword-arguments">Keyword arguments</a><ul> <li><a class="reference internal" href="#define-block">Define block</a></li> <li><a class="reference internal" href="#declaration">Declaration</a></li> <li><a class="reference internal" href="#c-declarations">C-declarations</a></li> <li><a class="reference internal" href="#cleanup">Cleanup</a></li> <li><a class="reference internal" href="#output">Output</a></li> </ul> </li> <li><a class="reference internal" href="#positional-only-arguments">Positional-only arguments</a></li> <li><a class="reference internal" href="#left-and-right-optional-arguments">Left and right optional arguments</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#flexibility-in-formatting">Flexibility in formatting</a></li> <li><a class="reference internal" href="#benefits-of-a-compact-notation">Benefits of a compact notation</a></li> <li><a class="reference internal" href="#easy-validation-of-the-definition">Easy validation of the definition</a></li> <li><a class="reference internal" href="#reference-implementation">Reference implementation</a></li> <li><a class="reference internal" href="#grammar">Grammar</a></li> <li><a class="reference internal" href="#comparison-with-pep-436">Comparison with PEP 436</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-0437.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>

Pages: 1 2 3 4 5 6 7 8 9 10