Inject
Inject is a lightweight, fast, and thread-safe Python dependency injection framework. It facilitates the creation and management of object dependencies, promoting modular and testable code. The library supports features like automatic parameter injection using type annotations and context managers. It maintains an active development status, with the current version being 5.3.0, and new releases are made periodically.
Warnings
- breaking `inject` v5.0 and later require Python 3.9+. If you are using an older Python version (e.g., 3.5-3.8), you must use `inject` v4.x. For Python 2.7-3.5, use `inject` v3.x.
- deprecated The `inject.param` decorator is deprecated. Use `inject.params` instead for injecting parameters into functions.
- gotcha By default, `inject` attempts to implicitly instantiate a class if a binding is missing (`bind_in_runtime=True`). This can mask missing bindings and lead to hard-to-debug issues if the default constructor is called unintentionally. For stricter control, disable runtime binding.
- gotcha `inject` creates objects as singletons by default. For advanced scope management (e.g., thread-local, request-local instances), you need to implement custom providers rather than relying on built-in scope management features found in some other DI frameworks.
Install
-
pip install inject
Imports
- inject
import inject
- autoparams
from inject import autoparams
- params
from inject import params
- instance
from inject import instance
Quickstart
import inject
# 1. Define services/dependencies
class Cache:
def save(self, key, value):
print(f"Saving to cache: {key} = {value}")
class DbInterface:
def query(self, statement):
print(f"Executing DB query: {statement}")
return [f"result_for_{statement}"]
# 2. Configure bindings (once at application start)
def config(binder):
binder.bind(Cache, Cache())
binder.bind(DbInterface, DbInterface())
inject.configure(config)
# 3. Use dependency injection
# Method 1: Using inject.instance()
cache_instance = inject.instance(Cache)
cache_instance.save('app_init', 'initial_value')
# Method 2: Using @inject.autoparams (requires type hints)
@inject.autoparams
def process_data(data: str, cache: Cache, db: DbInterface):
cache.save('processed', data)
results = db.query(f"SELECT * FROM data WHERE value = '{data}'")
print(f"Processed '{data}', results: {results}")
process_data('example_data')
# Method 3: Using @inject.params (explicitly name dependencies)
@inject.params(cache=Cache, db=DbInterface)
def report_status(message: str, cache=None, db=None):
if cache: cache.save('status', message)
if db: db.query(f"INSERT INTO logs VALUES ('{message}')")
print(f"Status reported: {message}")
report_status('Application running successfully')