Injector API reference

Note

Unless specified otherwise, instance methods are not thread safe.

The following functions are thread safe:

  • Injector.get()
  • injection provided by inject() decorator (please note, however, that it doesn’t say anything about decorated function thread safety)

Injector - Python dependency injection framework, inspired by Guice

copyright:
  1. 2012 by Alec Thomas
license:

BSD

class injector.Binder(injector, auto_bind=True, parent=None)

Bases: object

Bind interfaces to implementations.

Note

This class is instantiated internally for you and there’s no need to instantiate it on your own.

bind(interface, to=None, scope=None)

Bind an interface to an implementation.

Parameters:
  • interface – Interface or Key() to bind.
  • to – Instance or class to bind to, or an explicit Provider subclass.
  • scope – Optional Scope in which to bind.
bind_scope(scope)

Bind a Scope.

Parameters:scope – Scope class.
install(module)

Install a module into this binder.

In this context the module is one of the following:

  • function taking the Binder as it’s only parameter

    def configure(binder):
        bind(str, to='s')
    
    binder.install(configure)
    
  • instance of Module (instance of it’s subclass counts)

    class MyModule(Module):
        def configure(self, binder):
            binder.bind(str, to='s')
    
    binder.install(MyModule())
    
  • subclass of Module - the subclass needs to be instantiable so if it expects any parameters they need to be injected

    binder.install(MyModule)
    
multibind(interface, to, scope=None)

Creates or extends a multi-binding.

A multi-binding maps from a key to a sequence, where each element in the sequence is provided separately.

Parameters:
  • interfaceMappingKey() or SequenceKey() to bind to.
  • to – Instance, class to bind to, or an explicit Provider subclass. Must provide a sequence.
  • scope – Optional Scope in which to bind.
class injector.BoundKey

Bases: tuple

A BoundKey provides a key to a type with pre-injected arguments.

>>> class A(object):
...   def __init__(self, a, b):
...     self.a = a
...     self.b = b
>>> InjectedA = BoundKey(A, a=InstanceProvider(1), b=InstanceProvider(2))
>>> injector = Injector()
>>> a = injector.get(InjectedA)
>>> a.a, a.b
(1, 2)
exception injector.CallError

Bases: injector.Error

Call to callable object fails.

class injector.CallableProvider(callable)

Bases: injector.Provider

Provides something using a callable.

The callable is called every time new value is requested from the provider.

>>> key = Key('key')
>>> def factory():
...     print('providing')
...     return []
...
>>> def configure(binder):
...     binder.bind(key, to=CallableProvider(factory))
...
>>> injector = Injector(configure)
>>> injector.get(key) is injector.get(key)
providing
providing
False
exception injector.CircularDependency

Bases: injector.Error

Circular dependency detected.

class injector.ClassProvider(cls)

Bases: injector.Provider

Provides instances from a given class, created using an Injector.

exception injector.Error

Bases: exceptions.Exception

Base exception.

class injector.Injector(modules=None, auto_bind=True, parent=None, use_annotations=False)

Bases: object

Parameters:
  • modules

    Optional - a configuration module or iterable of configuration modules. Each module will be installed in current Binder using Binder.install().

    Consult Binder.install() documentation for the details.

  • auto_bind – Whether to automatically bind missing types.
  • parent – Parent injector.
  • use_annotations – Attempt to infer injected arguments using Python3 argument annotations.

If you use Python 3 you can make Injector use constructor parameter annotations to determine class dependencies. The following code:

class B(object):
    @inject(a=A):
    def __init__(self, a):
        self.a = a

can now be written as:

class B(object):
    def __init__(self, a:A):
        self.a = a

To enable Python 3 annotation support, instantiate your Injector with use_annotations=True.

New in version 0.7.5: use_annotations parameter

call_with_injection(callable, self_=None, args=(), kwargs={})

Call a callable and provide it’s dependencies if needed.

Parameters:
  • self – Instance of a class callable belongs to if it’s a method, None otherwise.
  • args (tuple of objects) – Arguments to pass to callable.
  • kwargs (dict of string -> object) – Keyword arguments to pass to callable.
Returns:

Value returned by callable.

create_object(cls, additional_kwargs=None)

Create a new instance, satisfying any dependencies on cls.

get(interface, scope=None)

Get an instance of the given interface.

Note

Although this method is part of Injector‘s public interface it’s meant to be used in limited set of circumstances.

For example, to create some kind of root object (application object) of your application (note that only one get call is needed, inside the Application class and any of its dependencies inject() can and should be used):

class Application(object):

    @inject(dep1=Dep1, dep2=dep2)
    def __init__(self, dep1, dep2):
        self.dep1 = dep1
        self.dep2 = dep2

    def run(self):
        self.dep1.something()

injector = Injector(configuration)
application = injector.get(Application)
application.run()
Parameters:
  • interface – Interface whose implementation we want.
  • scope – Class of the Scope in which to resolve.
Returns:

An implementation of interface.

install_into(instance)

Put injector reference in given object.

This method has, in general, two applications:

  • Injector internal use (not documented here)

  • Making it possible to inject into methods of an object that wasn’t created

    using Injector. Usually it’s because you either don’t control the instantiation process, it’d generate unnecessary boilerplate or it’s just easier this way.

    For example, in application main script:

    from injector import Injector
    
    class Main(object):
        def __init__(self):
            def configure(binder):
                binder.bind(str, to='Hello!')
    
            injector = Injector(configure)
            injector.install_into(self)
    
        @inject(s=str)
        def run(self, s):
            print(s)
    
    if __name__ == '__main__':
        main = Main()
        main.run()
    

Note

You don’t need to use this method if the object is created using Injector.

Warning

Using install_into to install Injector reference into an object created by different Injector instance may very likely result in unexpected behaviour of that object immediately or in the future.

class injector.InstanceProvider(instance)

Bases: injector.Provider

Provide a specific instance.

>>> my_list = Key('my_list')
>>> def configure(binder):
...     binder.bind(my_list, to=InstanceProvider([]))
...
>>> injector = Injector(configure)
>>> injector.get(my_list) is injector.get(my_list)
True
>>> injector.get(my_list).append('x')
>>> injector.get(my_list)
['x']
injector.Key(name)

Create a new type key.

>>> Age = Key('Age')
>>> def configure(binder):
...   binder.bind(Age, to=90)
>>> Injector(configure).get(Age)
90
injector.MappingKey(name)

As for Key, but declares a multibind mapping.

class injector.Module

Bases: object

Configures injector and providers.

configure(binder)

Override to configure bindings.

class injector.NoScope(injector=None)

Bases: injector.Scope

An unscoped provider.

class injector.Provider

Bases: object

Provides class instances.

class injector.ProviderOf(injector, interface)

Bases: typing.Generic

Can be used to get a provider of an interface, for example:

>>> def provide_int():
...     print('providing')
...     return 123
>>>
>>> def configure(binder):
...     binder.bind(int, to=provide_int)
>>>
>>> injector = Injector(configure)
>>> provider = injector.get(ProviderOf[int])
>>> value = provider.get()
providing
>>> value
123
get()

Get an implementation for the specified interface.

class injector.Scope(injector)

Bases: object

A Scope looks up the Provider for a binding.

By default (ie. NoScope ) this simply returns the default Provider .

configure()

Configure the scope.

get(key, provider)

Get a Provider for a key.

Parameters:
  • key – The key to return a provider for.
  • provider – The default Provider associated with the key.
Returns:

A Provider instance that can provide an instance of key.

injector.SequenceKey(name)

As for Key, but declares a multibind sequence.

class injector.SingletonScope(injector)

Bases: injector.Scope

A Scope that returns a per-Injector instance for a key.

singleton can be used as a convenience class decorator.

>>> class A(object): pass
>>> injector = Injector()
>>> provider = ClassProvider(A)
>>> singleton = SingletonScope(injector)
>>> a = singleton.get(A, provider)
>>> b = singleton.get(A, provider)
>>> a is b
True
class injector.ThreadLocalScope(injector)

Bases: injector.Scope

A Scope that returns a per-thread instance for a key.

exception injector.UnknownProvider

Bases: injector.Error

Tried to bind to a type whose provider couldn’t be determined.

exception injector.UnsatisfiedRequirement

Bases: injector.Error

Requirement could not be satisfied.

injector.inject(function=None, **bindings)

Decorator declaring parameters to be injected.

eg.

>>> Sizes = Key('sizes')
>>> Names = Key('names')
>>>
>>> # Recommended, Python 3+ style
>>> class A:
...     @inject
...     def __init__(self, number: int, name: str, sizes: Sizes):
...         print([number, name, sizes])
...
>>> # Or older, Python 2-compatible style
>>> class A(object):
...     @inject(number=int, name=str, sizes=Sizes)
...     def __init__(self, number, name, sizes):
...         print([number, name, sizes])
...
>>> def configure(binder):
...     binder.bind(A)
...     binder.bind(int, to=123)
...     binder.bind(str, to='Bob')
...     binder.bind(Sizes, to=[1, 2, 3])

Use the Injector to get a new instance of A:

>>> a = Injector(configure).get(A)
[123, 'Bob', [1, 2, 3]]
injector.is_decorated_with_inject(function)

See if given callable is declared to want some dependencies injected.

Example use:

>>> def fun(i: int) -> str:
...     return str(i)
>>> is_decorated_with_inject(fun)
False
>>>
>>> @inject
... def fun2(i: int) -> str:
...     return str(i)
>>> is_decorated_with_inject(fun2)
True
injector.noninjectable(*args)

Mark some parameters as not injectable.

This serves as documentation for people reading the code and will prevent Injector from ever attempting to provide the parameters.

For example:

>>> class Service:
...    pass
...
>>> class SomeClass:
...     @inject
...     @noninjectable('user_id')
...     def __init__(self, service: Service, user_id: int):
...         # ...
...         pass

noninjectable() decorations can be stacked on top of each other and the order in which a function is decorated with inject() and noninjectable() doesn’t matter.

injector.provider(function)

Decorator for Module methods, registering a provider of a type.

>>> class MyModule(Module):
...   @provider
...   def provide_name(self) -> str:
...       return 'Bob'

@provider-decoration implies @inject so you can omit it and things will work just the same:

>>> class MyModule2(Module):
...     def configure(self, binder):
...         binder.bind(int, to=654)
...
...     @provider
...     def provide_str(self, i: int) -> str:
...         return str(i)
...
>>> injector = Injector(MyModule2)
>>> injector.get(str)
'654'

Note

This function works only on Python 3

injector.provides(interface, scope=None, eager=False)

Decorator for Module methods, registering a provider of a type.

Warning

Deprecated, use provider() instead.

>>> class MyModule(Module):
...   @provides(str)
...   def provide_name(self):
...       return 'Bob'
Parameters:
  • interface – Interface to provide.
  • scope – Optional scope of provided value.
injector.with_injector(*injector_args, **injector_kwargs)

Decorator for a method. Installs Injector object which the method belongs to before the decorated method is executed.

Parameters are the same as for Injector constructor.