Skip to main content

Simple yet powerful typed dependency injection container

Project description

typedi

Build PyPI version Coverage Status

Simple yet powerful typed dependency injection container.

To install from python package index simply type (no dependencies):

pip install typedi

Or if you don't want to bring a dependency inside your project simply copy and paste typedi.py file (and dont forget the tests).

Usage

Common usage scenario

config.py

from dataclasses import dataclass

@dataclass
class DatabaseConfig:
    host: str
    username: str
    password: str

@dataclass
class AppConfig:
    debug: bool = False 

app.py

from config import DatabaseConfig, AppConfig

class Application:
    def __init__(self, app_conf: AppConfig, db_config: DatabaseConfig):
        pass

    def run(self):
        pass

main.py

from typedi import Container

from config import DatabaseConfig, AppConfig
from app import Application

def load_db_config_from_file() -> DatabaseConfig:
    # Load config from file... and intantiate a config object
    return DatabaseConfig(host='localhost', username='user', password='pass')

if __name__ == '__main__':
    container = Container()
    container.register_singleton_factory(load_db_config_from_file)
    container.register_singleton_class(AppConfig)
    container.register_class(Application)

    # When accessing the instance typedi will automatically resolve all required dependencies
    # provided in __init__ annotations
    application_with_initialized_configs = container.get_instance(Application)
    application_with_initialized_configs.run()

Containers

You can create your own container DI container that will store instances/factories you provide:

from typedi import Container

container = Container()

typedi does not come with a shared container since not to encourage the use of global state. In fact, you should take care of sharing container across modules if you want to implement service-locator pattern.

Instance bindings, "user-managed singletons"

Containers could act as a simple key-value storage for instances where the key is actually a type of that instance, you register an instance first, then ask for a type to get the instance.

from typedi import Container

class MyClass:
    pass

instance = MyClass()
container = Container()
container.register_instance(instance)
instance2 = container.get_instance(MyClass)

Class bindings

Note that instead of registering an actual instance you could register a class acting as a factory of instances. Then when an instance is requested, a class would be instantiated (with all init args resolved) and returned.

from typedi import Container

class MyClass:
    pass

container = Container()
container.register_class(MyClass)
instance = container.get_instance(MyClass)

Class bindings with inheritance

The main strength of DI containers is ability to decouple dependencies by sharing common interface while user of an object does not care about actual implementation.

from typedi import Container

class SomeBaseClass:
    pass

class MyClass(SomeBaseClass):
    pass

container = Container()

# here we register MyClass as a class binding
# It is factory of both MyClass objects and SomeBaseClass objects (using MRO)
container.register_class(MyClass)

# Note that we ask for a base class but container will actually instantiate a MyClass object
# since container knows the base classes of MyClass
instance = container.get_instance(SomeBaseClass)  # type: MyClass

Features

typedi also has support of various features:

  • Factory functions
  • Singletons support, both for classes and factory functions
  • Optionals support - ability to implement "try resolve or return None if no dependency" behavior
  • Instantiation kwargs - ability to override default kwargs or resolution of kwargs
  • Container nesting
  • Configurable container storage

If you want to learn more, please refer to typedi_tests and actual implementation since it is quite self-describing :)

Testing

We are using tox (and pytest) to test among multiple python versions. To run test suites and generate coverage reports simply execute

tox

If you don't have tox installed, execute pip install tox first.

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

typedi-0.5.0.tar.gz (5.0 kB view details)

Uploaded Source

Built Distribution

typedi-0.5.0-py3-none-any.whl (5.7 kB view details)

Uploaded Python 3

File details

Details for the file typedi-0.5.0.tar.gz.

File metadata

  • Download URL: typedi-0.5.0.tar.gz
  • Upload date:
  • Size: 5.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.7.8

File hashes

Hashes for typedi-0.5.0.tar.gz
Algorithm Hash digest
SHA256 498dbb7b2428d9d1b8c11d96493e240d16d9a5331fb9185c722f6b65e1b01c0d
MD5 bfbb3e83afbb2695013f5455d20cd254
BLAKE2b-256 3bb53eb991a9cc403b82c66773eb3351ec93b17b2548d3e0b201ecaa6f436c84

See more details on using hashes here.

File details

Details for the file typedi-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: typedi-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 5.7 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/47.1.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.7.8

File hashes

Hashes for typedi-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4412f01c4fbb1079c93af3631d195f10f7e4a57195d2870a1e5dd3fe7085896c
MD5 99b94b59827f73c22368a4f734e46fc2
BLAKE2b-256 6a08f860a5bbe80865723eb1c1fd44f0a1059a9847a0739f20d8065f77332850

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