reagento / dishka

Cute DI framework with agreeable API and everything you need
https://dishka.readthedocs.io
Apache License 2.0
428 stars 48 forks source link

[Feature request] Provider overriding in container #275

Open jakub-borusewicz opened 1 month ago

jakub-borusewicz commented 1 month ago

Hello! I started playing around with dishka, looking for some alternative to dependency-injector, and I really liked it conteptually, especially scopes and type-based injections.

Unfortunetly, when trying to introduce it to django project, I found out one missing feature from dependency-injector, i.e. in place providers overriding. I managed to succesfully integrate container to inject dependencies into django views, but things get tricky when it comes to tests. It's very hard, if not impossible, to setup django tests with pytest in simillar manner as with more modern frameworks, i.e. by creating whole new application object that could be passed around in pytest fixtures, with it's own tests container attached.

I found other issue about container overriding: https://github.com/reagento/dishka/issues/151 , but it mentions cloning container with different providers, which would not help in my case. I guess only overriding in context manager (independent of scopes), or with teardown method (I mean, overriding in place, not cloning) would help in my case. Like in dependency-injector https://python-dependency-injector.ets-labs.org/providers/overriding.html

Apart of solving problems with Django specifically, it would also make possible to use pattern in pytest that I find very helpful, i.e. incrementally overriding providers in different tests scopes, taking adventage of how pytest look for fixtures: https://docs.pytest.org/en/6.2.x/fixture.html#fixture-availability

So for example, I would define most general overrides on container fixture in root conftest.py, and then add more specific overrides in more narrow scopes, using pattern:

@pytest.fixture
def container(container):
      container.override(<some_specific_provider>)
      return container

Is it possible/feasible to implement that with your design?

Tishka17 commented 1 month ago

We have plans for this in one of future releases (#231), but it is not actually required for you.

The container is rebuilt from a list of providers. To build another container you can take the same list.. and add more providers to it. The latest factories override previous ones.


providers = [Provider1(), Provider2()]

prod_container = make_container(*providers)

test_container = make_container(*providers, TestProvider())