872 lines
74 KiB
HTML
872 lines
74 KiB
HTML
|
|
|||
|
<!DOCTYPE html>
|
|||
|
<html lang="en">
|
|||
|
<head>
|
|||
|
<meta charset="utf-8">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
<meta name="color-scheme" content="light dark">
|
|||
|
<title>PEP 681 – Data Class Transforms | peps.python.org</title>
|
|||
|
<link rel="shortcut icon" href="../_static/py.png">
|
|||
|
<link rel="canonical" href="https://peps.python.org/pep-0681/">
|
|||
|
<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 681 – Data Class Transforms | peps.python.org'>
|
|||
|
<meta property="og:description" content="PEP 557 introduced the dataclass to the Python stdlib. Several popular libraries have behaviors that are similar to dataclasses, but these behaviors cannot be described using standard type annotations. Such projects include attrs, pydantic, and object r...">
|
|||
|
<meta property="og:type" content="website">
|
|||
|
<meta property="og:url" content="https://peps.python.org/pep-0681/">
|
|||
|
<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="PEP 557 introduced the dataclass to the Python stdlib. Several popular libraries have behaviors that are similar to dataclasses, but these behaviors cannot be described using standard type annotations. Such projects include attrs, pydantic, and object r...">
|
|||
|
<meta name="theme-color" content="#3776ab">
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
|||
|
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Following system colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<circle cx="12" cy="12" r="9"></circle>
|
|||
|
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Selected dark colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|||
|
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Selected light colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<circle cx="12" cy="12" r="5"></circle>
|
|||
|
<line x1="12" y1="1" x2="12" y2="3"></line>
|
|||
|
<line x1="12" y1="21" x2="12" y2="23"></line>
|
|||
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
|||
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
|||
|
<line x1="1" y1="12" x2="3" y2="12"></line>
|
|||
|
<line x1="21" y1="12" x2="23" y2="12"></line>
|
|||
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
|||
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
</svg>
|
|||
|
<script>
|
|||
|
|
|||
|
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
|
|||
|
</script>
|
|||
|
<section id="pep-page-section">
|
|||
|
<header>
|
|||
|
<h1>Python Enhancement Proposals</h1>
|
|||
|
<ul class="breadcrumbs">
|
|||
|
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
|||
|
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
|||
|
<li>PEP 681</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 681 – Data Class Transforms</h1>
|
|||
|
<dl class="rfc2822 field-list simple">
|
|||
|
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd">Erik De Bonte <erikd at microsoft.com>,
|
|||
|
Eric Traut <erictr at microsoft.com></dd>
|
|||
|
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even">Jelle Zijlstra <jelle.zijlstra at gmail.com></dd>
|
|||
|
<dt class="field-odd">Discussions-To<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/thread/EAALIHA3XEDFDNG2NRXTI3ERFPAD65Z4/">Typing-SIG thread</a></dd>
|
|||
|
<dt class="field-even">Status<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</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">Topic<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even"><a class="reference external" href="../topic/typing/">Typing</a></dd>
|
|||
|
<dt class="field-odd">Created<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd">02-Dec-2021</dd>
|
|||
|
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even">3.11</dd>
|
|||
|
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/thread/TXL5LEHYX5ZJAZPZ7YHZU7MVFXMVUVWL/" title="Typing-SIG thread">24-Apr-2021</a>,
|
|||
|
<a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/thread/EAALIHA3XEDFDNG2NRXTI3ERFPAD65Z4/" title="Typing-SIG thread">13-Dec-2021</a>,
|
|||
|
<a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/thread/BW6CB6URC4BCN54QSG2STINU2M7V4TQQ/" title="Typing-SIG thread">22-Feb-2022</a></dd>
|
|||
|
<dt class="field-even">Resolution<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/python-dev@python.org/message/R4A2IYLGFHKFDYJPSDA5NFJ6N7KRPJ6D/">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="#motivation">Motivation</a></li>
|
|||
|
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
|||
|
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
|||
|
<li><a class="reference internal" href="#the-dataclass-transform-decorator">The <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> decorator</a><ul>
|
|||
|
<li><a class="reference internal" href="#decorator-function-example">Decorator function example</a></li>
|
|||
|
<li><a class="reference internal" href="#class-example">Class example</a></li>
|
|||
|
<li><a class="reference internal" href="#metaclass-example">Metaclass example</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#decorator-function-and-class-metaclass-parameters">Decorator function and class/metaclass parameters</a></li>
|
|||
|
<li><a class="reference internal" href="#dataclass-transform-parameters"><code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> parameters</a><ul>
|
|||
|
<li><a class="reference internal" href="#id1">Decorator function example</a></li>
|
|||
|
<li><a class="reference internal" href="#id2">Class example</a></li>
|
|||
|
<li><a class="reference internal" href="#id3">Metaclass example</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#field-specifiers">Field specifiers</a><ul>
|
|||
|
<li><a class="reference internal" href="#field-specifier-parameters">Field specifier parameters</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#runtime-behavior">Runtime behavior</a></li>
|
|||
|
<li><a class="reference internal" href="#dataclass-semantics">Dataclass semantics</a></li>
|
|||
|
<li><a class="reference internal" href="#undefined-behavior">Undefined behavior</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
|
|||
|
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
|
|||
|
<li><a class="reference internal" href="#auto-attribs-parameter"><code class="docutils literal notranslate"><span class="pre">auto_attribs</span></code> parameter</a></li>
|
|||
|
<li><a class="reference internal" href="#cmp-parameter"><code class="docutils literal notranslate"><span class="pre">cmp</span></code> parameter</a></li>
|
|||
|
<li><a class="reference internal" href="#automatic-field-name-aliasing">Automatic field name aliasing</a></li>
|
|||
|
<li><a class="reference internal" href="#alternate-field-ordering-algorithms">Alternate field ordering algorithms</a></li>
|
|||
|
<li><a class="reference internal" href="#fields-redeclared-in-subclasses">Fields redeclared in subclasses</a></li>
|
|||
|
<li><a class="reference internal" href="#django-primary-and-foreign-keys">Django primary and foreign keys</a></li>
|
|||
|
<li><a class="reference internal" href="#class-wide-default-values">Class-wide default values</a></li>
|
|||
|
<li><a class="reference internal" href="#descriptor-typed-field-support">Descriptor-typed field support</a></li>
|
|||
|
<li><a class="reference internal" href="#converter-field-specifier-parameter"><code class="docutils literal notranslate"><span class="pre">converter</span></code> field specifier parameter</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
|||
|
</ul>
|
|||
|
</details></section>
|
|||
|
<div class="pep-banner canonical-typing-spec sticky-banner admonition attention">
|
|||
|
<p class="admonition-title">Attention</p>
|
|||
|
<p>This PEP is a historical document: see <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/dataclasses.html#dataclass-transform" title="(in typing)"><span>The dataclass_transform decorator</span></a> and
|
|||
|
<a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.dataclass_transform" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">@typing.dataclass_transform</span></code></a> for up-to-date specs and documentation. Canonical typing specs are maintained at the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/">typing specs site</a>; runtime typing behaviour is described in the CPython documentation.</p>
|
|||
|
<p class="close-button">×</p>
|
|||
|
<p>See the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/meta.html">typing specification update process</a> for how to propose changes to the typing spec.</p>
|
|||
|
</div>
|
|||
|
<section id="abstract">
|
|||
|
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
|||
|
<p><a class="pep reference internal" href="../pep-0557/" title="PEP 557 – Data Classes">PEP 557</a> introduced the dataclass to the Python stdlib. Several popular
|
|||
|
libraries have behaviors that are similar to dataclasses, but these
|
|||
|
behaviors cannot be described using standard type annotations. Such
|
|||
|
projects include attrs, pydantic, and object relational mapper (ORM)
|
|||
|
packages such as SQLAlchemy and Django.</p>
|
|||
|
<p>Most type checkers, linters and language servers have full support for
|
|||
|
dataclasses. This proposal aims to generalize this functionality and
|
|||
|
provide a way for third-party libraries to indicate that certain
|
|||
|
decorator functions, classes, and metaclasses provide behaviors
|
|||
|
similar to dataclasses.</p>
|
|||
|
<p>These behaviors include:</p>
|
|||
|
<ul class="simple">
|
|||
|
<li>Synthesizing an <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method based on declared
|
|||
|
data fields.</li>
|
|||
|
<li>Optionally synthesizing <code class="docutils literal notranslate"><span class="pre">__eq__</span></code>, <code class="docutils literal notranslate"><span class="pre">__ne__</span></code>, <code class="docutils literal notranslate"><span class="pre">__lt__</span></code>,
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__le__</span></code>, <code class="docutils literal notranslate"><span class="pre">__gt__</span></code> and <code class="docutils literal notranslate"><span class="pre">__ge__</span></code> methods.</li>
|
|||
|
<li>Supporting “frozen” classes, a way to enforce immutability during
|
|||
|
static type checking.</li>
|
|||
|
<li>Supporting “field specifiers”, which describe attributes of
|
|||
|
individual fields that a static type checker must be aware of,
|
|||
|
such as whether a default value is provided for the field.</li>
|
|||
|
</ul>
|
|||
|
<p>The full behavior of the stdlib dataclass is described in the <a class="reference external" href="https://docs.python.org/3.11/library/dataclasses.html">Python
|
|||
|
documentation</a>.</p>
|
|||
|
<p>This proposal does not affect CPython directly except for the addition
|
|||
|
of a <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> decorator in <code class="docutils literal notranslate"><span class="pre">typing.py</span></code>.</p>
|
|||
|
</section>
|
|||
|
<section id="motivation">
|
|||
|
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
|||
|
<p>There is no existing, standard way for libraries with dataclass-like
|
|||
|
semantics to declare their behavior to type checkers. To work around
|
|||
|
this limitation, Mypy custom plugins have been developed for many of
|
|||
|
these libraries, but these plugins don’t work with other type
|
|||
|
checkers, linters or language servers. They are also costly to
|
|||
|
maintain for library authors, and they require that Python developers
|
|||
|
know about the existence of these plugins and download and configure
|
|||
|
them within their environment.</p>
|
|||
|
</section>
|
|||
|
<section id="rationale">
|
|||
|
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
|||
|
<p>The intent of this proposal is not to support every feature of every
|
|||
|
library with dataclass-like semantics, but rather to make it possible
|
|||
|
to use the most common features of these libraries in a way that is
|
|||
|
compatible with static type checking. If a user values these libraries
|
|||
|
and also values static type checking, they may need to avoid using
|
|||
|
certain features or make small adjustments to the way they use them.
|
|||
|
That’s already true for the Mypy custom plugins, which
|
|||
|
don’t support every feature of every dataclass-like library.</p>
|
|||
|
<p>As new features are added to dataclasses in the future, we intend, when
|
|||
|
appropriate, to add support for those features on
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> as well. Keeping these two feature sets in
|
|||
|
sync will make it easier for dataclass users to understand and use
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> and will simplify the maintenance of dataclass
|
|||
|
support in type checkers.</p>
|
|||
|
<p>Additionally, we will consider adding <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> support
|
|||
|
in the future for features that have been adopted by multiple
|
|||
|
third-party libraries but are not supported by dataclasses.</p>
|
|||
|
</section>
|
|||
|
<section id="specification">
|
|||
|
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
|||
|
<section id="the-dataclass-transform-decorator">
|
|||
|
<h3><a class="toc-backref" href="#the-dataclass-transform-decorator" role="doc-backlink">The <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> decorator</a></h3>
|
|||
|
<p>This specification introduces a new decorator function in
|
|||
|
the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module named <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code>. This decorator
|
|||
|
can be applied to either a function that is itself a decorator,
|
|||
|
a class, or a metaclass. The presence of
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> tells a static type checker that the decorated
|
|||
|
function, class, or metaclass performs runtime “magic” that transforms
|
|||
|
a class, endowing it with dataclass-like behaviors.</p>
|
|||
|
<p>If <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> is applied to a function, using the decorated
|
|||
|
function as a decorator is assumed to apply dataclass-like semantics.
|
|||
|
If the function has overloads, the <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> decorator can
|
|||
|
be applied to the implementation of the function or any one, but not more
|
|||
|
than one, of the overloads. When applied to an overload, the
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> decorator still impacts all usage of the
|
|||
|
function.</p>
|
|||
|
<p>If <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> is applied to a class, dataclass-like
|
|||
|
semantics will be assumed for any class that directly or indirectly
|
|||
|
derives from the decorated class or uses the decorated class as a
|
|||
|
metaclass. Attributes on the decorated class and its base classes
|
|||
|
are not considered to be fields.</p>
|
|||
|
<p>Examples of each approach are shown in the following sections. Each
|
|||
|
example creates a <code class="docutils literal notranslate"><span class="pre">CustomerModel</span></code> class with dataclass-like semantics.
|
|||
|
The implementation of the decorated objects is omitted for brevity,
|
|||
|
but we assume that they modify classes in the following ways:</p>
|
|||
|
<ul class="simple">
|
|||
|
<li>They synthesize an <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method using data fields declared
|
|||
|
within the class and its parent classes.</li>
|
|||
|
<li>They synthesize <code class="docutils literal notranslate"><span class="pre">__eq__</span></code> and <code class="docutils literal notranslate"><span class="pre">__ne__</span></code> methods.</li>
|
|||
|
</ul>
|
|||
|
<p>Type checkers supporting this PEP will recognize that the
|
|||
|
<code class="docutils literal notranslate"><span class="pre">CustomerModel</span></code> class can be instantiated using the synthesized
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__init__</span></code> method:</p>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Using positional arguments</span>
|
|||
|
<span class="n">c1</span> <span class="o">=</span> <span class="n">CustomerModel</span><span class="p">(</span><span class="mi">327</span><span class="p">,</span> <span class="s2">"John Smith"</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="c1"># Using keyword arguments</span>
|
|||
|
<span class="n">c2</span> <span class="o">=</span> <span class="n">CustomerModel</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">327</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s2">"John Smith"</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="c1"># These calls will generate runtime errors and should be flagged as</span>
|
|||
|
<span class="c1"># errors by a static type checker.</span>
|
|||
|
<span class="n">c3</span> <span class="o">=</span> <span class="n">CustomerModel</span><span class="p">()</span>
|
|||
|
<span class="n">c4</span> <span class="o">=</span> <span class="n">CustomerModel</span><span class="p">(</span><span class="mi">327</span><span class="p">,</span> <span class="n">first_name</span><span class="o">=</span><span class="s2">"John"</span><span class="p">)</span>
|
|||
|
<span class="n">c5</span> <span class="o">=</span> <span class="n">CustomerModel</span><span class="p">(</span><span class="mi">327</span><span class="p">,</span> <span class="s2">"John Smith"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<section id="decorator-function-example">
|
|||
|
<h4><a class="toc-backref" href="#decorator-function-example" role="doc-backlink">Decorator function example</a></h4>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"_T"</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="c1"># The ``create_model`` decorator is defined by a library.</span>
|
|||
|
<span class="c1"># This could be in a type stub or inline.</span>
|
|||
|
<span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">()</span>
|
|||
|
<span class="k">def</span> <span class="nf">create_model</span><span class="p">(</span><span class="bp">cls</span><span class="p">:</span> <span class="n">Type</span><span class="p">[</span><span class="n">_T</span><span class="p">])</span> <span class="o">-></span> <span class="n">Type</span><span class="p">[</span><span class="n">_T</span><span class="p">]:</span>
|
|||
|
<span class="bp">cls</span><span class="o">.</span><span class="fm">__init__</span> <span class="o">=</span> <span class="o">...</span>
|
|||
|
<span class="bp">cls</span><span class="o">.</span><span class="fm">__eq__</span> <span class="o">=</span> <span class="o">...</span>
|
|||
|
<span class="bp">cls</span><span class="o">.</span><span class="fm">__ne__</span> <span class="o">=</span> <span class="o">...</span>
|
|||
|
<span class="k">return</span> <span class="bp">cls</span>
|
|||
|
|
|||
|
<span class="c1"># The ``create_model`` decorator can now be used to create new model</span>
|
|||
|
<span class="c1"># classes, like this:</span>
|
|||
|
<span class="nd">@create_model</span>
|
|||
|
<span class="k">class</span> <span class="nc">CustomerModel</span><span class="p">:</span>
|
|||
|
<span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
<section id="class-example">
|
|||
|
<h4><a class="toc-backref" href="#class-example" role="doc-backlink">Class example</a></h4>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># The ``ModelBase`` class is defined by a library. This could be in</span>
|
|||
|
<span class="c1"># a type stub or inline.</span>
|
|||
|
<span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">()</span>
|
|||
|
<span class="k">class</span> <span class="nc">ModelBase</span><span class="p">:</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># The ``ModelBase`` class can now be used to create new model</span>
|
|||
|
<span class="c1"># subclasses, like this:</span>
|
|||
|
<span class="k">class</span> <span class="nc">CustomerModel</span><span class="p">(</span><span class="n">ModelBase</span><span class="p">):</span>
|
|||
|
<span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
<section id="metaclass-example">
|
|||
|
<h4><a class="toc-backref" href="#metaclass-example" role="doc-backlink">Metaclass example</a></h4>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># The ``ModelMeta`` metaclass and ``ModelBase`` class are defined by</span>
|
|||
|
<span class="c1"># a library. This could be in a type stub or inline.</span>
|
|||
|
<span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">()</span>
|
|||
|
<span class="k">class</span> <span class="nc">ModelMeta</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="k">class</span> <span class="nc">ModelBase</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ModelMeta</span><span class="p">):</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># The ``ModelBase`` class can now be used to create new model</span>
|
|||
|
<span class="c1"># subclasses, like this:</span>
|
|||
|
<span class="k">class</span> <span class="nc">CustomerModel</span><span class="p">(</span><span class="n">ModelBase</span><span class="p">):</span>
|
|||
|
<span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="decorator-function-and-class-metaclass-parameters">
|
|||
|
<h3><a class="toc-backref" href="#decorator-function-and-class-metaclass-parameters" role="doc-backlink">Decorator function and class/metaclass parameters</a></h3>
|
|||
|
<p>A decorator function, class, or metaclass that provides dataclass-like
|
|||
|
functionality may accept parameters that modify certain behaviors.
|
|||
|
This specification defines the following parameters that static type
|
|||
|
checkers must honor if they are used by a dataclass transform. Each of
|
|||
|
these parameters accepts a bool argument, and it must be possible for
|
|||
|
the bool value (<code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code>) to be statically evaluated.</p>
|
|||
|
<ul class="simple">
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">eq</span></code>, <code class="docutils literal notranslate"><span class="pre">order</span></code>, <code class="docutils literal notranslate"><span class="pre">frozen</span></code>, <code class="docutils literal notranslate"><span class="pre">init</span></code> and <code class="docutils literal notranslate"><span class="pre">unsafe_hash</span></code> are parameters
|
|||
|
supported in the stdlib dataclass, with meanings defined in
|
|||
|
<a class="pep reference internal" href="../pep-0557/#id7" title="PEP 557 – Data Classes § 7">PEP 557</a>.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">kw_only</span></code>, <code class="docutils literal notranslate"><span class="pre">match_args</span></code> and <code class="docutils literal notranslate"><span class="pre">slots</span></code> are parameters supported
|
|||
|
in the stdlib dataclass, first introduced in Python 3.10.</li>
|
|||
|
</ul>
|
|||
|
</section>
|
|||
|
<section id="dataclass-transform-parameters">
|
|||
|
<h3><a class="toc-backref" href="#dataclass-transform-parameters" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> parameters</a></h3>
|
|||
|
<p>Parameters to <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> allow for some basic
|
|||
|
customization of default behaviors:</p>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"_T"</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="nf">dataclass_transform</span><span class="p">(</span>
|
|||
|
<span class="o">*</span><span class="p">,</span>
|
|||
|
<span class="n">eq_default</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="n">order_default</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">kw_only_default</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">field_specifiers</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">type</span> <span class="o">|</span> <span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="o">...</span><span class="p">]</span> <span class="o">=</span> <span class="p">(),</span>
|
|||
|
<span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span>
|
|||
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[[</span><span class="n">_T</span><span class="p">],</span> <span class="n">_T</span><span class="p">]:</span> <span class="o">...</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<ul class="simple">
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">eq_default</span></code> indicates whether the <code class="docutils literal notranslate"><span class="pre">eq</span></code> parameter is assumed to
|
|||
|
be True or False if it is omitted by the caller. If not specified,
|
|||
|
<code class="docutils literal notranslate"><span class="pre">eq_default</span></code> will default to True (the default assumption for
|
|||
|
dataclass).</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">order_default</span></code> indicates whether the <code class="docutils literal notranslate"><span class="pre">order</span></code> parameter is
|
|||
|
assumed to be True or False if it is omitted by the caller. If not
|
|||
|
specified, <code class="docutils literal notranslate"><span class="pre">order_default</span></code> will default to False (the default
|
|||
|
assumption for dataclass).</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">kw_only_default</span></code> indicates whether the <code class="docutils literal notranslate"><span class="pre">kw_only</span></code> parameter is
|
|||
|
assumed to be True or False if it is omitted by the caller. If not
|
|||
|
specified, <code class="docutils literal notranslate"><span class="pre">kw_only_default</span></code> will default to False (the default
|
|||
|
assumption for dataclass).</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">field_specifiers</span></code> specifies a static list of supported classes
|
|||
|
that describe fields. Some libraries also supply functions to
|
|||
|
allocate instances of field specifiers, and those functions may
|
|||
|
also be specified in this tuple. If not specified,
|
|||
|
<code class="docutils literal notranslate"><span class="pre">field_specifiers</span></code> will default to an empty tuple (no field
|
|||
|
specifiers supported). The standard dataclass behavior supports
|
|||
|
only one type of field specifier called <code class="docutils literal notranslate"><span class="pre">Field</span></code> plus a helper
|
|||
|
function (<code class="docutils literal notranslate"><span class="pre">field</span></code>) that instantiates this class, so if we were
|
|||
|
describing the stdlib dataclass behavior, we would provide the
|
|||
|
tuple argument <code class="docutils literal notranslate"><span class="pre">(dataclasses.Field,</span> <span class="pre">dataclasses.field)</span></code>.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">kwargs</span></code> allows arbitrary additional keyword args to be passed to
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code>. This gives type checkers the freedom to
|
|||
|
support experimental parameters without needing to wait for changes
|
|||
|
in <code class="docutils literal notranslate"><span class="pre">typing.py</span></code>. Type checkers should report errors for any
|
|||
|
unrecognized parameters.</li>
|
|||
|
</ul>
|
|||
|
<p>In the future, we may add additional parameters to
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> as needed to support common behaviors in user
|
|||
|
code. These additions will be made after reaching consensus on
|
|||
|
typing-sig rather than via additional PEPs.</p>
|
|||
|
<p>The following sections provide additional examples showing how these
|
|||
|
parameters are used.</p>
|
|||
|
<section id="id1">
|
|||
|
<h4><a class="toc-backref" href="#id1" role="doc-backlink">Decorator function example</a></h4>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Indicate that the ``create_model`` function assumes keyword-only</span>
|
|||
|
<span class="c1"># parameters for the synthesized ``__init__`` method unless it is</span>
|
|||
|
<span class="c1"># invoked with ``kw_only=False``. It always synthesizes order-related</span>
|
|||
|
<span class="c1"># methods and provides no way to override this behavior.</span>
|
|||
|
<span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">(</span><span class="n">kw_only_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">order_default</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|||
|
<span class="k">def</span> <span class="nf">create_model</span><span class="p">(</span>
|
|||
|
<span class="o">*</span><span class="p">,</span>
|
|||
|
<span class="n">frozen</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">kw_only</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Type</span><span class="p">[</span><span class="n">_T</span><span class="p">]],</span> <span class="n">Type</span><span class="p">[</span><span class="n">_T</span><span class="p">]]:</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># Example of how this decorator would be used by code that imports</span>
|
|||
|
<span class="c1"># from this library:</span>
|
|||
|
<span class="nd">@create_model</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">kw_only</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
|||
|
<span class="k">class</span> <span class="nc">CustomerModel</span><span class="p">:</span>
|
|||
|
<span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
<section id="id2">
|
|||
|
<h4><a class="toc-backref" href="#id2" role="doc-backlink">Class example</a></h4>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Indicate that classes that derive from this class default to</span>
|
|||
|
<span class="c1"># synthesizing comparison methods.</span>
|
|||
|
<span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">(</span><span class="n">eq_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">order_default</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|||
|
<span class="k">class</span> <span class="nc">ModelBase</span><span class="p">:</span>
|
|||
|
<span class="k">def</span> <span class="nf">__init_subclass__</span><span class="p">(</span>
|
|||
|
<span class="bp">cls</span><span class="p">,</span>
|
|||
|
<span class="o">*</span><span class="p">,</span>
|
|||
|
<span class="n">init</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="n">frozen</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">eq</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="n">order</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="p">):</span>
|
|||
|
<span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># Example of how this class would be used by code that imports</span>
|
|||
|
<span class="c1"># from this library:</span>
|
|||
|
<span class="k">class</span> <span class="nc">CustomerModel</span><span class="p">(</span>
|
|||
|
<span class="n">ModelBase</span><span class="p">,</span>
|
|||
|
<span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="n">eq</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">order</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="p">):</span>
|
|||
|
<span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
<section id="id3">
|
|||
|
<h4><a class="toc-backref" href="#id3" role="doc-backlink">Metaclass example</a></h4>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Indicate that classes that use this metaclass default to</span>
|
|||
|
<span class="c1"># synthesizing comparison methods.</span>
|
|||
|
<span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">(</span><span class="n">eq_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">order_default</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|||
|
<span class="k">class</span> <span class="nc">ModelMeta</span><span class="p">(</span><span class="nb">type</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">name</span><span class="p">,</span>
|
|||
|
<span class="n">bases</span><span class="p">,</span>
|
|||
|
<span class="n">namespace</span><span class="p">,</span>
|
|||
|
<span class="o">*</span><span class="p">,</span>
|
|||
|
<span class="n">init</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="n">frozen</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">eq</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="n">order</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="p">):</span>
|
|||
|
<span class="o">...</span>
|
|||
|
|
|||
|
<span class="k">class</span> <span class="nc">ModelBase</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ModelMeta</span><span class="p">):</span>
|
|||
|
<span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># Example of how this class would be used by code that imports</span>
|
|||
|
<span class="c1"># from this library:</span>
|
|||
|
<span class="k">class</span> <span class="nc">CustomerModel</span><span class="p">(</span>
|
|||
|
<span class="n">ModelBase</span><span class="p">,</span>
|
|||
|
<span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="n">eq</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="n">order</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="p">):</span>
|
|||
|
<span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="field-specifiers">
|
|||
|
<h3><a class="toc-backref" href="#field-specifiers" role="doc-backlink">Field specifiers</a></h3>
|
|||
|
<p>Most libraries that support dataclass-like semantics provide one or
|
|||
|
more “field specifier” types that allow a class definition to provide
|
|||
|
additional metadata about each field in the class. This metadata can
|
|||
|
describe, for example, default values, or indicate whether the field
|
|||
|
should be included in the synthesized <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method.</p>
|
|||
|
<p>Field specifiers can be omitted in cases where additional metadata is
|
|||
|
not required:</p>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@dataclass</span>
|
|||
|
<span class="k">class</span> <span class="nc">Employee</span><span class="p">:</span>
|
|||
|
<span class="c1"># Field with no specifier</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
|
|||
|
<span class="c1"># Field that uses field specifier class instance</span>
|
|||
|
<span class="n">age</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="n">field</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="c1"># Field with type annotation and simple initializer to</span>
|
|||
|
<span class="c1"># describe default value</span>
|
|||
|
<span class="n">is_paid_hourly</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span>
|
|||
|
|
|||
|
<span class="c1"># Not a field (but rather a class variable) because type</span>
|
|||
|
<span class="c1"># annotation is not provided.</span>
|
|||
|
<span class="n">office_number</span> <span class="o">=</span> <span class="s2">"unassigned"</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<section id="field-specifier-parameters">
|
|||
|
<h4><a class="toc-backref" href="#field-specifier-parameters" role="doc-backlink">Field specifier parameters</a></h4>
|
|||
|
<p>Libraries that support dataclass-like semantics and support field
|
|||
|
specifier classes typically use common parameter names to construct
|
|||
|
these field specifiers. This specification formalizes the names and
|
|||
|
meanings of the parameters that must be understood for static type
|
|||
|
checkers. These standardized parameters must be keyword-only.</p>
|
|||
|
<p>These parameters are a superset of those supported by
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclasses.field</span></code>, excluding those that do not have an impact on
|
|||
|
type checking such as <code class="docutils literal notranslate"><span class="pre">compare</span></code> and <code class="docutils literal notranslate"><span class="pre">hash</span></code>.</p>
|
|||
|
<p>Field specifier classes are allowed to use other
|
|||
|
parameters in their constructors, and those parameters can be
|
|||
|
positional and may use other names.</p>
|
|||
|
<ul class="simple">
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">init</span></code> is an optional bool parameter that indicates whether the
|
|||
|
field should be included in the synthesized <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method. If
|
|||
|
unspecified, <code class="docutils literal notranslate"><span class="pre">init</span></code> defaults to True. Field specifier functions
|
|||
|
can use overloads that implicitly specify the value of <code class="docutils literal notranslate"><span class="pre">init</span></code>
|
|||
|
using a literal bool value type
|
|||
|
(<code class="docutils literal notranslate"><span class="pre">Literal[False]</span></code> or <code class="docutils literal notranslate"><span class="pre">Literal[True]</span></code>).</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">default</span></code> is an optional parameter that provides the default value
|
|||
|
for the field.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">default_factory</span></code> is an optional parameter that provides a runtime
|
|||
|
callback that returns the default value for the field. If neither
|
|||
|
<code class="docutils literal notranslate"><span class="pre">default</span></code> nor <code class="docutils literal notranslate"><span class="pre">default_factory</span></code> are specified, the field is
|
|||
|
assumed to have no default value and must be provided a value when
|
|||
|
the class is instantiated.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">factory</span></code> is an alias for <code class="docutils literal notranslate"><span class="pre">default_factory</span></code>. Stdlib dataclasses
|
|||
|
use the name <code class="docutils literal notranslate"><span class="pre">default_factory</span></code>, but attrs uses the name <code class="docutils literal notranslate"><span class="pre">factory</span></code>
|
|||
|
in many scenarios, so this alias is necessary for supporting attrs.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">kw_only</span></code> is an optional bool parameter that indicates whether the
|
|||
|
field should be marked as keyword-only. If true, the field will be
|
|||
|
keyword-only. If false, it will not be keyword-only. If unspecified,
|
|||
|
the value of the <code class="docutils literal notranslate"><span class="pre">kw_only</span></code> parameter on the object decorated with
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> will be used, or if that is unspecified, the
|
|||
|
value of <code class="docutils literal notranslate"><span class="pre">kw_only_default</span></code> on <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> will be used.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">alias</span></code> is an optional str parameter that provides an alternative
|
|||
|
name for the field. This alternative name is used in the synthesized
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__init__</span></code> method.</li>
|
|||
|
</ul>
|
|||
|
<p>It is an error to specify more than one of <code class="docutils literal notranslate"><span class="pre">default</span></code>,
|
|||
|
<code class="docutils literal notranslate"><span class="pre">default_factory</span></code> and <code class="docutils literal notranslate"><span class="pre">factory</span></code>.</p>
|
|||
|
<p>This example demonstrates the above:</p>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Library code (within type stub or inline)</span>
|
|||
|
<span class="c1"># In this library, passing a resolver means that init must be False,</span>
|
|||
|
<span class="c1"># and the overload with Literal[False] enforces that.</span>
|
|||
|
<span class="nd">@overload</span>
|
|||
|
<span class="k">def</span> <span class="nf">model_field</span><span class="p">(</span>
|
|||
|
<span class="o">*</span><span class="p">,</span>
|
|||
|
<span class="n">default</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="o">...</span><span class="p">,</span>
|
|||
|
<span class="n">resolver</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[],</span> <span class="n">Any</span><span class="p">],</span>
|
|||
|
<span class="n">init</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="kc">False</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Any</span><span class="p">:</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="nd">@overload</span>
|
|||
|
<span class="k">def</span> <span class="nf">model_field</span><span class="p">(</span>
|
|||
|
<span class="o">*</span><span class="p">,</span>
|
|||
|
<span class="n">default</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="o">...</span><span class="p">,</span>
|
|||
|
<span class="n">resolver</span><span class="p">:</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
|||
|
<span class="n">init</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Any</span><span class="p">:</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">(</span>
|
|||
|
<span class="n">kw_only_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="n">field_specifiers</span><span class="o">=</span><span class="p">(</span><span class="n">model_field</span><span class="p">,</span> <span class="p">))</span>
|
|||
|
<span class="k">def</span> <span class="nf">create_model</span><span class="p">(</span>
|
|||
|
<span class="o">*</span><span class="p">,</span>
|
|||
|
<span class="n">init</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Type</span><span class="p">[</span><span class="n">_T</span><span class="p">]],</span> <span class="n">Type</span><span class="p">[</span><span class="n">_T</span><span class="p">]]:</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># Code that imports this library:</span>
|
|||
|
<span class="nd">@create_model</span><span class="p">(</span><span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
|||
|
<span class="k">class</span> <span class="nc">CustomerModel</span><span class="p">:</span>
|
|||
|
<span class="nb">id</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">model_field</span><span class="p">(</span><span class="n">resolver</span><span class="o">=</span><span class="k">lambda</span> <span class="p">:</span> <span class="mi">0</span><span class="p">)</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="runtime-behavior">
|
|||
|
<h3><a class="toc-backref" href="#runtime-behavior" role="doc-backlink">Runtime behavior</a></h3>
|
|||
|
<p>At runtime, the <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> decorator’s only effect is to
|
|||
|
set an attribute named <code class="docutils literal notranslate"><span class="pre">__dataclass_transform__</span></code> on the decorated
|
|||
|
function or class to support introspection. The value of the attribute
|
|||
|
should be a dict mapping the names of the <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code>
|
|||
|
parameters to their values.</p>
|
|||
|
<p>For example:</p>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
|
|||
|
<span class="s2">"eq_default"</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
|
|||
|
<span class="s2">"order_default"</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="s2">"kw_only_default"</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
|
|||
|
<span class="s2">"field_specifiers"</span><span class="p">:</span> <span class="p">(),</span>
|
|||
|
<span class="s2">"kwargs"</span><span class="p">:</span> <span class="p">{}</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
<section id="dataclass-semantics">
|
|||
|
<h3><a class="toc-backref" href="#dataclass-semantics" role="doc-backlink">Dataclass semantics</a></h3>
|
|||
|
<p>Except where stated otherwise in this PEP, classes impacted by
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code>, either by inheriting from a class that is
|
|||
|
decorated with <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> or by being decorated with
|
|||
|
a function decorated with <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code>, are assumed to
|
|||
|
behave like stdlib <code class="docutils literal notranslate"><span class="pre">dataclass</span></code>.</p>
|
|||
|
<p>This includes, but is not limited to, the following semantics:</p>
|
|||
|
<ul>
|
|||
|
<li>Frozen dataclasses cannot inherit from non-frozen dataclasses. A
|
|||
|
class that has been decorated with <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> is
|
|||
|
considered neither frozen nor non-frozen, thus allowing frozen
|
|||
|
classes to inherit from it. Similarly, a class that directly
|
|||
|
specifies a metaclass that is decorated with <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code>
|
|||
|
is considered neither frozen nor non-frozen.<p>Consider these class examples:</p>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ModelBase is not considered either "frozen" or "non-frozen"</span>
|
|||
|
<span class="c1"># because it is decorated with ``dataclass_transform``</span>
|
|||
|
<span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">()</span>
|
|||
|
<span class="k">class</span> <span class="nc">ModelBase</span><span class="p">():</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># Vehicle is considered non-frozen because it does not specify</span>
|
|||
|
<span class="c1"># "frozen=True".</span>
|
|||
|
<span class="k">class</span> <span class="nc">Vehicle</span><span class="p">(</span><span class="n">ModelBase</span><span class="p">):</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
|
|||
|
<span class="c1"># Car is a frozen class that derives from Vehicle, which is a</span>
|
|||
|
<span class="c1"># non-frozen class. This is an error.</span>
|
|||
|
<span class="k">class</span> <span class="nc">Car</span><span class="p">(</span><span class="n">Vehicle</span><span class="p">,</span> <span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
|
|||
|
<span class="n">wheel_count</span><span class="p">:</span> <span class="nb">int</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>And these similar metaclass examples:</p>
|
|||
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@typing</span><span class="o">.</span><span class="n">dataclass_transform</span><span class="p">()</span>
|
|||
|
<span class="k">class</span> <span class="nc">ModelMeta</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># ModelBase is not considered either "frozen" or "non-frozen"</span>
|
|||
|
<span class="c1"># because it directly specifies ModelMeta as its metaclass.</span>
|
|||
|
<span class="k">class</span> <span class="nc">ModelBase</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ModelMeta</span><span class="p">):</span> <span class="o">...</span>
|
|||
|
|
|||
|
<span class="c1"># Vehicle is considered non-frozen because it does not specify</span>
|
|||
|
<span class="c1"># "frozen=True".</span>
|
|||
|
<span class="k">class</span> <span class="nc">Vehicle</span><span class="p">(</span><span class="n">ModelBase</span><span class="p">):</span>
|
|||
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|||
|
|
|||
|
<span class="c1"># Car is a frozen class that derives from Vehicle, which is a</span>
|
|||
|
<span class="c1"># non-frozen class. This is an error.</span>
|
|||
|
<span class="k">class</span> <span class="nc">Car</span><span class="p">(</span><span class="n">Vehicle</span><span class="p">,</span> <span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
|
|||
|
<span class="n">wheel_count</span><span class="p">:</span> <span class="nb">int</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</li>
|
|||
|
<li>Field ordering and inheritance is assumed to follow the rules
|
|||
|
specified in <a class="pep reference internal" href="../pep-0557/#inheritance" title="PEP 557 – Data Classes § Inheritance">557</a>. This includes the effects of
|
|||
|
overrides (redefining a field in a child class that has already been
|
|||
|
defined in a parent class).</li>
|
|||
|
<li><a class="pep reference internal" href="../pep-0557/#post-init-parameters" title="PEP 557 – Data Classes § post-init parameters">PEP 557 indicates</a> that
|
|||
|
all fields without default values must appear before
|
|||
|
fields with default values. Although not explicitly
|
|||
|
stated in PEP 557, this rule is ignored when <code class="docutils literal notranslate"><span class="pre">init=False</span></code>, and
|
|||
|
this specification likewise ignores this requirement in that
|
|||
|
situation. Likewise, there is no need to enforce this ordering when
|
|||
|
keyword-only parameters are used for <code class="docutils literal notranslate"><span class="pre">__init__</span></code>, so the rule is
|
|||
|
not enforced if <code class="docutils literal notranslate"><span class="pre">kw_only</span></code> semantics are in effect.</li>
|
|||
|
<li>As with <code class="docutils literal notranslate"><span class="pre">dataclass</span></code>, method synthesis is skipped if it would
|
|||
|
overwrite a method that is explicitly declared within the class.
|
|||
|
Method declarations on base classes do not cause method synthesis to
|
|||
|
be skipped.<p>For example, if a class declares an <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method explicitly,
|
|||
|
an <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method will not be synthesized for that class.</p>
|
|||
|
</li>
|
|||
|
<li>KW_ONLY sentinel values are supported as described in <a class="reference external" href="https://docs.python.org/3/library/dataclasses.html#dataclasses.KW_ONLY">the Python
|
|||
|
docs</a> and <a class="reference external" href="https://bugs.python.org/issue43532">bpo-43532</a>.</li>
|
|||
|
<li>ClassVar attributes are not considered dataclass fields and are
|
|||
|
<a class="reference external" href="https://docs.python.org/3/library/dataclasses.html#class-variables">ignored by dataclass mechanisms</a>.</li>
|
|||
|
</ul>
|
|||
|
</section>
|
|||
|
<section id="undefined-behavior">
|
|||
|
<h3><a class="toc-backref" href="#undefined-behavior" role="doc-backlink">Undefined behavior</a></h3>
|
|||
|
<p>If multiple <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> decorators are found, either on a
|
|||
|
single function (including its overloads), a single class, or within a
|
|||
|
class hierarchy, the resulting behavior is undefined. Library authors
|
|||
|
should avoid these scenarios.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="reference-implementation">
|
|||
|
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
|
|||
|
<p><a class="reference external" href="https://github.com/Microsoft/pyright">Pyright</a> contains the reference implementation of type
|
|||
|
checker support for <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code>. Pyright’s
|
|||
|
<code class="docutils literal notranslate"><span class="pre">dataClasses.ts</span></code> <a class="reference external" href="https://github.com/microsoft/pyright/blob/main/packages/pyright-internal/src/analyzer/dataClasses.ts">source file</a> would be a good
|
|||
|
starting point for understanding the implementation.</p>
|
|||
|
<p>The <a class="reference external" href="https://github.com/python-attrs/attrs/pull/796">attrs</a> and <a class="reference external" href="https://github.com/samuelcolvin/pydantic/pull/2721">pydantic</a>
|
|||
|
libraries are using <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> and serve as real-world
|
|||
|
examples of its usage.</p>
|
|||
|
</section>
|
|||
|
<section id="rejected-ideas">
|
|||
|
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
|
|||
|
<section id="auto-attribs-parameter">
|
|||
|
<h3><a class="toc-backref" href="#auto-attribs-parameter" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">auto_attribs</span></code> parameter</a></h3>
|
|||
|
<p>The attrs library supports an <code class="docutils literal notranslate"><span class="pre">auto_attribs</span></code> parameter that
|
|||
|
indicates whether class members decorated with <a class="pep reference internal" href="../pep-0526/" title="PEP 526 – Syntax for Variable Annotations">PEP 526</a> variable
|
|||
|
annotations but with no assignment should be treated as data fields.</p>
|
|||
|
<p>We considered supporting <code class="docutils literal notranslate"><span class="pre">auto_attribs</span></code> and a corresponding
|
|||
|
<code class="docutils literal notranslate"><span class="pre">auto_attribs_default</span></code> parameter, but decided against this because it
|
|||
|
is specific to attrs.</p>
|
|||
|
<p>Django does not support declaring fields using type annotations only,
|
|||
|
so Django users who leverage <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> should be aware
|
|||
|
that they should always supply assigned values.</p>
|
|||
|
</section>
|
|||
|
<section id="cmp-parameter">
|
|||
|
<h3><a class="toc-backref" href="#cmp-parameter" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">cmp</span></code> parameter</a></h3>
|
|||
|
<p>The attrs library supports a bool parameter <code class="docutils literal notranslate"><span class="pre">cmp</span></code> that is equivalent
|
|||
|
to setting both <code class="docutils literal notranslate"><span class="pre">eq</span></code> and <code class="docutils literal notranslate"><span class="pre">order</span></code> to True. We chose not to support
|
|||
|
a <code class="docutils literal notranslate"><span class="pre">cmp</span></code> parameter, since it only applies to attrs. Users can emulate
|
|||
|
the <code class="docutils literal notranslate"><span class="pre">cmp</span></code> behaviour by using the <code class="docutils literal notranslate"><span class="pre">eq</span></code> and <code class="docutils literal notranslate"><span class="pre">order</span></code> parameter names
|
|||
|
instead.</p>
|
|||
|
</section>
|
|||
|
<section id="automatic-field-name-aliasing">
|
|||
|
<h3><a class="toc-backref" href="#automatic-field-name-aliasing" role="doc-backlink">Automatic field name aliasing</a></h3>
|
|||
|
<p>The attrs library performs <a class="reference external" href="https://www.attrs.org/en/stable/init.html#private-attributes">automatic aliasing</a> of
|
|||
|
field names that start with a single underscore, stripping the
|
|||
|
underscore from the name of the corresponding <code class="docutils literal notranslate"><span class="pre">__init__</span></code> parameter.</p>
|
|||
|
<p>This proposal omits that behavior since it is specific to attrs. Users
|
|||
|
can manually alias these fields using the <code class="docutils literal notranslate"><span class="pre">alias</span></code> parameter.</p>
|
|||
|
</section>
|
|||
|
<section id="alternate-field-ordering-algorithms">
|
|||
|
<h3><a class="toc-backref" href="#alternate-field-ordering-algorithms" role="doc-backlink">Alternate field ordering algorithms</a></h3>
|
|||
|
<p>The attrs library currently supports two approaches to ordering the
|
|||
|
fields within a class:</p>
|
|||
|
<ul class="simple">
|
|||
|
<li>Dataclass order: The same ordering used by dataclasses. This is the
|
|||
|
default behavior of the older APIs (e.g. <code class="docutils literal notranslate"><span class="pre">attr.s</span></code>).</li>
|
|||
|
<li>Method Resolution Order (MRO): This is the default behavior of the
|
|||
|
newer APIs (e.g. define, mutable, frozen). Older APIs (e.g. <code class="docutils literal notranslate"><span class="pre">attr.s</span></code>)
|
|||
|
can opt into this behavior by specifying <code class="docutils literal notranslate"><span class="pre">collect_by_mro=True</span></code>.</li>
|
|||
|
</ul>
|
|||
|
<p>The resulting field orderings can differ in certain diamond-shaped
|
|||
|
multiple inheritance scenarios.</p>
|
|||
|
<p>For simplicity, this proposal does not support any field ordering
|
|||
|
other than that used by dataclasses.</p>
|
|||
|
</section>
|
|||
|
<section id="fields-redeclared-in-subclasses">
|
|||
|
<h3><a class="toc-backref" href="#fields-redeclared-in-subclasses" role="doc-backlink">Fields redeclared in subclasses</a></h3>
|
|||
|
<p>The attrs library differs from stdlib dataclasses in how it
|
|||
|
handles inherited fields that are redeclared in subclasses. The
|
|||
|
dataclass specification preserves the original order, but attrs
|
|||
|
defines a new order based on subclasses.</p>
|
|||
|
<p>For simplicity, we chose to only support the dataclass behavior.
|
|||
|
Users of attrs who rely on the attrs-specific ordering will not see
|
|||
|
the expected order of parameters in the synthesized <code class="docutils literal notranslate"><span class="pre">__init__</span></code>
|
|||
|
method.</p>
|
|||
|
</section>
|
|||
|
<section id="django-primary-and-foreign-keys">
|
|||
|
<h3><a class="toc-backref" href="#django-primary-and-foreign-keys" role="doc-backlink">Django primary and foreign keys</a></h3>
|
|||
|
<p>Django applies <a class="reference external" href="https://docs.djangoproject.com/en/4.0/topics/db/models/#automatic-primary-key-fields">additional logic for primary and foreign keys</a>. For example, it automatically adds an <code class="docutils literal notranslate"><span class="pre">id</span></code> field
|
|||
|
(and <code class="docutils literal notranslate"><span class="pre">__init__</span></code> parameter) if there is no field designated as a
|
|||
|
primary key.</p>
|
|||
|
<p>As this is not broadly applicable to dataclass libraries, this
|
|||
|
additional logic is not accommodated with this proposal, so
|
|||
|
users of Django would need to explicitly declare the <code class="docutils literal notranslate"><span class="pre">id</span></code> field.</p>
|
|||
|
</section>
|
|||
|
<section id="class-wide-default-values">
|
|||
|
<h3><a class="toc-backref" href="#class-wide-default-values" role="doc-backlink">Class-wide default values</a></h3>
|
|||
|
<p>SQLAlchemy requested that we expose a way to specify that the default
|
|||
|
value of all fields in the transformed class is <code class="docutils literal notranslate"><span class="pre">None</span></code>. It is typical
|
|||
|
that all SQLAlchemy fields are optional, and <code class="docutils literal notranslate"><span class="pre">None</span></code> indicates that
|
|||
|
the field is not set.</p>
|
|||
|
<p>We chose not to support this feature, since it is specific to
|
|||
|
SQLAlchemy. Users can manually set <code class="docutils literal notranslate"><span class="pre">default=None</span></code> on these fields
|
|||
|
instead.</p>
|
|||
|
</section>
|
|||
|
<section id="descriptor-typed-field-support">
|
|||
|
<h3><a class="toc-backref" href="#descriptor-typed-field-support" role="doc-backlink">Descriptor-typed field support</a></h3>
|
|||
|
<p>We considered adding a boolean parameter on <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code>
|
|||
|
to enable better support for fields with descriptor types, which is
|
|||
|
common in SQLAlchemy. When enabled, the type of each parameter on the
|
|||
|
synthesized <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method corresponding to a descriptor-typed
|
|||
|
field would be the type of the value parameter to the descriptor’s
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__set__</span></code> method rather than the descriptor type itself. Similarly,
|
|||
|
when setting the field, the <code class="docutils literal notranslate"><span class="pre">__set__</span></code> value type would be expected.
|
|||
|
And when getting the value of the field, its type would be expected to
|
|||
|
match the return type of <code class="docutils literal notranslate"><span class="pre">__get__</span></code>.</p>
|
|||
|
<p>This idea was based on the belief that <code class="docutils literal notranslate"><span class="pre">dataclass</span></code> did not properly
|
|||
|
support descriptor-typed fields. In fact it does, but type checkers
|
|||
|
(at least mypy and pyright) did not reflect the runtime behavior which
|
|||
|
led to our misunderstanding. For more details, see the
|
|||
|
<a class="reference external" href="https://github.com/microsoft/pyright/issues/3245">Pyright bug</a>.</p>
|
|||
|
</section>
|
|||
|
<section id="converter-field-specifier-parameter">
|
|||
|
<h3><a class="toc-backref" href="#converter-field-specifier-parameter" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">converter</span></code> field specifier parameter</a></h3>
|
|||
|
<p>The attrs library supports a <code class="docutils literal notranslate"><span class="pre">converter</span></code> field specifier parameter,
|
|||
|
which is a <code class="docutils literal notranslate"><span class="pre">Callable</span></code> that is called by the generated
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__init__</span></code> method to convert the supplied value to some other
|
|||
|
desired value. This is tricky to support since the parameter type in
|
|||
|
the synthesized <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method needs to accept uncovered values,
|
|||
|
but the resulting field is typed according to the output of the
|
|||
|
converter.</p>
|
|||
|
<p>Some aspects of this issue are detailed in a
|
|||
|
<a class="reference external" href="https://github.com/microsoft/pyright/discussions/1782?sort=old#discussioncomment-653909">Pyright discussion</a>.</p>
|
|||
|
<p>There may be no good way to support this because there’s not enough
|
|||
|
information to derive the type of the input parameter. One possible
|
|||
|
solution would be to add support for a <code class="docutils literal notranslate"><span class="pre">converter</span></code> field specifier
|
|||
|
parameter but then use the <code class="docutils literal notranslate"><span class="pre">Any</span></code> type for the corresponding
|
|||
|
parameter in the <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="copyright">
|
|||
|
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
|
|||
|
<p>This document is placed in the public domain or under the
|
|||
|
CC0-1.0-Universal license, whichever is more permissive.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<hr class="docutils" />
|
|||
|
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0681.rst">https://github.com/python/peps/blob/main/peps/pep-0681.rst</a></p>
|
|||
|
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0681.rst">2024-06-11 22:12:09 GMT</a></p>
|
|||
|
|
|||
|
</article>
|
|||
|
<nav id="pep-sidebar">
|
|||
|
<h2>Contents</h2>
|
|||
|
<ul>
|
|||
|
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
|||
|
<li><a class="reference internal" href="#motivation">Motivation</a></li>
|
|||
|
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
|||
|
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
|||
|
<li><a class="reference internal" href="#the-dataclass-transform-decorator">The <code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> decorator</a><ul>
|
|||
|
<li><a class="reference internal" href="#decorator-function-example">Decorator function example</a></li>
|
|||
|
<li><a class="reference internal" href="#class-example">Class example</a></li>
|
|||
|
<li><a class="reference internal" href="#metaclass-example">Metaclass example</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#decorator-function-and-class-metaclass-parameters">Decorator function and class/metaclass parameters</a></li>
|
|||
|
<li><a class="reference internal" href="#dataclass-transform-parameters"><code class="docutils literal notranslate"><span class="pre">dataclass_transform</span></code> parameters</a><ul>
|
|||
|
<li><a class="reference internal" href="#id1">Decorator function example</a></li>
|
|||
|
<li><a class="reference internal" href="#id2">Class example</a></li>
|
|||
|
<li><a class="reference internal" href="#id3">Metaclass example</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#field-specifiers">Field specifiers</a><ul>
|
|||
|
<li><a class="reference internal" href="#field-specifier-parameters">Field specifier parameters</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#runtime-behavior">Runtime behavior</a></li>
|
|||
|
<li><a class="reference internal" href="#dataclass-semantics">Dataclass semantics</a></li>
|
|||
|
<li><a class="reference internal" href="#undefined-behavior">Undefined behavior</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
|
|||
|
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
|
|||
|
<li><a class="reference internal" href="#auto-attribs-parameter"><code class="docutils literal notranslate"><span class="pre">auto_attribs</span></code> parameter</a></li>
|
|||
|
<li><a class="reference internal" href="#cmp-parameter"><code class="docutils literal notranslate"><span class="pre">cmp</span></code> parameter</a></li>
|
|||
|
<li><a class="reference internal" href="#automatic-field-name-aliasing">Automatic field name aliasing</a></li>
|
|||
|
<li><a class="reference internal" href="#alternate-field-ordering-algorithms">Alternate field ordering algorithms</a></li>
|
|||
|
<li><a class="reference internal" href="#fields-redeclared-in-subclasses">Fields redeclared in subclasses</a></li>
|
|||
|
<li><a class="reference internal" href="#django-primary-and-foreign-keys">Django primary and foreign keys</a></li>
|
|||
|
<li><a class="reference internal" href="#class-wide-default-values">Class-wide default values</a></li>
|
|||
|
<li><a class="reference internal" href="#descriptor-typed-field-support">Descriptor-typed field support</a></li>
|
|||
|
<li><a class="reference internal" href="#converter-field-specifier-parameter"><code class="docutils literal notranslate"><span class="pre">converter</span></code> field specifier parameter</a></li>
|
|||
|
</ul>
|
|||
|
</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-0681.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>
|