Dependency Injector is a dependency injection framework for Python.

Overview

Latest Version License Supported Python versions Supported Python implementations Downloads Downloads Downloads Wheel Build Status Coverage Status

What is Dependency Injector?

Dependency Injector is a dependency injection framework for Python.

It helps implementing the dependency injection principle.

Key features of the Dependency Injector:

  • Providers. Provides Factory, Singleton, Callable, Coroutine, Object, List, Dict, Configuration, Resource, Dependency and Selector providers that help assembling your objects. See Providers.
  • Overriding. Can override any provider by another provider on the fly. This helps in testing and configuring dev / stage environment to replace API clients with stubs etc. See Provider overriding.
  • Configuration. Reads configuration from yaml & ini files, pydantic settings, environment variables, and dictionaries. See Configuration provider.
  • Containers. Provides declarative and dynamic containers. See Containers.
  • Resources. Helps with initialization and configuring of logging, event loop, thread or process pool, etc. Can be used for per-function execution scope in tandem with wiring. See Resource provider.
  • Wiring. Injects dependencies into functions and methods. Helps integrating with other frameworks: Django, Flask, Aiohttp, Sanic, FastAPI, etc. See Wiring.
  • Asynchronous. Supports asynchronous injections. See Asynchronous injections.
  • Typing. Provides typing stubs, mypy-friendly. See Typing and mypy.
  • Performance. Fast. Written in Cython.
  • Maturity. Mature and production-ready. Well-tested, documented and supported.
from dependency_injector import containers, providers
from dependency_injector.wiring import inject, Provide


class Container(containers.DeclarativeContainer):

    config = providers.Configuration()

    api_client = providers.Singleton(
        ApiClient,
        api_key=config.api_key,
        timeout=config.timeout.as_int(),
    )

    service = providers.Factory(
        Service,
        api_client=api_client,
    )


@inject
def main(service: Service = Provide[Container.service]):
    ...


if __name__ == '__main__':
    container = Container()
    container.config.api_key.from_env('API_KEY')
    container.config.timeout.from_env('TIMEOUT')
    container.wire(modules=[sys.modules[__name__]])

    main()  # <-- dependency is injected automatically

    with container.api_client.override(mock.Mock()):
        main()  # <-- overridden dependency is injected automatically

When you call main() function the Service dependency is assembled and injected automatically.

When doing a testing you call the container.api_client.override() to replace the real API client with a mock. When you call main() the mock is injected.

You can override any provider with another provider.

It also helps you in configuring project for the different environments: replace an API client with a stub on the dev or stage.

With the Dependency Injector objects assembling is consolidated in the container. Dependency injections are defined explicitly. This makes easier to understand and change how application works.

Visit the docs to know more about the Dependency injection and inversion of control in Python.

Installation

The package is available on the PyPi:

pip install dependency-injector

Documentation

The documentation is available here.

Examples

Choose one of the following:

Tutorials

Choose one of the following:

Concept

The framework stands on the PEP20 (The Zen of Python) principle:

Explicit is better than implicit

You need to specify how to assemble and where to inject the dependencies explicitly.

The power of the framework is in a simplicity. Dependency Injector is a simple tool for the powerful concept.

Frequently asked questions

What is the dependency injection?
  • dependency injection is a principle that decreases coupling and increases cohesion
Why should I do the dependency injection?
  • your code becomes more flexible, testable and clear 😎
How do I start doing the dependency injection?
  • you start writing the code following the dependency injection principle
  • you register all of your application components and their dependencies in the container
  • when you need a component, you specify where to inject it or get it from the container
What price do I pay and what do I get?
  • you need to explicitly specify the dependencies
  • it will be extra work in the beginning
  • it will payoff as the project grows
Have a question?
Found a bug?
Want to help?
  • ⭐️ Star the Dependency Injector on the Github
  • 🆕 Start a new project with the Dependency Injector
  • 💬 Tell your friend about the Dependency Injector
Want to contribute?
  • 🔀 Fork the project
  • ⬅️ Open a pull request to the develop branch
Comments
  • server is http

    server is http

    Hello,

    all your docs are stored in a HTTP server, however, many company proxies/AntiVir block any HTTP site.

    Just mentioning that moving to a https will make your docs available to a bigger audience (including myself :)).

    Regards, A.

    enhancement docs 
    opened by alnavv 48
  • Adding type hints to dependency-injector

    Adding type hints to dependency-injector

    Hi,

    Now that python typing (type hints) is very common, it would be great that dependency-injector will have type hints / annotations. Currently when using Container / Provider classes mypy complains since it doesn't have information about a provider returned type, etc.

    For example:

    provider: Provider[Animal] = providers.Factory(Cat)
    
    animal = provider()  # mypy can know that animal is of type Animal
    

    My current workaround is to put type: ignore in many places but it is less desired since I won't get errors at type checking time.

    Thanks

    feature docs 
    opened by awaizman1 24
  • Configuration raises AttributeError when provider is called

    Configuration raises AttributeError when provider is called

    Hi, I just run into this issue with the Configuration provider. After scratching my head for a bit, I managed to find a workaround, but I was wondering if this is actually a bug or just something wrong I am doing. Any help would be appreciated!

    Steps to reproduce

    containers.py

    from dependency_injector import providers, containers
    
    class MyService(object):
        def __init__(self, **kwargs):
            self.key = kwargs.pop('key')
    
        def trigger(self):
            pass
    
    class MyDevice(object):
        def __init__(self, **kwargs):
            # doesn't raise an error because it's an instance of
            # dependency_injector.providers.Singleton
            self.service = kwargs.pop('service')
    
        def do_something(self):
            # raises "AttributeError: 'NoneType' object has no attribute 'get'"
            self.service().trigger()
    
    class ServiceContainer(containers.DeclarativeContainer):
        config = providers.Configuration()
    
        myservice = providers.Singleton(MyService, config=config.myservice)
    
    
    class Container(containers.DeclarativeContainer):
        config = providers.Configuration()
    
        services = providers.Container(ServiceContainer, config=config.services)
    
        mydevice = providers.Factory(MyDevice)
    

    If I run app.py

    import sys
    
    from containers import Container
    
    container = Container()
    container.config.from_yaml('config.yaml')
    container.init_resources()
    container.wire(modules=[sys.modules[__name__]])
    
    mydevice = container.mydevice(service=container.services.myservice)
    mydevice.do_something()
    

    with config.yaml

    foo:
      bar: 42
    

    it raises the following error

    File "/home/stefano/personal/test-error/containers.py", line 15, in do_something self.service().trigger() File "src/dependency_injector/providers.pyx", line 168, in dependency_injector.providers.Provider.call File "src/dependency_injector/providers.pyx", line 2245, in dependency_injector.providers.Singleton._provide File "src/dependency_injector/providers.pxd", line 550, in dependency_injector.providers.__factory_call File "src/dependency_injector/providers.pxd", line 536, in dependency_injector.providers.__callable_call File "src/dependency_injector/providers.pxd", line 495, in dependency_injector.providers.__call File "src/dependency_injector/providers.pxd", line 387, in dependency_injector.providers.__provide_keyword_args File "src/dependency_injector/providers.pxd", line 310, in dependency_injector.providers.__get_value File "src/dependency_injector/providers.pyx", line 168, in dependency_injector.providers.Provider.call File "src/dependency_injector/providers.pyx", line 1232, in dependency_injector.providers.ConfigurationOption._provide File "src/dependency_injector/providers.pyx", line 1467, in dependency_injector.providers.Configuration.get AttributeError: 'NoneType' object has no attribute 'get'

    Workaround To avoid the issue, I have to pass the whole config to ServiceContainer

    class ServiceContainer(containers.DeclarativeContainer):
        config = providers.Configuration()
    
        myservice = providers.Singleton(MyService, config=config.services.myservice)
    
    
    class Container(containers.DeclarativeContainer):
        config = providers.Configuration()
    
        services = providers.Container(ServiceContainer, config=config)
    
        mydevice = providers.Factory(MyDevice)
    

    Running the application now, raises the following (as expected)

    File "/home/stefano/personal/test-error/containers.py", line 18, in do_something self.service().trigger() File "src/dependency_injector/providers.pyx", line 168, in dependency_injector.providers.Provider.call File "src/dependency_injector/providers.pyx", line 2245, in dependency_injector.providers.Singleton._provide File "src/dependency_injector/providers.pxd", line 550, in dependency_injector.providers.__factory_call File "src/dependency_injector/providers.pxd", line 536, in dependency_injector.providers.__callable_call File "src/dependency_injector/providers.pxd", line 526, in dependency_injector.providers.__call File "/home/stefano/personal/test-error/containers.py", line 5, in init self.key = kwargs.pop('key') KeyError: 'key'

    bug 
    opened by StefanoFrazzetto 21
  • Injection not working for class methods

    Injection not working for class methods

    I am not quite sure if this is expected behavior or not. Methods annotated as @classmethod end up getting extra parameters injected. The following code demonstrates. I discovered this while using Closing, but filled out the example a bit as I discovered that it is a general issue for Provide.

    import sys
    from dependency_injector import containers, providers
    from dependency_injector.wiring import Provide, Closing
    
    
    def my_factory():
        return 'test-factory'
    
    
    def my_resource():
        yield 'test-resource'
        print('Closing')
    
    
    class Container(containers.DeclarativeContainer):
    
        factory = providers.Factory(my_factory)
        resource = providers.Resource(my_resource)
    
    
    def do_function_thing(r:str=Closing[Provide[Container.resource]]) -> None:
        print('from function', r)
    
    
    class MyClass():
    
        def do_instance_thing(self, r:str=Closing[Provide[Container.resource]]) -> None:
            print('from instance', r)
    
        @classmethod
        def do_class_thing(cls, r:str=Closing[Provide[Container.resource]]) -> None:
            print('from class', r)
    
        @classmethod
        def non_closing_class_thing(cls, r:str=Provide[Container.factory]) -> None:
            print('non-closing from class', r)
    
    
    container = Container()
    container.init_resources()
    container.wire(modules=[sys.modules[__name__]])
    
    
    do_function_thing()
    c = MyClass()
    c.do_instance_thing()
    
    # both of these end up getting multiple values for r:
    c.non_closing_class_thing()
    c.do_class_thing()
    

    The resulting output is:

    from function test-resource
    Closing
    from instance test-resource
    Closing
    Traceback (most recent call last):
      File "clstest.py", line 49, in <module>
        c.non_closing_class_thing()
      File "/Users/scott/repos/github.com/scott2b/Starlight/.venv/lib/python3.8/site-packages/dependency_injector/wiring.py", line 296, in _patched
        result = fn(*args, **to_inject)
    TypeError: non_closing_class_thing() got multiple values for argument 'r'
    
    bug 
    opened by scott2b 19
  • Using dynamic containers with Fastapi endpoint.

    Using dynamic containers with Fastapi endpoint.

    I have not been able to find any documentation/examples on how to setup an endpoint using dynamic containers. All i've seen is: def create_transaction( dbengine: MyDbEngine = Depends(Provide[DiContainer.dbengine_provider]) )

    Of course this doesn't work for dynamic containers since i have no declarative container called DiContainer. Am i correct here? I'm sure i'm missing something here being new to python etc...

    thx ~MarvinB

    feature 
    opened by marvfinsy 17
  • Unable to wire injections, Flask out of context error

    Unable to wire injections, Flask out of context error

    I'm hoping this is just because I'm new at this.

    I'm developing an application, and currently working on converting to use dependency-injector. I've written a container and have been able to get configuration and a data store factory working. However, I'm running into an issue when wiring up injections with a Flask blueprint.

    When I follow the documentation and call the function to wire the container, I get a RuntimeError (actually from Flask):

    Traceback (most recent call last):
      File "c:\source\personal\pydas\src\pydas\__init__.py", line 61, in create_app
        app.container.wire(
      File "src/dependency_injector/containers.pyx", line 250, in dependency_injector.containers.DynamicContainer.wire
      File "C:\Source\Personal\pyDAS\.env\lib\site-packages\dependency_injector\wiring.py", line 238, in wire
        if inspect.isfunction(member):
      File "C:\Python38\lib\inspect.py", line 169, in isfunction
        return isinstance(object, types.FunctionType)
      File "C:\Source\Personal\pyDAS\.env\lib\site-packages\werkzeug-2.0.0rc1-py3.8.egg\werkzeug\local.py", line 379, in __get__
        obj = instance._get_current_object()
      File "C:\Source\Personal\pyDAS\.env\lib\site-packages\werkzeug-2.0.0rc1-py3.8.egg\werkzeug\local.py", line 499, in _get_current_object
        return self.__local()  # type: ignore
      File "C:\Source\Personal\pyDAS\.env\lib\site-packages\flask-1.1.2-py3.8.egg\flask\globals.py", line 38, in _lookup_req_object
        raise RuntimeError(_request_ctx_err_msg)
    RuntimeError: Working outside of request context.
    
    This typically means that you attempted to use functionality that needed
    an active HTTP request.  Consult the documentation on testing for
    information about how to avoid this problem.
    

    Although it's from Flask, it is only raised when calling the wire function, passing in the modules to my blueprints. I've refactored my code to no longer use current_app, thinking that might have made an impact. My primary app factory can be found here: https://github.com/bvanfleet/pydas/blob/u/bvanfleet/di.support/src/pydas/init.py

    Has this ever been encountered before? I tried searching through the other issues, but couldn't find an obvious answer.

    bug 
    opened by bvanfleet 16
  • How to deal with async resources

    How to deal with async resources

    Hi, for my usecase I want to use aio_pika

    And my singleton resource connection is created via:

    connection = await connect(
            "amqp://guest:guest@localhost/", loop=loop
        )
    

    and shutdown via

    await connection.close()
    

    but it looks like something like this is not supported yet:

    async def aio_pika_connection():
     connection = await connect(
            "amqp://guest:guest@localhost/", loop=loop
        )
     yield connection
     await connection.close()
    
    class Container(containers.DeclarativeContainer):
    
        config = providers.Configuration()
    
        aio_pika_connection= providers.Resource(
            aio_pika_connection
        )
    

    Any hints how to deal with this?

    question feature 
    opened by mxab 13
  • Question: providers.Configuration from *.ini

    Question: providers.Configuration from *.ini

    Hi,

    I use this module daily at work and for me fits perfectly! Thanks so much for your work!

    Question: Is there any way to load ini file directly to dependency_injector.providers.Configuration? Currently I solve this by implementing in Core my configuration loader and then override config values. Other way is to use directly python ConfigParser, load ini file and then override Core.config. I don't want to use directly ConfigParser because I had too much customized this class.

    So there is another question: Is there any awy to use customized ConfigParser to paste parameters from ini to Core.config?

    best regards!

    feature 
    opened by thegrymek 13
  • Cannot load pickle file when parameters are passed through Provide

    Cannot load pickle file when parameters are passed through Provide

    Hello, I have a class that is in charge to load some pickle files for a "machine learning" purpose.

    Specifically, I call my class, called Regressor, in this way, through the usage of a .ini file reporting all the desired settings:

    from dependency_injector import containers, providers
    from dependency_injector.wiring import inject, Provide
    from src.service.costestimator.configuration.configuration import Container
    
    class Regressor():
        def __init__(self,
                     regressors_list = Provide[Container.config.regressors_scalers.regressors_list.as_(str)],
                     regressors_path = Provide[Container.config.regressors_scalers.regressors_path.as_(str)],
                     scalers_path = Provide[Container.config.regressors_scalers.scalers_path.as_(str)],
                     file_type_regressors = Provide[Container.config.regressors_scalers.file_type_regressors.as_(str)],
                     file_type_scalers = Provide[Container.config.regressors_scalers.file_type_scalers.as_(str)]):
    

    When it comes to the "core" part of the code, it fails to load the pickle file:

        def load_model(self):
            if self.regressors_out is None:
                resulting_reg = {}
                resulting_scal = {}
                
                for regressor in self.regressors_list:
                    with open(self.regressors_path.joinpath(self.regressors_path, f'{regressor}.{self.file_type_regressors}'), 'rb') as reg:
                        resulting_reg[regressor] = pickle.load(reg)
    

    The error I get is the following: ImportError: cannot import name '_ccallback_c' from 'scipy._lib'

    The funny part is that: if I instantiate my Regressor class using the "Factory approach", it perfectly works.

    Any idea? Thank you in advance for any response

    bug 
    opened by Balthus1989 12
  • impossible to perform wire when modules are dinamically invoked with importlib.import_module

    impossible to perform wire when modules are dinamically invoked with importlib.import_module

    Hello there, I noticed that an explicit import of a package works smoothly, while a dinamic import causes the wire function to not work properly

    When it works:

    `from dependency_injector import containers, providers from dependency_injector.wiring import inject, Provide from pathlib import Path

    from src.service.costestimator.costestimator import costestimator as CE

    if name == 'main': service = 'costestimator' customer = 'john_doe' plant = '0'

    # Retrieving paths
    root_dir = Path.cwd().parent
    ini_file = service + '_' + customer + '_' + plant + '.ini'
    ini_path = root_dir.joinpath(root_dir, 'config', 'params', ini_file)
    
    # Loading needed libraries
    container = importlib.import_module('src.service.' + service + '.configuration.configuration')
    configuration = container.Container()
    configuration.config.from_ini(ini_path)
    configuration.wire(modules=[sys.modules[__name__]])
    
    CE_1 = CE()`
    

    In this case, the output is constituted by prints of fields coming from an .ini file (i.e.: the desired output).

    In the following case, it does not work: ` from dependency_injector import containers, providers from dependency_injector.wiring import inject, Provide from pathlib import Path import importlib

    if name == 'main': service = 'costestimator' customer = 'john_doe' plant = '0'

    # Retrieving paths
    root_dir = Path.cwd().parent
    ini_file = service + '_' + customer + '_' + plant + '.ini'
    ini_path = root_dir.joinpath(root_dir, 'config', 'params', ini_file)
    
    # Loading needed libraries
    container = importlib.import_module('src.service.' + service + '.configuration.configuration')
    configuration = container.Container()
    configuration.config.from_ini(ini_path)
    configuration.wire(modules=[sys.modules[__name__]])
    
    getattr(importlib.import_module('src.service.' + service + '.' + service), service)()
    

    `

    in this case, the result is a print of the Provide objects.

    The init function of the class costestimator is written as: class costestimator(): def __init__(self, customer_name = Provide[Container.config.customer.customer_name.as_(str)], customer_plant = Provide[Container.config.customer.customer_plant.as_(str)]):

    question feature 
    opened by Balthus1989 12
  • Optional dependencies

    Optional dependencies

    I am trying to create a container that optionally takes a dependency, and otherwise provides a value derived from another provider. The (IMO) hacky solution I have so far is a custom provider which either provides a Callable, or a default value if the callable has an error. Then I use this with the Callable being the dependency provider.

    My questions are (1) is there a better way? and (2) even using this method, DefaultCallable defined below seems like a hack -- how can I improve?

    
    T = TypeVar("T")
    
    class DefaultCallable(providers.Provider):
    
        __slots__ = ("_callable", "_default")
    
        def __init__(
            self, callable: Callable[..., T], default: T, *args, **kwargs
        ):
            self._default = default
            self._callable = providers.Callable(callable, *args, **kwargs)
    
            super().__init__()
    
        def __deepcopy__(self, memo):
            copied = memo.get(id(self))
            if copied is not None:
                return copied
    
            # TODO: type?
            copied = self.__class__(
                cast(Callable[..., T], self._callable.provides),
                providers.deepcopy(self._default, memo),
                *providers.deepcopy(self._callable.args, memo),
                **providers.deepcopy(self._callable.kwargs, memo),
            )
            self._copy_overridings(copied, memo)
            return copied
    
        def _provide(self, args, kwargs):
            try:
                return self._callable(*args, **kwargs)
            except Exception:
                # TODO: why do we need to check if is provider?
                # type?
                if getattr(cast(Any, self._default), "__IS_PROVIDER__", False):
                    return cast(Any, self._default)()
                else:
                    return self._default
    
    # Used like
    
    class Foo(containers.DeclarativeContainer):
    
        #: specify dv for pattern discovery (optional)
        dv_in: Provider[xr.DataArray] = providers.Dependency(
            instance_of=xr.DataArray
        )
    
        #: dv for pattern discovery (specified or default)
        dv: Provider[xr.DataArray] = DefaultCallable(
            # cast(Callable[..., xr.DataArray], dv_in), type??
            cast(Any, dv_in),
            problem.training.provided["dv"],
        )
    
    question feature 
    opened by shaunc 12
  • Attempting to inject, getting:

    Attempting to inject, getting: "AttributeError: 'Provide' object has no attribute X"

    Trying to understand how to correctly inject dependencies into a class constructor, the following is a sandbox example where I've extracted the key parts from a broader project.

    from dependency_injector import containers, providers
    from dependency_injector.wiring import Provide, inject
    
    class Config():
        def __init__(self, config_file: str = None):
            self.config_file = config_file
    
    class Container(containers.DeclarativeContainer):
        config = providers.Singleton(Config)
    
    class Engine():
        @inject
        def __init__(
            self,
            config: Config = Provide[Container.config],
        ):
            self.config = config
    
        def init(self) -> None:
            print(f'Reading from config: {self.config.config_file}')
    
    def container_factory(config_file: str = None) -> Container:
        container = containers.DynamicContainer()
        config_provider = providers.Factory(Config, config_file=config_file) \
            if config_file else providers.Factory(Config)
        container.config = config_provider
        return container
    
    def main():
        container = container_factory('/tmp/config.yml')
        container.wire(modules=[__name__])
        engine = Engine()
        engine.init()
    
    if __name__ == '__main__':
        main()
    

    I'm getting an error here from the init log: AttributeError: 'Provide' object has no attribute 'config_file'

    My expected behavior is that config is an instance of the Config class that has been passed the config_file value in its constructor. Instead I seem to be given an instance of the Provide class?

    I have a few questions about this:

    • The documentation is very vague about what wire actually does, and what it expects for its modules/packages arguments. What should these values be? The module and/or package that needs to have dependencies injected?
    • I'm assuming the problem here is that the wire has failed so it's unable to inject correctly?
    • I'm having a hard time finding examples that demonstrate where the @inject decorator needs to go for a class -- is it on the class declaration or on the actual __init__ def, if I wish to inject into the constructor?

    If it's relevant, I use virtualenv .venv to create a virtual env at the root of the project and am using poetry install and poetry shell to load the environment and run it.

    opened by eriknelson 1
  • create task for a coroutine that depends on an async factory

    create task for a coroutine that depends on an async factory

    I have a dependency injection container that holds a coroutine. This coroutine takes some object as a parameter. Also that object is managed by the container - it is created via a factory method but the method itself is asynchronous. The code snippet below depicts clearly how it is done:

    import asyncio
    
    from dependency_injector import containers, providers
    
    
    async def create_a():
        await asyncio.sleep(1)
        return 1
    
    
    async def run(a: int):
        await asyncio.sleep(1)
        return a
    
    
    class Container(containers.DeclarativeContainer):
        a = providers.Factory(
            create_a
        )
    
        run_a = providers.Coroutine(
            run,
            a=a,
        )
    
    
    async def main():
        container = Container()
        asyncio.create_task(container.run_a())
    
    
    if __name__ == "__main__":
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(main())
    

    If create_a was a normal synchronous function, then the code above would run as expected. However, with an async create_a an exception is raised while trying to create a task for container.run():

    Traceback (most recent call last):
      File "C:\Users\-\Desktop\coro\main.py", line 35, in <module>
        loop.run_until_complete(main())
      File "C:\Python310\lib\asyncio\base_events.py", line 641, in run_until_complete
        return future.result()
      File "C:\Users\-\Desktop\coro\main.py", line 29, in main
        asyncio.create_task(container.run())
      File "C:\Python310\lib\asyncio\tasks.py", line 337, in create_task
        task = loop.create_task(coro)
      File "C:\Python310\lib\asyncio\base_events.py", line 433, in create_task
        task = tasks.Task(coro, loop=self, name=name)
    TypeError: a coroutine was expected, got <Future pending>
    

    At first glance, I thought that I need to await container.run() to acquire the actual coroutine object and then pass it to asyncio.create_task() but this way await just runs the run coroutine and blocks execution which is not what I want. What am I doing wrong?

    opened by pikrog 0
  • Question: Possibility of defining dependency parameters for a container on call site

    Question: Possibility of defining dependency parameters for a container on call site

    
    class Service:
        ...
    
    from dependency_injector import containers, providers
    
    
    class Container(containers.DeclarativeContainer):
        # obtain `environment` as a passed in parameter
        environment = providers.Dependency()
    
        # utilise the provided `environment`
        service = providers.Factory(Service, env=environment.provided)
    
    from dependency_injector.wiring import Provide, inject
    
    
    @inject
    def start(service: Service = Provide['service']) -> None:
        ...
    
    
    if __name__ == "__main__":
        # example of passing a param into our container
        container = Container(environment='DEBUG')
        container.wire(modules=[__name__])
    
        start()
    

    Given the above example, with a dependency provided as environment I would like to know if something like this exists within the dependency_injector package, I had a look at the documentation and couldn't really figure out a way to achieve this, and this is as far as I got which doesn't work

    opened by wax911 0
  • Container dependencies issue, multiple files, classes

    Container dependencies issue, multiple files, classes

    Traceback (most recent call last): File "", line 1178, in _find_and_load File "", line 1149, in _find_and_load_unlocked File "", line 690, in _load_unlocked File "", line 940, in exec_module File "", line 241, in _call_with_frames_removed File "D:\Projects\python\user-test\user\route\user_route.py", line 17, in @user_router.get( ^^^^^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\routing.py", line 630, in decorator self.add_api_route( File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\routing.py", line 569, in add_api_route route = route_class( ^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\routing.py", line 442, in init get_parameterless_sub_dependant(depends=depends, path=self.path_format), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\dependencies\utils.py", line 135, in get_parameterless_sub_dependant return get_sub_dependant(depends=depends, dependency=depends.dependency, path=path) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\dependencies\utils.py", line 158, in get_sub_dependant sub_dependant = get_dependant( ^^^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\dependencies\utils.py", line 281, in get_dependant endpoint_signature = get_typed_signature(call) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\site-packages\fastapi\dependencies\utils.py", line 249, in get_typed_signature signature = inspect.signature(call) ^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\inspect.py", line 3278, in signature return Signature.from_callable(obj, follow_wrapped=follow_wrapped, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\inspect.py", line 3026, in from_callable return _signature_from_callable(obj, sigcls=cls, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Eugene\AppData\Local\Programs\Python\Python311\Lib\inspect.py", line 2615, in _signature_from_callable raise ValueError('callable {!r} is not supported by signature'.format(obj)) ValueError: callable <dependency_injector.providers.Factory(<class 'user.infrastructure.query.user_uow.UserUnitOfWork'>) at 0x27549c2cc40> is not supported by signature python-BaseException

    opened by Spenchik 1
  • Issue a warning if the decorated function doesn't use `Provide` arguments

    Issue a warning if the decorated function doesn't use `Provide` arguments

    When a function is decorated with @inject the wrapped function is inspected for Provide[...] arguments:

    https://github.com/ets-labs/python-dependency-injector/blob/cc2304e46e054ae08dc12995428759fbfb51af10/src/dependency_injector/wiring.py#L564

    But if multiple decorators are used like this

    @inject
    @some_other_decorator
    def my_func(...):
    

    and some_other_decorator doesn't use functools.wraps, the Provide arguments are not found.

    Here is a reproducible example:

    import functools
    from dependency_injector import containers, providers
    from dependency_injector.wiring import Provide, inject
    
    
        
    def some_other_decorator(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapped
    
    
    
    class Service:
        ...
    
    
    class Container(containers.DeclarativeContainer):
        service = providers.Factory(Service)
    
    
    @inject
    @some_other_decorator
    def main(service: Service = Provide[Container.service]) -> None:
        print(service)
    
    
    if __name__ == "__main__":
        container = Container()
        # btw, this doesn't work: container.wire(modules=[__name__])
        # copied from https://github.com/ets-labs/python-dependency-injector/blob/master/examples/wiring/example.py
        container.wire(modules=[__name__])
        main()
    
    

    If we comment out the @functools.wraps(func) line, we get printed:

    <dependency_injector.wiring.Provide object at 0x10ae99fd0>
    

    Issuing a warning inside _fetch_reference_injections if the decorated function doesn't have Provide arguments would help:

    1. When such a decorator is used
    2. When someone is using @inject and Provide was removed as unnecessary.
    opened by warvariuc 0
  • Allow Closing to detect dependent resources passed as kwargs too #636

    Allow Closing to detect dependent resources passed as kwargs too #636

    A small addiction to the work of @StummeJ about issue #633 which allows to benefit of his improvement even for dependencies passed as kwargs (such as my case)

    opened by federinik 0
Owner
ETS Labs
Expert Technical Solutions Labs
ETS Labs
A Container for the Dependency Injection in Python.

Python Dependency Injection library aiodi is a Container for the Dependency Injection in Python. Installation Use the package manager pip to install a

Denis NA 3 Nov 25, 2022
Python lightweight dependency injection library

pythondi pythondi is a lightweight dependency injection library for python Support both sync and async functions Installation pip3 install pythondi Us

Hide 41 Dec 16, 2022
Run async workflows using pytest-fixtures-style dependency injection

Run async workflows using pytest-fixtures-style dependency injection

Simon Willison 26 Jun 26, 2022
A library for interacting with Path of Exile game and economy data, and a unique loot filter generation framework.

wraeblast A library for interfacing with Path of Exile game and economy data, and a set of item filters geared towards trade league players. Filter Ge

David Gidwani 29 Aug 28, 2022
A collection of resources/tools and analyses for the angr binary analysis framework.

Awesome angr A collection of resources/tools and analyses for the angr binary analysis framework. This page does not only collect links and external r

null 105 Jan 2, 2023
Modest utility collection for development with AIOHTTP framework.

aiohttp-things Modest utility collection for development with AIOHTTP framework. Documentation https://aiohttp-things.readthedocs.io Installation Inst

Ruslan Ilyasovich Gilfanov 0 Dec 11, 2022
✨ Voici un code en Python par moi, et en français qui permet d'exécuter du Javascript en Python.

JavaScript In Python ❗ Voici un code en Python par moi, et en français qui permet d'exécuter du Javascript en Python. ?? Une vidéo pour vous expliquer

MrGabin 4 Mar 28, 2022
Simple python module to get the information regarding battery in python.

Battery Stats A python3 module created for easily reading the current parameters of Battery in realtime. It reads battery stats from /sys/class/power_

Shreyas Ashtamkar 5 Oct 21, 2022
ticktock is a minimalist library to view Python time performance of Python code.

ticktock is a minimalist library to view Python time performance of Python code.

Victor Benichoux 30 Sep 28, 2022
Python @deprecat decorator to deprecate old python classes, functions or methods.

deprecat Decorator Python @deprecat decorator to deprecate old python classes, functions or methods. Installation pip install deprecat Usage To use th

null 12 Dec 12, 2022
A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.

A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.

PyBash 11 May 22, 2022
Find dependent python scripts of a python script in a project directory.

Find dependent python scripts of a python script in a project directory.

null 2 Dec 5, 2021
A functional standard library for Python.

Toolz A set of utility functions for iterators, functions, and dictionaries. See the PyToolz documentation at https://toolz.readthedocs.io LICENSE New

null 4.1k Dec 30, 2022
Python Classes Without Boilerplate

attrs is the Python package that will bring back the joy of writing classes by relieving you from the drudgery of implementing object protocols (aka d

The attrs Cabal 4.6k Jan 6, 2023
🔩 Like builtins, but boltons. 250+ constructs, recipes, and snippets which extend (and rely on nothing but) the Python standard library. Nothing like Michael Bolton.

Boltons boltons should be builtins. Boltons is a set of over 230 BSD-licensed, pure-Python utilities in the same spirit as — and yet conspicuously mis

Mahmoud Hashemi 6k Jan 4, 2023
Retrying library for Python

Tenacity Tenacity is an Apache 2.0 licensed general-purpose retrying library, written in Python, to simplify the task of adding retry behavior to just

Julien Danjou 4.3k Jan 5, 2023
Simple yet flexible natural sorting in Python.

natsort Simple yet flexible natural sorting in Python. Source Code: https://github.com/SethMMorton/natsort Downloads: https://pypi.org/project/natsort

Seth Morton 712 Dec 23, 2022
A Python utility belt containing simple tools, a stdlib like feel, and extra batteries. Hashing, Caching, Timing, Progress, and more made easy!

Ubelt is a small library of robust, tested, documented, and simple functions that extend the Python standard library. It has a flat API that all behav

Jon Crall 638 Dec 13, 2022
Retrying is an Apache 2.0 licensed general-purpose retrying library, written in Python, to simplify the task of adding retry behavior to just about anything.

Retrying Retrying is an Apache 2.0 licensed general-purpose retrying library, written in Python, to simplify the task of adding retry behavior to just

Ray Holder 1.9k Dec 29, 2022