CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pinject

A pythonic dependency injection library that assembles objects into graphs in an easy, maintainable way

Pending
Overview
Eval results
Files

decorators.mddocs/

Dependency Injection Decorators

Decorators for controlling injection behavior, marking classes as injectable, defining provider methods, and specifying argument annotations for precise dependency resolution.

Capabilities

Injection Control

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
    """

Injectable Marking

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
    """

Provider Methods

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
    """

Argument Annotation

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
    """

Usage Examples

Basic Injection Control

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_key

Excluding Arguments from Injection

import 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)

Explicit Injectable Classes

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)

Provider Methods in Binding Specs

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()])

Argument Annotations for Disambiguation

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

docs

binding-specs.md

decorators.md

error-handling.md

field-initialization.md

index.md

object-graph.md

scoping.md

tile.json