A pythonic dependency injection library that assembles objects into graphs in an easy, maintainable way
—
Decorators for controlling injection behavior, marking classes as injectable, defining provider methods, and specifying argument annotations for precise dependency resolution.
Controls which arguments are injected and which are passed directly, providing fine-grained control over the dependency injection process.
def inject(arg_names=None, all_except=None):
"""
Decorator that specifies which arguments to inject for a method.
Parameters:
- arg_names: list of argument names to inject; if None, inject all possible args
- all_except: list of argument names NOT to inject; mutually exclusive with arg_names
Returns:
Decorated function with injection specifications
"""Explicitly marks classes as available for dependency injection, required when using only_use_explicit_bindings=True.
def injectable(fn):
"""
Decorator that explicitly marks a class as injectable.
Parameters:
- fn: class to mark as injectable
Returns:
The class with injectable metadata
"""Defines methods that provide instances for dependency injection, typically used within BindingSpec classes.
def provides(arg_name=None, annotated_with=None, in_scope=None):
"""
Decorator that marks a method as a provider for dependency injection.
Parameters:
- arg_name: name of the argument this provider serves; if None, inferred from method name
- annotated_with: annotation object for disambiguation
- in_scope: scope ID for the provided instances
Returns:
Decorated provider method
"""Adds annotations to specific arguments for disambiguation when multiple bindings exist for the same type.
def annotate_arg(arg_name, with_annotation):
"""
Adds an annotation to an injected argument for disambiguation.
Parameters:
- arg_name: name of the argument to annotate
- with_annotation: annotation object for disambiguation
Returns:
Function decorator that applies the annotation
"""import pinject
class DatabaseService(object):
def __init__(self):
self.connected = True
class UserService(object):
@pinject.inject(['database_service'])
def __init__(self, database_service, api_key="default_key"):
self.db = database_service
self.api_key = api_key # api_key has default, not injected
obj_graph = pinject.new_object_graph()
user_service = obj_graph.provide(UserService) # uses default api_keyimport pinject
class LoggingService(object):
def __init__(self):
self.logs = []
class ProcessingService(object):
@pinject.inject(all_except=['batch_size'])
def __init__(self, logging_service, batch_size=100):
self.logger = logging_service
self.batch_size = batch_size
obj_graph = pinject.new_object_graph()
service = obj_graph.provide(ProcessingService, batch_size=50)import pinject
@pinject.injectable
class DatabaseConnection(object):
def __init__(self):
self.url = "sqlite://memory"
@pinject.injectable
class UserRepository(object):
def __init__(self, database_connection):
self.db = database_connection
# Use only explicitly marked classes
obj_graph = pinject.new_object_graph(
classes=[DatabaseConnection, UserRepository],
only_use_explicit_bindings=True
)
repo = obj_graph.provide(UserRepository)import pinject
class DatabaseConfig(object):
def __init__(self, url, timeout):
self.url = url
self.timeout = timeout
class MyBindingSpec(pinject.BindingSpec):
@pinject.provides('database_config')
def provide_db_config(self):
return DatabaseConfig("postgresql://localhost", 30)
@pinject.provides(in_scope=pinject.SINGLETON)
def provide_connection_pool(self, database_config):
return ConnectionPool(database_config.url)
obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()])import pinject
class DatabaseConnection(object):
def __init__(self, host, port):
self.host = host
self.port = port
class CacheConnection(object):
def __init__(self, host, port):
self.host = host
self.port = port
class AppService(object):
@pinject.annotate_arg('database_connection', with_annotation='primary')
@pinject.annotate_arg('cache_connection', with_annotation='redis')
def __init__(self, database_connection, cache_connection):
self.db = database_connection
self.cache = cache_connection
class MyBindingSpec(pinject.BindingSpec):
@pinject.provides('database_connection', annotated_with='primary')
def provide_primary_db(self):
return DatabaseConnection('db.example.com', 5432)
@pinject.provides('cache_connection', annotated_with='redis')
def provide_redis_cache(self):
return CacheConnection('cache.example.com', 6379)
obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()])
app = obj_graph.provide(AppService)Install with Tessl CLI
npx tessl i tessl/pypi-pinject