Skip to main content

A dependency injection container for Python, using semantics similar to Castle Windsor.

Project description

Dependency Injection Container

Full featured, flexible and fluent IoC solution for Python

PyPi

di_container can be installed from PyPi.

The Code

Basics:

Types, callables and values can be registered into a container and bound to either a dependency type, or a name. Registration is independent of dependency order: A dependency can be registered after the dependent type, as long as they are both registered before resolving.

from di_container.container import Container

container = Container(name='container')

container.register_callable(main).to_name('main_func')
container.register_value(app_config['logging']['log_path']).to_name('log_path')
container.register_type(FileLogger).to_type(ILogger)
Multiplicity:

Types and callables can be registered as Instantiation.Singleton (default), or as Instantiation.MultiInstance.

from di_container.container import Container, Instantiation

container = Container(name='container')

container.register_callable(ConnectionFactory.new_udp_connection, instantiation=Instantiation.MultiInstance).to_type(IConnection)
Type checks:

Registering to_type type checks against the given dependency type. When registering to_name, an optional type can be given, in order to make the same check. If the check fails, a TypeError is raised.

from di_container.container import Container

container = Container(name='container')

container.register_value(app_config['network']['http_port']).to_name('port', int)
Manual assignment:

Type initializers and callables can have some, or all, of their arguments assigned values explicitly. The rest will be resolved at resolve time.

from di_container.container import Container, Instantiation

container = Container(name='container')

container.register_callable(ConnectionFactory.new_udp_connection, instantiation=Instantiation.MultiInstance).to_type(IConnection).with_params(host='localhost', port=12345)
Resolving order:

Resolving a registered type, or name, will attempt to resolve any needed arguments for type initializers, or callables, recursively. First, with values given in with_params, second, with declared default values, and then, with arguments' type annotations (please use them ).

When a dependency is registered to_name, it cannot be automatically inferred by type annotation. A container's default behavior is to use an argument's name to lookup a to_name registration as a last attempt to resolve an argument. This behavior can be changed if it's deemed to be too risky, and dependency names can be assigned explicitly when needed.

from di_container.container import Container, Instantiation

container = Container(name='container', param_names_as_bindings=False)

container.register_callable(ConnectionFactory.new_udp_connection, instantiation=Instantiation.MultiInstance).to_type(IConnection).with_name_bindings(host='host_ip', port='port')
container.register_value(app_config['network']['ip']).to_name('host_ip', str)
container.register_value(app_config['network']['http_port']).to_name('port', int)
Sub-containers:

Sub-containers can help when writing several packages, or sub-systems, or just to organize a large amount of dependencies. The resolving process will try to resolve from the current container and if no match is found, will try to resolve using each sub-container (and its sub-containers recursively) in the order they were added. Containers are initialized with names for identification in error messages.

from di_container.container import Container

base_container = Container(name='base')
# register config values and core classes
base_container.register_value(app_config['logging']['log_path']).to_name('log_path')
base_container.register_value(app_config['database']['database_url']).to_name('database_url', str)
base_container.register_type(FileLogger).to_type(ILogger)
base_container.register_type(NoSqlDatabase).to_type(IDatabase)

main_container = Container('main')
# register main class and entry point
main_container.register_callable(main).to_name('main_function').with_name_bindings(main_manager='main_class')
main_container.register_type(MainManager).to_name('main_class').with_name_bindings(internal_comm='int_comm', external_comm='ext_comm')

comm_container = Container('comm')
# register communication classes
comm_container.register_type(UdpCommunicator).to_name('int_comm', ICommunicator)
comm_container.register_type(HttpCommunicator).to_name('ext_comm', ICommunicator)

# setting sub containers
comm_container.add_sub_container(base_container)
main_container.add_sub_container(base_container)
main_container.add_sub_container(comm_container)

# activating the main function
main_container.resolve_name('main_function')

To Do

Some features that are being considered:

  1. Configuration registration.
  2. Binding to members of registered items.
  3. Registration of collections of values.
  4. Display of dependency tree (forest).

More

  • An example is available in the git repository.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

di_container-2.1.8.tar.gz (11.1 kB view details)

Uploaded Source

Built Distribution

di_container-2.1.8-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

File details

Details for the file di_container-2.1.8.tar.gz.

File metadata

  • Download URL: di_container-2.1.8.tar.gz
  • Upload date:
  • Size: 11.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/49.3.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.7.3

File hashes

Hashes for di_container-2.1.8.tar.gz
Algorithm Hash digest
SHA256 73fa8c7dc34595f9cbe300a0d9d0ce6bad830c493f1b57b7a9bdb631b82237cd
MD5 12c7b7ab2ca5cfc5abe12ebcc79833f0
BLAKE2b-256 5e1371de1fc1bfebba6c47e10549f0b7050278567abe9c71e8717208d4c98322

See more details on using hashes here.

File details

Details for the file di_container-2.1.8-py3-none-any.whl.

File metadata

  • Download URL: di_container-2.1.8-py3-none-any.whl
  • Upload date:
  • Size: 10.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/49.3.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.7.3

File hashes

Hashes for di_container-2.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 5b7f9cafa53d980a9d93126fed32d0962f7f0dbc03ce11720d88fed8410c9f85
MD5 96d18da9ec65d566fd53a76b2b5f1ca9
BLAKE2b-256 712b45f534affd7a6f9849cc04b8d9b202f1c2240a5a85ae40a24f2cd0333cf4

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page