Dependency injection tool
Project description
injectool
Lightweight dependency injection tool.
Installation
Install using pip:
pip install injectool
How to use
Injecting
https://github.com/eumis/injectool/blob/dev/injectool/injection.py
resolve()
import injectool
instance = injectool.resolve(SomeClass)
function = injectool.resolve(some_function)
value = injectool.resolve('some_value')
inject decorator
import injectool
from typing import Callable
class DependenciesUser:
@injectool.inject(instance=SomeClass)
def __init__(self, instance: SomeClass = injectool.In):
pass
@injectool.inject(function=some_function)
def some_method(self, function: Callable = injectool.In):
pass
@injectool.inject(value='some_value')
def use_some_value(value: int = injectool.In):
pass
dependency decorator
import injectool
@injectool.dependency
def some_function():
return 'some_function'
def some_function_implementation():
return 'some_function implementation'
injectool.add_singleton(some_function, some_function_implementation)
value = some_function() # value: some_function implementation
Dependencies
https://github.com/eumis/injectool/blob/dev/injectool/resolvers.py
Singleton
import injectool
injectool.add_singleton('some_value', 54)
some_value = injectool.resolve('some_value')
injectool.add_singleton(SomeClass, SomeClassImplementation())
instance: SomeClass = injectool.resolve(SomeClass)
Type
New instance is created for every resolving.
import injectool
injectool.add_type(SomeClass, SomeClassImplementation)
instance = injectool.resolve(SomeClass)
Scoped
One instance is created per scope.
import injectool
injectool.add_scoped(SomeClass, SomeClassImplementation)
with injectool.scope():
instance1: SomeClass = injectool.resolve(SomeClass)
with injectool.scope():
instance2: SomeClass = injectool.resolve(SomeClass)
Dispose method can be passed to add_type method. The method will be called on closing scope.
import injectool
def dispose(instance: SomeClassImplementation):
pass
injectool.add_scoped(SomeClass, SomeClassImplementation, dispose)
with injectool.scope():
injectool.resolve(SomeClass)
Thread
One instance is created per thread.
import injectool
from threading import Thread
from concurrent.futures.thread import ThreadPoolExecutor
injectool.add_per_thread(SomeClass, SomeClassImplementation)
one = injectool.resolve(SomeClass)
def thread_target():
two = injectool.resolve(SomeClass)
thread = Thread(target=thread_target)
thread.start()
with ThreadPoolExecutor(max_workers=1) as executor:
future = executor.submit(injectool.resolve, SomeClass)
three = future.result()
Custom resolver
import injectool
injectool.add('some_value', lambda: 54)
some_value = injectool.resolve('some_value')
injectool.add(SomeClass, lambda: SomeClassImplementation())
instance: SomeClass = injectool.resolve(SomeClass)
How it works
All dependencies are stored in Container.
Basically Container is just a dictionary with Dependency used as a key and Resolver used as a value.
Any object can be used as Dependency.
Resolver is function that returns value for a Dependency.
https://github.com/eumis/injectool/blob/dev/injectool/core.py#L12-37
Dependency = Any
Resolver = Callable[[], Any]
class Container:
"""Container for dependencies"""
def __init__(self, resolvers: Optional[Dict[Dependency, Resolver]] = None):
self._resolvers: Dict[Dependency, Resolver] = {} if resolvers is None else resolvers
self.set(Container, lambda: self)
def set(self, dependency: Dependency, resolve: Resolver):
"""Sets resolver for dependency"""
self._resolvers[dependency] = resolve
def resolve(self, dependency: Dependency) -> Any:
"""Resolve dependency"""
resolve = self._resolvers.get(dependency)
if resolve is None:
dependency_name = dependency.__name__ if hasattr(dependency, '__name__') else str(dependency)
raise DependencyError(f'Dependency "{dependency_name}" is not found')
return resolve()
def copy(self) -> 'Container':
"""returns new container with same dependencies"""
return Container(self._resolvers.copy())
Default container is stored as global variable and used by default. Default container can be changed.
https://github.com/eumis/injectool/blob/dev/injectool/core.py#L40-45
_DEFAULT_CONTAINER = Container()
def set_default_container(container: Container):
"""Sets default container"""
global _DEFAULT_CONTAINER
_DEFAULT_CONTAINER = container
Current container can be set and used temporary. It's stored in ContextVar so it can be used in asynchronous code.
https://github.com/eumis/injectool/blob/dev/injectool/core.py#L48-66
_CURRENT_CONTAINER = ContextVar('dependency_container')
def get_container() -> Container:
"""Returns current container"""
return _CURRENT_CONTAINER.get(_DEFAULT_CONTAINER)
@contextmanager
def use_container(container: Optional[Container] = None) -> Generator[Container, None, None]:
"""
Uses passed container for registering and resolving dependencies
Creates new if container doesn't exist.
"""
container = container if container else Container()
reset_token = _CURRENT_CONTAINER.set(container)
try:
yield container
finally:
_CURRENT_CONTAINER.reset(reset_token)
License
Copyright (c) 2017-present, eumis (Eugen Misievich)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file injectool-3.0.0.tar.gz
.
File metadata
- Download URL: injectool-3.0.0.tar.gz
- Upload date:
- Size: 6.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.9.16
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | b84c327f2fed7b2857309e9157344e70e8c73e1a95dba6be024f34c1e5f00a6d |
|
MD5 | 4a0dfc37897f94ba51b17dda0182f0d2 |
|
BLAKE2b-256 | 32a9a29716f2427ddf43ef3d72503c7b8aa436b24941565f64d2f1697f448886 |
File details
Details for the file injectool-3.0.0-py3-none-any.whl
.
File metadata
- Download URL: injectool-3.0.0-py3-none-any.whl
- Upload date:
- Size: 7.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.9.16
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0ab39621e00156cea1231b8b24e6de1d777df40223c47db88a581cff086b4181 |
|
MD5 | a522540f1f999ca40147ad2dad5d8931 |
|
BLAKE2b-256 | 8b58b82a375d5d1013a782f57efcd5fe7254431bd5d002814984de7224144103 |