OiO.lk Blog python Singleton by arguments in dependency_injector python
python

Singleton by arguments in dependency_injector python


Im using dependency_injector in python with fastapi, and I’d like to cache instances of classes by the parameters passed to them. Here’s my current code:

from fastapi import FastAPI, Depends
from dependency_injector import containers, providers
from dependency_injector.providers import Factory
from dependency_injector.wiring import inject, Provide, Provider

class Service:
    def __init__(self, name: str):
        print(f"Called constructor for {name}")
        self.name = name

    def send_message(self) -> dict[str, str]:
        return {"message": f"Hello, {self.name}"}


class Container(containers.DeclarativeContainer):
    wiring_config = containers.WiringConfiguration(modules=[__name__])
    service_factory = providers.Factory(Service)


def create_app() -> FastAPI:
    app = FastAPI()
    app.container = Container()

    service_factory = app.container.service_factory

    print(service_factory(name="World").send_message())
    print(service_factory(name="Wirld").send_message())
    print(service_factory(name="World").send_message())

    return app


app = create_app()


# Define a simple route
@app.get("/hello/{name}")
@inject
async def hello(
    name: str,
    service_factory: Factory[Service] = Depends(Provide[Container.service_factory]),
):
    print(type(service_factory))
    service = service_factory(name=name)
    return service.send_message()

In the following example, I have two problems:

  1. In the create_app function, the container factory gets called twice for "World". (Using a providers.Singleton doesn’t work, the saved instance will be the first instance)

  2. For some reason, in the /hello/{name} route, if I try to GET it service_factory is of type "Provide", and calling the service_factory(name=name) just throws an error saying that _Marker doesn’t expect arguments. I tried changing the WiringConfig to ".app" (current file name) but it still doesn’t work)

So I’d love this example to work without calling a constructor with the same arguments twice, and while still having type hinting



You need to sign in to view this answers

Exit mobile version