Skip to main content

injectool

example branch parameter Codacy Badge Codacy Badge image image image Downloads

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

MIT

Copyright (c) 2017-present, eumis (Eugen Misievich)

Metadata

Release files for injectool 3.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for injectool 3.0.0
File Size Uploaded
injectool-3.0.0.tar.gz 6.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for injectool 3.0.0
File Interpreter ABI Platform
injectool-3.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 13.6 kB

Release files / injectool-3.0.0.tar.gz

Download URL injectool-3.0.0.tar.gz
Size 6.3 kB
Tags Source
SHA-256 checksum
How to use checksums
b84c327f2fed7b2857309e9157344e70e8c73e1a95dba6be024f34c1e5f00a6d
BLAKE2b-256 checksum
How to use checksums
32a9a29716f2427ddf43ef3d72503c7b8aa436b24941565f64d2f1697f448886
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.9.16

Release files / injectool-3.0.0-py3-none-any.whl

Download URL injectool-3.0.0-py3-none-any.whl
Size 7.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0ab39621e00156cea1231b8b24e6de1d777df40223c47db88a581cff086b4181
BLAKE2b-256 checksum
How to use checksums
8b58b82a375d5d1013a782f57efcd5fe7254431bd5d002814984de7224144103
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.9.16

Release history Release notifications | RSS feed

This release

3.0.0 This release

2 release files

2.0.4

2 release files

2.0.3

1 release file

2.0.2

1 release file

2.0.1

1 release file

2.0.0

1 release file

1.1.2

1 release file

1.1.1

1 release file

1.1.0

1 release file

1.0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page