Skip to content

Is That-Depends could be used in a Library? #50

@rustam-ashurov-mcx

Description

@rustam-ashurov-mcx

Hey mates,
On the main page it's said that this lib is good to switch from dependency-injector so I'm hyped already.
But can this library help with wiring FastAPI routers which are defined in a library and should be used eventually in a customer application code?

To elaborate a bit more about my particular example (which fails with other DI libraries):

I want to make a library with some REST API routers for FastAPI application and with some DI bindings to pre-configured so my routers will receive my services:

Here is the LoggignContainer where I have logging-related dependencies:

class LoggingContainer(containers.DeclarativeContainer):

    logger = providers.Singleton(MyLogger)

And here is a main BaseContainer where I aggregated all smaller containers from my library, it then can be used in the client code to register (for me) and access (for client) my services if needed:

class BaseContainer(containers.DeclarativeContainer):

    app = providers.Container(AppContainer)

    logging = providers.Container(LoggingContainer)

    web_api = providers.Container(WebApiContainer, app=app, logging=logging)

Here is my library router which should automate some work, very simple one and which uses services registred in IoC Contaier from my lib, specifically my logger:

router = APIRouter()

tag = "Ping"

@router.get("/ping", tags=[tag], status_code=status.HTTP_200_OK)

@inject

async def ping_async(logger: Logger = Depends(Provide[LoggingContainer.logger])):

    logger.trace("Ping")

    return

In a client code some steps should be done, firstly a client Container to be defined, it has it's own application-related dependencies + inherits from my BaseContainer:

class AppContainer(BaseContainer):

    hello_world_service = providers.Factory(HelloWorldService) <- some application related registration

Now client code need to register the library router (typical registration via FastAPI methods) + wire the router :

if __name__ == "__main__":

    container = Container()

    ... here happens FastAPI code and registration of router there ....

    container.wire(modules=[ping_router])

    container.wire(modules=[__name__])

    configure_services()

    run_app()

My expectations are Logger from my library will be injected in my router but the results is:
"AttributeError: 'Provide' object has no attribute logger"

I tried many combinations and changed code many ways but unless I directly use AppContainer in my library code (what is impossible to expect beyond local examples and testing since I can not know what is App level container in advance) wiring doesn't work

So now I started to check you examples and in the FastAPI example I see such lines of code:

@ROUTER.get("/decks/")
async def list_decks(
    decks_repo: DecksRepository = fastapi.Depends(ioc.IOCContainer.decks_repo),
) -> schemas.Decks:
    objects = await decks_repo.all()
    return typing.cast(schemas.Decks, {"items": objects})

Where ioc.IOCContainer.decks_repo is a reference to the container in the application code and I decided to ask in advance.

Is it possible in your lib to:

  • Define a library Container that will be used or inherited by the Client specific container
  • Wire client and library modules with Client Container
  • And happily use dependencies from library container in library code not knowing about client-level Container in advance?

Thank you 🙂

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions