Deployed 06d49d5 to v5.0 with Zensical 0.0.43 and mike 2.2.0+zensical-0.1.0

This commit is contained in:
github-actions[bot]
2026-07-04 09:08:25 +00:00
parent 8c60711c56
commit c9285b0fb8
7 changed files with 667 additions and 317 deletions
+69 -60
View File
@@ -2078,40 +2078,45 @@
</tbody>
</table>
<p>A fixture with no <code>contexts</code> defined takes <code>Context.BASE</code> by default.</p>
<p><code>Context.BASE</code> fixtures are always included alongside whatever context you load or list — there's no way to load a non-base context in isolation:</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="c1"># also loads any Context.BASE fixtures, even though only TESTING is requested</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="k">await</span> <span class="n">load_fixtures_by_context</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">fixtures</span><span class="p">,</span> <span class="n">Context</span><span class="o">.</span><span class="n">TESTING</span><span class="p">)</span>
</span></code></pre></div>
<h3 id="custom-contexts">Custom contexts<a class="headerlink" href="#custom-contexts" title="Permanent link">&para;</a></h3>
<p>Plain strings and any <code>Enum</code> subclass are accepted wherever a <code>Context</code> enum is expected.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">enum</span><span class="w"> </span><span class="kn">import</span> <span class="n">Enum</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="k">class</span><span class="w"> </span><span class="nc">AppContext</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="n">Enum</span><span class="p">):</span>
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a> <span class="n">STAGING</span> <span class="o">=</span> <span class="s2">&quot;staging&quot;</span>
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a> <span class="n">DEMO</span> <span class="o">=</span> <span class="s2">&quot;demo&quot;</span>
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a>
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">contexts</span><span class="o">=</span><span class="p">[</span><span class="n">AppContext</span><span class="o">.</span><span class="n">STAGING</span><span class="p">])</span>
</span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="k">def</span><span class="w"> </span><span class="nf">staging_data</span><span class="p">():</span>
</span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a> <span class="k">return</span> <span class="p">[</span><span class="n">Config</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">&quot;feature_x&quot;</span><span class="p">,</span> <span class="n">enabled</span><span class="o">=</span><span class="kc">True</span><span class="p">)]</span>
</span><span id="__span-3-10"><a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a>
</span><span id="__span-3-11"><a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="k">await</span> <span class="n">load_fixtures_by_context</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">fixtures</span><span class="p">,</span> <span class="n">AppContext</span><span class="o">.</span><span class="n">STAGING</span><span class="p">)</span>
<div class="language-python highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">enum</span><span class="w"> </span><span class="kn">import</span> <span class="n">Enum</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="k">class</span><span class="w"> </span><span class="nc">AppContext</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="n">Enum</span><span class="p">):</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a> <span class="n">STAGING</span> <span class="o">=</span> <span class="s2">&quot;staging&quot;</span>
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a> <span class="n">DEMO</span> <span class="o">=</span> <span class="s2">&quot;demo&quot;</span>
</span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a>
</span><span id="__span-4-7"><a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">contexts</span><span class="o">=</span><span class="p">[</span><span class="n">AppContext</span><span class="o">.</span><span class="n">STAGING</span><span class="p">])</span>
</span><span id="__span-4-8"><a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="k">def</span><span class="w"> </span><span class="nf">staging_data</span><span class="p">():</span>
</span><span id="__span-4-9"><a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a> <span class="k">return</span> <span class="p">[</span><span class="n">Config</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">&quot;feature_x&quot;</span><span class="p">,</span> <span class="n">enabled</span><span class="o">=</span><span class="kc">True</span><span class="p">)]</span>
</span><span id="__span-4-10"><a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a>
</span><span id="__span-4-11"><a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="c1"># loads staging_data plus any Context.BASE fixtures</span>
</span><span id="__span-4-12"><a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a><span class="k">await</span> <span class="n">load_fixtures_by_context</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">fixtures</span><span class="p">,</span> <span class="n">AppContext</span><span class="o">.</span><span class="n">STAGING</span><span class="p">)</span>
</span></code></pre></div>
<h3 id="default-context-for-a-registry">Default context for a registry<a class="headerlink" href="#default-context-for-a-registry" title="Permanent link">&para;</a></h3>
<p>Pass <code>contexts</code> to <code>FixtureRegistry</code> to set a default for all fixtures registered in it:</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="n">testing_registry</span> <span class="o">=</span> <span class="n">FixtureRegistry</span><span class="p">(</span><span class="n">contexts</span><span class="o">=</span><span class="p">[</span><span class="n">Context</span><span class="o">.</span><span class="n">TESTING</span><span class="p">])</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="nd">@testing_registry</span><span class="o">.</span><span class="n">register</span> <span class="c1"># implicitly contexts=[Context.TESTING]</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="k">def</span><span class="w"> </span><span class="nf">test_orders</span><span class="p">():</span>
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a> <span class="k">return</span> <span class="p">[</span><span class="n">Order</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">total</span><span class="o">=</span><span class="mi">99</span><span class="p">)]</span>
<div class="language-python highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="n">testing_registry</span> <span class="o">=</span> <span class="n">FixtureRegistry</span><span class="p">(</span><span class="n">contexts</span><span class="o">=</span><span class="p">[</span><span class="n">Context</span><span class="o">.</span><span class="n">TESTING</span><span class="p">])</span>
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a>
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="nd">@testing_registry</span><span class="o">.</span><span class="n">register</span> <span class="c1"># implicitly contexts=[Context.TESTING]</span>
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="k">def</span><span class="w"> </span><span class="nf">test_orders</span><span class="p">():</span>
</span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a> <span class="k">return</span> <span class="p">[</span><span class="n">Order</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">total</span><span class="o">=</span><span class="mi">99</span><span class="p">)]</span>
</span></code></pre></div>
<h3 id="same-fixture-name-multiple-context-variants">Same fixture name, multiple context variants<a class="headerlink" href="#same-fixture-name-multiple-context-variants" title="Permanent link">&para;</a></h3>
<p>The same fixture name may be registered under different (non-overlapping) context sets. When multiple contexts are loaded together, all matching variants are merged:</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">contexts</span><span class="o">=</span><span class="p">[</span><span class="n">Context</span><span class="o">.</span><span class="n">BASE</span><span class="p">])</span>
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="k">def</span><span class="w"> </span><span class="nf">users</span><span class="p">():</span>
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a> <span class="k">return</span> <span class="p">[</span><span class="n">User</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">&quot;admin&quot;</span><span class="p">)]</span>
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a>
</span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">contexts</span><span class="o">=</span><span class="p">[</span><span class="n">Context</span><span class="o">.</span><span class="n">TESTING</span><span class="p">])</span>
</span><span id="__span-5-6"><a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a><span class="k">def</span><span class="w"> </span><span class="nf">users</span><span class="p">():</span>
</span><span id="__span-5-7"><a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a> <span class="k">return</span> <span class="p">[</span><span class="n">User</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">&quot;tester&quot;</span><span class="p">)]</span>
</span><span id="__span-5-8"><a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a>
</span><span id="__span-5-9"><a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a><span class="c1"># loads both admin and tester</span>
</span><span id="__span-5-10"><a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a><span class="k">await</span> <span class="n">load_fixtures_by_context</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">fixtures</span><span class="p">,</span> <span class="n">Context</span><span class="o">.</span><span class="n">BASE</span><span class="p">,</span> <span class="n">Context</span><span class="o">.</span><span class="n">TESTING</span><span class="p">)</span>
<div class="language-python highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">contexts</span><span class="o">=</span><span class="p">[</span><span class="n">Context</span><span class="o">.</span><span class="n">BASE</span><span class="p">])</span>
</span><span id="__span-6-2"><a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="k">def</span><span class="w"> </span><span class="nf">users</span><span class="p">():</span>
</span><span id="__span-6-3"><a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a> <span class="k">return</span> <span class="p">[</span><span class="n">User</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">&quot;admin&quot;</span><span class="p">)]</span>
</span><span id="__span-6-4"><a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a>
</span><span id="__span-6-5"><a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">contexts</span><span class="o">=</span><span class="p">[</span><span class="n">Context</span><span class="o">.</span><span class="n">TESTING</span><span class="p">])</span>
</span><span id="__span-6-6"><a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a><span class="k">def</span><span class="w"> </span><span class="nf">users</span><span class="p">():</span>
</span><span id="__span-6-7"><a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a> <span class="k">return</span> <span class="p">[</span><span class="n">User</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">&quot;tester&quot;</span><span class="p">)]</span>
</span><span id="__span-6-8"><a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a>
</span><span id="__span-6-9"><a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a><span class="c1"># loads both admin and tester (Context.BASE is included automatically)</span>
</span><span id="__span-6-10"><a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a><span class="k">await</span> <span class="n">load_fixtures_by_context</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">fixtures</span><span class="p">,</span> <span class="n">Context</span><span class="o">.</span><span class="n">TESTING</span><span class="p">)</span>
</span></code></pre></div>
<p>Registering two variants with overlapping context sets raises <code>ValueError</code>.</p>
<h2 id="load-strategies">Load strategies<a class="headerlink" href="#load-strategies" title="Permanent link">&para;</a></h2>
@@ -2138,50 +2143,54 @@
</tr>
</tbody>
</table>
<div class="language-python highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="k">await</span> <span class="n">load_fixtures_by_context</span><span class="p">(</span>
</span><span id="__span-6-2"><a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a> <span class="n">session</span><span class="p">,</span> <span class="n">fixtures</span><span class="p">,</span> <span class="n">Context</span><span class="o">.</span><span class="n">BASE</span><span class="p">,</span> <span class="n">strategy</span><span class="o">=</span><span class="n">LoadStrategy</span><span class="o">.</span><span class="n">SKIP_EXISTING</span>
</span><span id="__span-6-3"><a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="p">)</span>
<div class="language-python highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="k">await</span> <span class="n">load_fixtures_by_context</span><span class="p">(</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a> <span class="n">session</span><span class="p">,</span> <span class="n">fixtures</span><span class="p">,</span> <span class="n">Context</span><span class="o">.</span><span class="n">BASE</span><span class="p">,</span> <span class="n">strategy</span><span class="o">=</span><span class="n">LoadStrategy</span><span class="o">.</span><span class="n">SKIP_EXISTING</span>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="p">)</span>
</span></code></pre></div>
<h2 id="merging-registries">Merging registries<a class="headerlink" href="#merging-registries" title="Permanent link">&para;</a></h2>
<p>Split fixture definitions across modules and merge them:</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">myapp.fixtures.dev</span><span class="w"> </span><span class="kn">import</span> <span class="n">dev_fixtures</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">myapp.fixtures.prod</span><span class="w"> </span><span class="kn">import</span> <span class="n">prod_fixtures</span>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a>
</span><span id="__span-7-4"><a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="n">fixtures</span> <span class="o">=</span> <span class="n">FixtureRegistry</span><span class="p">()</span>
</span><span id="__span-7-5"><a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="n">fixtures</span><span class="o">.</span><span class="n">include_registry</span><span class="p">(</span><span class="n">registry</span><span class="o">=</span><span class="n">dev_fixtures</span><span class="p">)</span>
</span><span id="__span-7-6"><a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a><span class="n">fixtures</span><span class="o">.</span><span class="n">include_registry</span><span class="p">(</span><span class="n">registry</span><span class="o">=</span><span class="n">prod_fixtures</span><span class="p">)</span>
<div class="language-python highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">myapp.fixtures.dev</span><span class="w"> </span><span class="kn">import</span> <span class="n">dev_fixtures</span>
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">myapp.fixtures.prod</span><span class="w"> </span><span class="kn">import</span> <span class="n">prod_fixtures</span>
</span><span id="__span-8-3"><a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a>
</span><span id="__span-8-4"><a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="n">fixtures</span> <span class="o">=</span> <span class="n">FixtureRegistry</span><span class="p">()</span>
</span><span id="__span-8-5"><a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a><span class="n">fixtures</span><span class="o">.</span><span class="n">include_registry</span><span class="p">(</span><span class="n">registry</span><span class="o">=</span><span class="n">dev_fixtures</span><span class="p">)</span>
</span><span id="__span-8-6"><a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a><span class="n">fixtures</span><span class="o">.</span><span class="n">include_registry</span><span class="p">(</span><span class="n">registry</span><span class="o">=</span><span class="n">prod_fixtures</span><span class="p">)</span>
</span></code></pre></div>
<p>Fixtures with the same name are allowed as long as their context sets do not overlap. Conflicting contexts raise <code>ValueError</code>.</p>
<h2 id="looking-up-fixture-instances">Looking up fixture instances<a class="headerlink" href="#looking-up-fixture-instances" title="Permanent link">&para;</a></h2>
<p><a href="../../reference/fixtures/#fastapi_toolsets.fixtures.utils.get_obj_by_attr"><code>get_obj_by_attr</code></a> retrieves a specific instance from a fixture function by attribute value — useful when building cross-fixture <code>depends_on</code> relationships:</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.fixtures</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_obj_by_attr</span>
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a>
</span><span id="__span-8-3"><a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">depends_on</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;roles&quot;</span><span class="p">])</span>
</span><span id="__span-8-4"><a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="k">def</span><span class="w"> </span><span class="nf">users</span><span class="p">():</span>
</span><span id="__span-8-5"><a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a> <span class="n">admin_role</span> <span class="o">=</span> <span class="n">get_obj_by_attr</span><span class="p">(</span><span class="n">roles</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;admin&quot;</span><span class="p">)</span>
</span><span id="__span-8-6"><a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a> <span class="k">return</span> <span class="p">[</span><span class="n">User</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">&quot;alice&quot;</span><span class="p">,</span> <span class="n">role_id</span><span class="o">=</span><span class="n">admin_role</span><span class="o">.</span><span class="n">id</span><span class="p">)]</span>
<p><a href="../../reference/fixtures/#fastapi_toolsets.fixtures.registry.FixtureRegistry.obj"><code>FixtureRegistry.obj</code></a> retrieves a specific instance from a registered fixture by attribute value, looked up by name on the registry — useful when building cross-fixture <code>depends_on</code> relationships:</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">depends_on</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;roles&quot;</span><span class="p">])</span>
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="k">def</span><span class="w"> </span><span class="nf">users</span><span class="p">():</span>
</span><span id="__span-9-3"><a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a> <span class="n">admin_role</span> <span class="o">=</span> <span class="n">fixtures</span><span class="o">.</span><span class="n">obj</span><span class="p">(</span><span class="s2">&quot;roles&quot;</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;admin&quot;</span><span class="p">)</span>
</span><span id="__span-9-4"><a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a> <span class="k">return</span> <span class="p">[</span><span class="n">User</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">&quot;alice&quot;</span><span class="p">,</span> <span class="n">role_id</span><span class="o">=</span><span class="n">admin_role</span><span class="o">.</span><span class="n">id</span><span class="p">)]</span>
</span></code></pre></div>
<p>Raises <code>StopIteration</code> if no matching instance is found.</p>
<p>Looking the fixture up by name (instead of importing the <code>roles</code> function directly) means fixture modules never need to import each other, which avoids circular imports in larger projects split across multiple files — the same reason <code>depends_on</code> takes fixture names rather than the functions themselves. The registry passed in must be the one that actually contains the fixture by load time; with a single shared registry this is automatic, but if you merge registries with <code>include_registry</code>, call <code>obj</code>/<code>field</code> on the merged registry.</p>
<p><a href="../../reference/fixtures/#fastapi_toolsets.fixtures.registry.FixtureRegistry.field"><code>FixtureRegistry.field</code></a> is shorthand for pulling a single attribute (<code>id</code> by default):</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="nd">@fixtures</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">depends_on</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;roles&quot;</span><span class="p">])</span>
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="k">def</span><span class="w"> </span><span class="nf">users</span><span class="p">():</span>
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a> <span class="k">return</span> <span class="p">[</span><span class="n">User</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">&quot;alice&quot;</span><span class="p">,</span> <span class="n">role_id</span><span class="o">=</span><span class="n">fixtures</span><span class="o">.</span><span class="n">field</span><span class="p">(</span><span class="s2">&quot;roles&quot;</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;admin&quot;</span><span class="p">))]</span>
</span></code></pre></div>
<p>Both raise <code>StopIteration</code> if no matching instance is found, and <code>KeyError</code> if the fixture name isn't registered.</p>
<h2 id="pytest-integration">Pytest integration<a class="headerlink" href="#pytest-integration" title="Permanent link">&para;</a></h2>
<p>Use <a href="../../reference/pytest/#fastapi_toolsets.pytest.plugin.register_fixtures"><code>register_fixtures</code></a> to expose each fixture in your registry as an injectable pytest fixture named <code>fixture_{name}</code> by default:</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="c1"># conftest.py</span>
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">pytest</span>
</span><span id="__span-9-3"><a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.pytest</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_db_session</span><span class="p">,</span> <span class="n">register_fixtures</span>
</span><span id="__span-9-4"><a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">app.fixtures</span><span class="w"> </span><span class="kn">import</span> <span class="n">registry</span>
</span><span id="__span-9-5"><a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">app.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">Base</span>
</span><span id="__span-9-6"><a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a>
</span><span id="__span-9-7"><a id="__codelineno-9-7" name="__codelineno-9-7" href="#__codelineno-9-7"></a><span class="n">DATABASE_URL</span> <span class="o">=</span> <span class="s2">&quot;postgresql+asyncpg://user:pass@localhost/test_db&quot;</span>
</span><span id="__span-9-8"><a id="__codelineno-9-8" name="__codelineno-9-8" href="#__codelineno-9-8"></a>
</span><span id="__span-9-9"><a id="__codelineno-9-9" name="__codelineno-9-9" href="#__codelineno-9-9"></a><span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span>
</span><span id="__span-9-10"><a id="__codelineno-9-10" name="__codelineno-9-10" href="#__codelineno-9-10"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">db_session</span><span class="p">():</span>
</span><span id="__span-9-11"><a id="__codelineno-9-11" name="__codelineno-9-11" href="#__codelineno-9-11"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">create_db_session</span><span class="p">(</span><span class="n">database_url</span><span class="o">=</span><span class="n">DATABASE_URL</span><span class="p">,</span> <span class="n">base</span><span class="o">=</span><span class="n">Base</span><span class="p">,</span> <span class="n">cleanup</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="k">as</span> <span class="n">session</span><span class="p">:</span>
</span><span id="__span-9-12"><a id="__codelineno-9-12" name="__codelineno-9-12" href="#__codelineno-9-12"></a> <span class="k">yield</span> <span class="n">session</span>
</span><span id="__span-9-13"><a id="__codelineno-9-13" name="__codelineno-9-13" href="#__codelineno-9-13"></a>
</span><span id="__span-9-14"><a id="__codelineno-9-14" name="__codelineno-9-14" href="#__codelineno-9-14"></a><span class="n">register_fixtures</span><span class="p">(</span><span class="n">registry</span><span class="o">=</span><span class="n">registry</span><span class="p">,</span> <span class="n">namespace</span><span class="o">=</span><span class="nb">globals</span><span class="p">())</span>
<div class="language-python highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="c1"># conftest.py</span>
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">pytest</span>
</span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi_toolsets.pytest</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_db_session</span><span class="p">,</span> <span class="n">register_fixtures</span>
</span><span id="__span-11-4"><a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">app.fixtures</span><span class="w"> </span><span class="kn">import</span> <span class="n">registry</span>
</span><span id="__span-11-5"><a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">app.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">Base</span>
</span><span id="__span-11-6"><a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a>
</span><span id="__span-11-7"><a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a><span class="n">DATABASE_URL</span> <span class="o">=</span> <span class="s2">&quot;postgresql+asyncpg://user:pass@localhost/test_db&quot;</span>
</span><span id="__span-11-8"><a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a>
</span><span id="__span-11-9"><a id="__codelineno-11-9" name="__codelineno-11-9" href="#__codelineno-11-9"></a><span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span>
</span><span id="__span-11-10"><a id="__codelineno-11-10" name="__codelineno-11-10" href="#__codelineno-11-10"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">db_session</span><span class="p">():</span>
</span><span id="__span-11-11"><a id="__codelineno-11-11" name="__codelineno-11-11" href="#__codelineno-11-11"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">create_db_session</span><span class="p">(</span><span class="n">database_url</span><span class="o">=</span><span class="n">DATABASE_URL</span><span class="p">,</span> <span class="n">base</span><span class="o">=</span><span class="n">Base</span><span class="p">,</span> <span class="n">cleanup</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="k">as</span> <span class="n">session</span><span class="p">:</span>
</span><span id="__span-11-12"><a id="__codelineno-11-12" name="__codelineno-11-12" href="#__codelineno-11-12"></a> <span class="k">yield</span> <span class="n">session</span>
</span><span id="__span-11-13"><a id="__codelineno-11-13" name="__codelineno-11-13" href="#__codelineno-11-13"></a>
</span><span id="__span-11-14"><a id="__codelineno-11-14" name="__codelineno-11-14" href="#__codelineno-11-14"></a><span class="n">register_fixtures</span><span class="p">(</span><span class="n">registry</span><span class="o">=</span><span class="n">registry</span><span class="p">,</span> <span class="n">namespace</span><span class="o">=</span><span class="nb">globals</span><span class="p">())</span>
</span></code></pre></div>
<div class="language-python highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="c1"># test_users.py</span>
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test_user_can_login</span><span class="p">(</span><span class="n">fixture_users</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">User</span><span class="p">],</span> <span class="n">fixture_roles</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">Role</span><span class="p">]):</span>
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a> <span class="o">...</span>
<div class="language-python highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="c1"># test_users.py</span>
</span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test_user_can_login</span><span class="p">(</span><span class="n">fixture_users</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">User</span><span class="p">],</span> <span class="n">fixture_roles</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">Role</span><span class="p">]):</span>
</span><span id="__span-12-3"><a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a> <span class="o">...</span>
</span></code></pre></div>
<p>The load order is resolved automatically from the <code>depends_on</code> declarations in your registry. Each generated fixture receives <code>db_session</code> as a dependency and returns the list of loaded model instances.</p>
<h2 id="cli-integration">CLI integration<a class="headerlink" href="#cli-integration" title="Permanent link">&para;</a></h2>