injections

Simple dependency injection library


Keywords
dependency, di, injection, python, python2, python3
License
MIT
Install
pip install injections==0.2.2

Documentation

Injections

Injections is a simple dependency injection library which is intended to cleanup object dependency hell.

Usage

Declare a class' dependencies:

@injections.has
class Hello(object):

    world = injections.depends(World, 'universe')

You must decorate class with @injections.has. All dependencies has a type(class), which is World in this case, and a name, which is universe in this case. This is for having multiple similar dependencies.

Note: Name of dependency is unique among all services in single dependency injector and not tied to particular type. This is done to easier support subclassing of dependencies (and you can also register subclass with abc instead of subclassing directly)

Then at some initialisation code you create dependency injector, and set apropriate services:

inj = injections.Container()
inj['universe'] = World()

Now you can create Hello instances and inject dependencies to them:

hello = inj.inject(Hello())
assert hello.world is inj['universe']

And you can propagate dependencies starting from existing instances:

h2 = injections.propagate(hello, Hello())
assert h2.world is hello.world

If you need do some class initialization when dependencies are ready, you must do the work in __injected__ method instead of __init__:

@injections.has
class CachedValue(object):
    redis = injections.depends(Redis)
    def __injected__(self):
        self.cached_value = self.redis.get('cache')

If you need to propagate some dependencies, you are probably want do do it in the __injected__ method too:

@injections.has
class Child:
    redis = injections.depends(Redis)

@injections.has
class Parent:
    def __injected__(self):
        self.child = injections.propagate(self, Child())

Note: In the last two examples where name is omitted, it's got from the name of the attribute to assign to. It's used to avoid repetitive typing, but may be error prone.

Cyclic Dependencies

Dependencies between objects might be cyclic as long as object don't use each other in __injected__ method. To handle cyclic depencency between classes A and B use code similar to the following:

inj['a'] = A()
inj['b'] = B()
inj.inject(inj['a'])
inj.inject(inj['b'])

Automatic Interconnection (experimental)

Sometimes it's useful to omit inject() calls for the objects put in container, and then connect them all using interconnect_all():

inj['a'] = A()
inj['b'] = B()
inj['c'] = C()
inj.interconnect_all()

This will call inj.inject for all objects in container in proper order (using topology sort based on their dependencies). It doesn't make your container sealed, so you can add more dependencies later, and interconnect new ones too.

Note: Cyclic dependencies are not processed by interconnect_all, so you must either do inject() for them (in proper order) before calling interconnect, or add them to the container after. In any case injections will not try to guess, but will fail with runtime exception if can't find out proper order.

History

The library was ininitally named zorro.di and was a part of zorro networking library.