I ran into this problem too and after much search I found the answer.

You can inject the callable by using the provider attribute:

import passlib.hash

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject


class Container(containers.DeclarativeContainer):
    # Use the 'provider' attribute on the provider in the container
    password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify).provider


@inject
def bar(password_verifier=Provide[Container.password_verifier]):
    password_verifier(...) 


if __name__ == "__main__":
    container = Container()
    container.wire(modules=[__name__])

    bar()
Answer from Aesonus on Stack Overflow
🌐
Ets-labs
python-dependency-injector.ets-labs.org › providers › callable.html
Callable provider — Dependency Injector 4.49.1 documentation
Callable provider calls a function, a method or another callable. import passlib.hash from dependency_injector import containers, providers class Container(containers.DeclarativeContainer): password_hasher = providers.Callable( passlib.hash.sha256_crypt.hash, salt_size=16, rounds=10000, ) ...
🌐
Ets-labs
python-dependency-injector.ets-labs.org › providers › index.html
Providers — Dependency Injector 4.49.0 documentation
Providers help to assemble the objects. They create objects and inject the dependencies. Each provider is a callable. You call the provider like a function when you need to create an object. Provider retrieves the underlying dependencies and inject them into the created object.
🌐
GitHub
github.com › ets-labs › python-dependency-injector
GitHub - ets-labs/python-dependency-injector: Dependency injection framework for Python · GitHub
Dependency Injector is a dependency injection framework for Python. It helps implement the dependency injection principle. ... Providers. Provides Factory, Singleton, Callable, Coroutine, Object, List, Dict, Configuration, Resource, Dependency, ...
Author   ets-labs
Top answer
1 of 2
3

I ran into this problem too and after much search I found the answer.

You can inject the callable by using the provider attribute:

import passlib.hash

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject


class Container(containers.DeclarativeContainer):
    # Use the 'provider' attribute on the provider in the container
    password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify).provider


@inject
def bar(password_verifier=Provide[Container.password_verifier]):
    password_verifier(...) 


if __name__ == "__main__":
    container = Container()
    container.wire(modules=[__name__])

    bar()
2 of 2
1

The method passlib.hash.sha256_crypt.verify requires two positional arguments, secret and hash as shown here: https://passlib.readthedocs.io/en/stable/lib/passlib.hash.sha256_crypt.html

Because you're injecting an attribute of the Container, the DI framework must create an instance of this to inject it into the bar() method. The DI framework is unable to instantiate this object however since the required positional arguments are missing.

If you wanted to use the method in bar(), you'd have to do so without provoking the DI framework to try to create an instance of the object at initialisation time. You could do this with the following:

import passlib.hash

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject


class Container(containers.DeclarativeContainer):
    password_hasher = providers.Callable(
        passlib.hash.sha256_crypt.hash,
        salt_size=16,
        rounds=10000,
    )
    password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)


@inject
def bar(container=Provide[Container]):
    hashed_password = container.password_hasher("123")
    assert container.password_verifier("123", hashed_password)


if __name__ == "__main__":
    container = Container()
    container.wire(modules=[__name__])

    bar()
🌐
Ets-labs
python-dependency-injector.ets-labs.org
Dependency Injector — Dependency injection framework for Python — Dependency Injector 4.49.1 documentation
Dependency Injector is a dependency injection framework for Python. It helps implementing the dependency injection principle. ... Providers. Provides Factory, Singleton, Callable, Coroutine, Object, List, Dict, Configuration, Resource, Dependency, and Selector providers that help assemble your ...
🌐
GitHub
github.com › ets-labs › python-dependency-injector › blob › master › docs › providers › callable.rst
python-dependency-injector/docs/providers/callable.rst at master · ets-labs/python-dependency-injector
.. literalinclude:: ../../examples/providers/callable.py :language: python :lines: 3- Callable provider handles an injection of the dependencies the same way like a :ref:`factory-provider`. ..
Author   ets-labs
🌐
Medium
medium.com › @rmogylatov › dependency-injector-python-dependency-injection-framework-eeb9f5c6db8b
Dependency Injector — Python dependency injection framework | by Roman Mogylatov | Medium
September 10, 2020 - Each provider is a callable. You call the provider like a function when you need to create an object. Provider retrieves the underlying dependencies and inject them into the created object.
Find elsewhere
🌐
Ets-labs
python-dependency-injector.ets-labs.org › providers › selector.html
Selector provider — Dependency Injector 4.49.1 documentation
When a Selector provider is called, it gets a selector value and delegates the work to the provider with a matching name. The selector callable works as a switch: when the returned value is changed the Selector provider will delegate the work to another provider. ... Aggregate provider to inject ...
🌐
PyPI
pypi.org › project › dependency-injector
dependency-injector · PyPI
Dependency Injector is a dependency injection framework for Python. It helps implement the dependency injection principle. ... Providers. Provides Factory, Singleton, Callable, Coroutine, Object, List, Dict, Configuration, Resource, Dependency, ...
      » pip install dependency-injector
    
Published   Jun 18, 2026
Version   4.49.1
🌐
GitHub
github.com › ets-labs › python-dependency-injector › blob › master › src › dependency_injector › providers.pyx
python-dependency-injector/src/dependency_injector/providers.pyx at master · ets-labs/python-dependency-injector
Callable interface implementation. """ if self._last_overriding is None: raise Error("{0} must be overridden before calling".format(self)) return super().__call__(*args, **kwargs) · def override(self, provider): """Override provider with another provider. · :param provider: Overriding provider. :type provider: :py:class:`Provider` · :raise: :py:exc:`dependency_injector.errors.Error` ·
Author   ets-labs
🌐
GitHub
github.com › ets-labs › python-dependency-injector › blob › master › src › dependency_injector › providers.pyi
python-dependency-injector/src/dependency_injector/providers.pyi at master · ets-labs/python-dependency-injector
def __init__(self, **dependencies: Provider) -> None: ... def __getattr__(self, name: str) -> Provider: ... @property · def providers(self) -> _Dict[str, Provider]: ... def resolve_provider_name(self, provider: Provider) -> str: ... @property · def parent(self) -> Optional[ProviderParent]: ... @property · def parent_name(self) -> Optional[str]: ... def assign_parent(self, parent: ProviderParent) -> None: ... · class Callable(Provider[T_Any]): def __init__( self, provides: Optional[Union[_Callable[..., T_Any], str]] = None, *args: Injection, **kwargs: Injection, ) -> None: ...
Author   ets-labs
Top answer
1 of 2
2

I've noticed that managing dependencies feels like a boring chore that I want to minimize.

First of all, you shouldn't assume that dependency injection is a means to minimize the chore of dependency management. It doesn't go away, it is just deferred to another place and time and possibly delegated to someone else.

That said, if what you are building is going to be used by others it would thus be wise to include some form of version checking into your 'injectables'so that your users will have an easy way to check if their version matches the one that is expected.

are there more expressive design patterns in existence?

Your method as I understand it is essentially a Strategy-Pattern, that is the job's code (callable) relies on calling methods on one of several concrete objects. The way you do it is perfectly reasonable - it works and is efficient.

You may want to formalize it a bit more to make it easier to read and maintain, e.g.

from collections import namedtuple

Job = namedtuple('Job', ['callable', 'args', 'strategies'])

def run_job(job, using=None):
    strategies = { k: using[k] for k in job.strategies] }
    return job.callable(*args, **strategies)

jobs_to_run = [
  Job(callable=some_func, args=(1,2), strategies=('A', 'B')),
  Job(callable=other_func, ...),
]

strategies = {"A": injected_strategy, ...}
for job in jobs_to_run: 
   run_job(job, using=strategies)

# actual job
def some_func(arg1, arg2, A=None, B=None):
   ...

As you can see the code still does the same thing, but it is instantly more readable, and it concentrates knowledge about the structure of the Job() objects in run_job. Also the call to a job function like some_func will fail if the wrong number of arguments are passed, and the job functions are easier to code and debug due to their explicitely listed and named arguments.

2 of 2
1

About the strings you could just make'em constants in a dependencies.py file an use these constants.

An more robust option with still little overhead would to be to use a dependency injection framework such as Injectable:

@autowired
def job42(some_instance: Autowired("SomeInstance", lazy=true)):
    ...

# some_instance is autowired to job42 calls and
# it will be automatically injected for you
job42()

Disclosure: I am the project maintainer.

🌐
PyPI
pypi.org › project › dependency-injector › 3.15.0
dependency-injector
JavaScript is disabled in your browser · Please enable JavaScript to proceed · A required part of this site couldn’t load. This may be due to a browser extension, network issues, or browser settings. Please check your connection, disable any ad blockers, or try using a different browser
🌐
Readthedocs
dependency-injection-py.readthedocs.io
dependency_injection.py — dependency_injection.py 1.1.0 documentation
>>> def inject_dependencies(func): ... my_state = {'bar': 1, 'baz': 2, 'bloo': 'blee'} ... dependencies = resolve_dependencies(func, my_state) ... return func(*dependencies.as_args) ... ... See get_signature for details on support for non-function callables.
🌐
PyPI
pypi.org › project › dependency-injector › 3.11.1
dependency-injector 3.11.1
JavaScript is disabled in your browser · Please enable JavaScript to proceed · A required part of this site couldn’t load. This may be due to a browser extension, network issues, or browser settings. Please check your connection, disable any ad blockers, or try using a different browser
🌐
Medium
medium.com › @spraneeth4 › python-dependency-injector-simplifying-dependency-injection-in-your-projects-14385af0bf78
Python Dependency Injector: Simplifying Dependency Injection in Your Projects | by praneeth_vvs | Medium
September 27, 2024 - Dependency Injector is a lightweight, comprehensive DI tool for Python that simplifies management of application components and their dependencies. It comes with features like: Containers: To encapsulate the configuration and provision of ...