A simple dependency injection library for python
To mark class as injectable use @component
annotation:
from tagil import component
@component
class InjectableClass:
def __init__(self):
pass
Now you can construct instance of this class with InjectionManager
:
from tagil import InjectionManager
instance = InjectionManager().get_component(InjectableClass)
All dependent instances from __init__
will be resolved automatically if there is class annotation and @component
decorator:
from tagil import component, InjectionManager
@component
class ClassWithDependency:
def __init__(self, injectable: InjectableClass):
self.injectable = injectable
instance = InjectionManager().get_component(ClassWithDependency)
Instance will be fully initialized.
You can assign function as a constructor function for component via @constructor
decorator:
from tagil import constructor
class SomeDependency:
pass
class SomeComponent:
def __init__(self, dep):
self.dep = dep
@constructor
def some_component(dep: SomeDependency) -> SomeComponent:
return SomeComponent(dep)
Function some_component
will be added as constructor.
You can get its result by function name (or by decorator parameter name
) and by class annotation if such annotation
present.
All dependencies from constructor arguments will be resolved the same way they are resolved in __init__
method.
In some rare cases you would like to manually set injectable components.
For that case use inject
parameter of @component
or @constructor
decorators:
from tagil import component, constructor
@component(inject={
"dependency": "dependence_component_name",
})
class SomeComponent:
def __init__(self, dependency):
self.dependency = dependency
@constructor(inject={
"dependency": DependencyClass,
})
def some_constructor(dependency):
return SomeAnotherComponent(dependency)
In that case dependencies will be resolved by they names or classes provided in inject dictionary.
When creating components tagil build initialization stack.
You can manually call InjectionManager().post_init()
and InjectionManager().pre_destory()
or use application
template via Application
base class:
from tagil import component, Application
@component()
class SimpleApp(Application):
def run(self) -> int:
return 0
if __name__ == "__main__":
SimpleApp.main()
All calls for post_init
and pre_destroy
methods of components will be performed by base class.
To define which component should be injected at instance creation tagil performs following set of rules:
- If injectable component name or class is set via
inject
argument, tagil will search component or constructor with that name or class. - If type of argument is present:
- Tagil will search component or constructor with this type or with subclass type.
- In case of many of candidates tagil will try to use argument name as component or constructor name
- If no type information or decorator rules are set tagil will search component by argument name.