Welcome to HinteDI’s documentation!

HinteDI - a package for basic and easy dependency injection

copyright:
  1. 2022-present Eetu Asikainen

license:

MIT

The HinteDI class

class hintedi.hinted_dependency_injector.HinteDI

The dependency injector class.

This class is meant to be used through the class method decorators HinteDI.singleton, HinteDI.instance and HinteDI.inject for normal dependency injection and the class method decorators HinteDI.abstract_base, HinteDI.singleton_implementation and HinteDI.instance_implementation for factory-type abstract base class based injection.

This is provided as a class instead of as a collection of methods to enable subclassing. By subclassing this class you can have multiple independent injector implementations in your program. The class also exposes the dependencies dict that stores all registered dependencies. This can be manipulated for example for testing purposes. For instance dependencies, the dependency type is mapped into an InstanceSentinel instance, for uninitialized singletons into None, for initialized singletons, the singleton instance and for Abstract base classes, a dict storing the key-implementation mappings. In the key-implementation mapping the default implementation is stored with a special key HinteDI.default_implementation.

Variables:
  • dependencies – A dict mapping dependency types into the dependency.

  • default_implementation – A sentinel object marking default implementations for abstract dependencies

classmethod abstract_base(dependency_class: type) type

A class method meant to be used as a class decorator to mark the class as an abstract dependency.

Use class decorators HinteDI.singleton_implementation and HinteDI.instance_implementation to register key-based implementations for the class.

Usage:

@HinteDI.abstract_base
class AbstractDependency:
    ...
Parameters:

dependency_class (type) – The class to be decorated

classmethod inject(func: Callable)

A class method meant to be used as a function decorator to mark the method as requiring injection. Only positional or positional + keyword arguments will be injected, keyword-only arguments will not be injected. Arguments already provided including default values will be ignored, as will all arguments named self or cls.

Usage in an instance method:

class DependentClass:

    @HinteDI.inject
    def __init__(self, dependency: Dependency)  # self is ignored automatically
        ...

Usage in a class method:

class DependentClass:

    @classmethod  # Ensure the classmethod decorator comes first
    @HinteDI.inject
    def perform_class_method(cls, dependency: Dependency)  # cls is ignored automatically
        ...

Usage in a function:

@HinteDI.inject
def perform_function(dependency: Dependency)
    ...

If HinteDI is asked to inject an abstract dependency it will return either an HinteDI.ImplementationFactory if the dependency has no default implementation, or the default implementation if the dependency has one. If a default implementation is returned, HinteDI will add the ‘’resolve_from_key’’ method to the object enabling you to resolve it to another implementation if needed.

Usage with an abstract dependency with no default implementation:

@HinteDI.inject
def perform_function(dependency: AbstractDependency):
    concrete_dependency = dependency.resolve_from_key("key")
    ...

Usage with an abstract dependency with a default implementation:

@HinteDI.inject
def perform_function(dependency: AbstractDependency):
    # You can use the returned dependency right away...
    dependency.do_stuff()

    # ...Or you can resolve it into a dependency of another type
    resolved_dependency = dependency.resolve_from_key("key")
Parameters:

func (Callable) – The function requiring dependency injection

classmethod instance(dependency_class: type) type

A class method meant to be used as a class decorator to mark the class as an instance dependency (create a new instance for all injections).

Usage:

@HinteDI.instance
class InstanceDependency:
    ...
Parameters:

dependency_class (type) – The class to be decorated

classmethod instance_implementation(*, base: type, key: str, is_default: bool = False) Callable[[type], type]

A class method meant to be used as a class decorator to mark the class as a concrete instance-based implementation of an abstract dependency.

See HinteDI.abstract_base for registering the abstract base class

Usage:

# Create the abstract dependency first
@HinteDI.abstract_base
class AbstractDependency:
    ...

# Note that actually inheriting the abstract base is not required for HinteDI to work
# The key can be any hashable value, but most use cases should probably use enums or strings
@HinteDI.instance_implementation(base = AbstractDependency, key = "concrete")
class ConcreteDependency(AbstractDependency):
    ...

The abstract class injection pattern in HinteDI will return a HinteDI.ImplementationFactory instance that has the HinteDI.ImplementationFactory.resolve_from_key method that can be used to resolve the concrete instance based on a given key. You can also specify a default implementation with the optional ‘’is_default’’ argument for the implementation decorators. If a default implementation is present, HinteDI will inject the default implementation when asked to inject the abstract base class and add the ‘’FromKey’’ method to the returned object enabling you to resolve the dependency to some other implementation if needed.

Creating a default implementation:

# Even though the key here is 'default', any key works for this
@HinteDI.instance_implementation(base = AbstractDependency, key = "default", is_default = True)
class DefaultImplementation(AbstractDependency):
    ...
Parameters:
  • base (type) – The abstract base class the created concrete class will implement

  • key (Hashable) – The key that can be used to resolve the abstract base class into the created implementation

  • is_default (bool) – An optional flag that marks the implementation as the default implementation, default=False

classmethod singleton(dependency_class: type) type

A class method meant to be used as a class decorator to mark the class as a singleton dependency (reuse the same instance for all injections).

Usage:

@HinteDI.singleton
class SingletonDependency:
    ...
Parameters:

dependency_class (type) – The class to be decorated

classmethod singleton_implementation(*, base: type, key: Hashable, is_default: bool = False) Callable[[type], type]

A class method meant to be used as a class decorator to mark the class as a concrete singleton-based implementation of an abstract dependency.

See HinteDI.abstract_base for registering the abstract base class and HinteDI.singleton for a more thorough explanation of the singleton patter in HinteDI

Usage:

# Create the abstract dependency first
@HinteDI.abstract_base
class AbstractDependency:
    ...

# Note that actually inheriting the abstract base is not required for HinteDI to work
# The key can be any hashable value, but most use cases should probably use enums or strings
@HinteDI.singleton_implementation(base = AbstractDependency, key = "concrete")
class ConcreteDependency(AbstractDependency):
    ...

The abstract class injection pattern in HinteDI will return a HinteDI.ImplementationFactory instance that has the HinteDI.ImplementationFactory.resolve_from_key method that can be used to resolve the concrete instance based on a given key. You can also specify a default implementation with the optional ‘’is_default’’ argument for the implementation decorators. If a default implementation is present, HinteDI will inject the default implementation when asked to inject the abstract base class and add the ‘’FromKey’’ method to the returned object enabling you to resolve the dependency to some other implementation if needed.

Creating a default implementation:

# Even though the key here is 'default', any key works for this
@HinteDI.singleton_implementation(base = AbstractDependency, key = "default", is_default = True)
class DefaultImplementation(AbstractDependency):
    ...
Parameters:
  • base (type) – The abstract base class the created concrete class will implement

  • key (Hashable) – The key that can be used to resolve the abstract base class into the created implementation

  • is_default (bool) – An optional flag that marks the implementation as the default implementation, default=False

The instance factory class

class hintedi.hinted_dependency_injector.ImplementationFactory(resolver: Callable[[Hashable], Any], base: type)

A class returned when resolving an abstract base class with no default implementations. Contains the ‘’ImplementationFactory.resolve_from_key’’ -method for resolving a concrete implementation from a given key.

resolve_from_key(key: Hashable) Any

A method for resolving a concrete implementation for the abstract base class an implementation factory represents.

Parameters:

key (Hashable) – The key used for resolving the implementation

Exception thrown by the package

class hintedi.hinted_dependency_injector.InjectionException(message: str)

An exception thrown by dependency injector.

This is exposed to enable catching it explicitly if needed. It is not advisable to use this class to construct your own exceptions.

Parameters:

message (str) – The error message

Sentinel classes

class hintedi.hinted_dependency_injector.InstanceSentinel

A sentinel class used for differentiating instance dependencies from singleton dependencies in dependency dict.

This is exposed to enable typechecking against this class.

class hintedi.hinted_dependency_injector.DefaultImplementationSentinel

A sentinel class used for identifying default implementations in dependency dict.

This is exposed to enable typechecking against this class.