<p dir="auto"><strong>Don't you think the dependency injection framework needs a singleton type?</strong></p>
<p dir="auto">I checked the documentation and as I can see there is no option for creating a class as a singleton. If I want to pass in a class as a dependency it will be created every time. So a feature to create singleton and if that already exists just pass it in as a dependency would be great. Because if you create a huge dependency tree than you have to specify one-by-one to make singletons.</p>
<p dir="auto">Maybe I missed something how to do that but if not that could be a new feature.</p>
<h3 dir="auto">Example</h3>
<p dir="auto">Must install <code class="notranslate">qcelemental</code> first! Pardon that I'm not able to take the core issues and create a simpler example without this external package; however, this demonstrates the core problem well.</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="pip install qcelemental"><pre class="notranslate">pip install qcelemental</pre></div>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from pydantic import BaseModel
from fastapi.encoders import jsonable_encoder
from qcelemental.models import Molecule
from numpy import array, ndarray


molecule_data = {
    &quot;schema_name&quot;: &quot;qcschema_molecule&quot;,
    &quot;schema_version&quot;: 2,
    &quot;validated&quot;: True,
    &quot;symbols&quot;: array([&quot;O&quot;, &quot;H&quot;, &quot;H&quot;], dtype=&quot;&lt;U1&quot;),
    &quot;geometry&quot;: array(
        [
            [0.0, 0.0, 0.0],
            [0.52421003, 1.68733646, 0.48074633],
            [1.14668581, -0.45032174, -1.35474466],
        ]
    ),
    &quot;name&quot;: &quot;IUPAC oxidane&quot;,
    &quot;molecular_charge&quot;: 0.0,
    &quot;molecular_multiplicity&quot;: 1,
    &quot;fix_com&quot;: False,
    &quot;fix_orientation&quot;: False,
    &quot;provenance&quot;: {
        &quot;creator&quot;: &quot;QCElemental&quot;,
        &quot;version&quot;: &quot;v0.17.0&quot;,
        &quot;routine&quot;: &quot;qcelemental.molparse.from_string&quot;,
    },
}


class NestedMolecule(BaseModel):
    molecule: Molecule


class NestedMoleculeRepeatedEncoders(NestedMolecule):
    class Config:
        json_encoders = {ndarray: lambda x: x.tolist()}


molecule = Molecule.parse_obj(molecule_data)
nested_molecule_repeat_encoders = NestedMoleculeRepeatedEncoders(molecule=molecule)
nested_molecule = NestedMolecule(molecule=molecule)

# Works great! Fastapi picks up the custom encoders/serialization methods on Molecule and can encode the object and ultimately return a JSONResponse (if this were the response_model on a path)
jsonable_encoder(molecule)

# Works! But why do I have to duplicate these encoders that already exist on the Molecule object??
jsonable_encoder(nested_molecule_repeat_encoders)

# Fails to properly encode numpy.ndarray field at nested_molecule.molecule.geometry. A JSONResponse with response_model=NestedMolecule would fail.
jsonable_encoder(nested_molecule)"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">pydantic</span> <span class="pl-k">import</span> <span class="pl-v">BaseModel</span>
<span class="pl-k">from</span> <span class="pl-s1">fastapi</span>.<span class="pl-s1">encoders</span> <span class="pl-k">import</span> <span class="pl-s1">jsonable_encoder</span>
<span class="pl-k">from</span> <span class="pl-s1">qcelemental</span>.<span class="pl-s1">models</span> <span class="pl-k">import</span> <span class="pl-v">Molecule</span>
<span class="pl-k">from</span> <span class="pl-s1">numpy</span> <span class="pl-k">import</span> <span class="pl-s1">array</span>, <span class="pl-s1">ndarray</span>


<span class="pl-s1">molecule_data</span> <span class="pl-c1">=</span> {
    <span class="pl-s">"schema_name"</span>: <span class="pl-s">"qcschema_molecule"</span>,
    <span class="pl-s">"schema_version"</span>: <span class="pl-c1">2</span>,
    <span class="pl-s">"validated"</span>: <span class="pl-c1">True</span>,
    <span class="pl-s">"symbols"</span>: <span class="pl-en">array</span>([<span class="pl-s">"O"</span>, <span class="pl-s">"H"</span>, <span class="pl-s">"H"</span>], <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">"&lt;U1"</span>),
    <span class="pl-s">"geometry"</span>: <span class="pl-en">array</span>(
        [
            [<span class="pl-c1">0.0</span>, <span class="pl-c1">0.0</span>, <span class="pl-c1">0.0</span>],
            [<span class="pl-c1">0.52421003</span>, <span class="pl-c1">1.68733646</span>, <span class="pl-c1">0.48074633</span>],
            [<span class="pl-c1">1.14668581</span>, <span class="pl-c1">-</span><span class="pl-c1">0.45032174</span>, <span class="pl-c1">-</span><span class="pl-c1">1.35474466</span>],
        ]
    ),
    <span class="pl-s">"name"</span>: <span class="pl-s">"IUPAC oxidane"</span>,
    <span class="pl-s">"molecular_charge"</span>: <span class="pl-c1">0.0</span>,
    <span class="pl-s">"molecular_multiplicity"</span>: <span class="pl-c1">1</span>,
    <span class="pl-s">"fix_com"</span>: <span class="pl-c1">False</span>,
    <span class="pl-s">"fix_orientation"</span>: <span class="pl-c1">False</span>,
    <span class="pl-s">"provenance"</span>: {
        <span class="pl-s">"creator"</span>: <span class="pl-s">"QCElemental"</span>,
        <span class="pl-s">"version"</span>: <span class="pl-s">"v0.17.0"</span>,
        <span class="pl-s">"routine"</span>: <span class="pl-s">"qcelemental.molparse.from_string"</span>,
    },
}


<span class="pl-k">class</span> <span class="pl-v">NestedMolecule</span>(<span class="pl-v">BaseModel</span>):
    <span class="pl-s1">molecule</span>: <span class="pl-v">Molecule</span>


<span class="pl-k">class</span> <span class="pl-v">NestedMoleculeRepeatedEncoders</span>(<span class="pl-v">NestedMolecule</span>):
    <span class="pl-k">class</span> <span class="pl-v">Config</span>:
        <span class="pl-s1">json_encoders</span> <span class="pl-c1">=</span> {<span class="pl-s1">ndarray</span>: <span class="pl-k">lambda</span> <span class="pl-s1">x</span>: <span class="pl-s1">x</span>.<span class="pl-en">tolist</span>()}


<span class="pl-s1">molecule</span> <span class="pl-c1">=</span> <span class="pl-v">Molecule</span>.<span class="pl-en">parse_obj</span>(<span class="pl-s1">molecule_data</span>)
<span class="pl-s1">nested_molecule_repeat_encoders</span> <span class="pl-c1">=</span> <span class="pl-v">NestedMoleculeRepeatedEncoders</span>(<span class="pl-s1">molecule</span><span class="pl-c1">=</span><span class="pl-s1">molecule</span>)
<span class="pl-s1">nested_molecule</span> <span class="pl-c1">=</span> <span class="pl-v">NestedMolecule</span>(<span class="pl-s1">molecule</span><span class="pl-c1">=</span><span class="pl-s1">molecule</span>)

<span class="pl-c"># Works great! Fastapi picks up the custom encoders/serialization methods on Molecule and can encode the object and ultimately return a JSONResponse (if this were the response_model on a path)</span>
<span class="pl-en">jsonable_encoder</span>(<span class="pl-s1">molecule</span>)

<span class="pl-c"># Works! But why do I have to duplicate these encoders that already exist on the Molecule object??</span>
<span class="pl-en">jsonable_encoder</span>(<span class="pl-s1">nested_molecule_repeat_encoders</span>)

<span class="pl-c"># Fails to properly encode numpy.ndarray field at nested_molecule.molecule.geometry. A JSONResponse with response_model=NestedMolecule would fail.</span>
<span class="pl-en">jsonable_encoder</span>(<span class="pl-s1">nested_molecule</span>)</pre></div>
<h3 dir="auto">Description</h3>
<p dir="auto">Fastapi appears to correctly utilize the custom json encoding/serialization methods found on <code class="notranslate">Molecule</code>. Great! However, if I nest a <code class="notranslate">Molecule</code> inside another Pydantic model, fastapi does not correctly pick up these serialization customizations. In order to use a <code class="notranslate">NestedMolecule</code> I have to add custom <code class="notranslate">json_encoders</code> to the <code class="notranslate">Config</code> class, as seen on <code class="notranslate">NestedMoleculeRepeatedEncoders</code>. But why do I have to do this? Seems fastapi should pick up the custom encoders on nested Pydantic objects just like it does on the original <code class="notranslate">Molecule</code> object. I believe this is a bug.</p>
<p dir="auto">One way to help see what's going on here is to add <code class="notranslate">print(type(obj), obj)</code> on line 37 of <code class="notranslate">fastapi.encoders</code> to see how the <code class="notranslate">jsonable_encoder</code> function is correctly handing the first two cases and fails the third case.</p>
<h3 dir="auto">Environment</h3>
<ul dir="auto">
<li>OS: MacOS:</li>
<li>FastAPI Version 0.62.0:</li>
<li>Python version: 3.9.0</li>
</ul>