Skip to content

Injectipy

A Python dependency injection library using explicit scopes instead of global state. Provides type-safe dependency resolution with circular dependency detection.

PyPI version Python Version License Tests

Features

  • Explicit scopes: Dependencies managed within context managers, no global state
  • Async/await support: Full support for async/await with proper context isolation
  • Type safety: Works with mypy for static type checking
  • Circular dependency detection: Detects dependency cycles at registration time
  • Thread safety: Each scope is isolated, safe for concurrent use
  • Context isolation: Thread and async task isolation using contextvars
  • Lazy evaluation: Dependencies resolved only when accessed
  • Test isolation: Each test can use its own scope

Quick Example

from injectipy import inject, Inject, DependencyScope

# Create a dependency scope
scope = DependencyScope()

# Register dependencies
scope.register_value("config", {"database_url": "sqlite:///app.db"})
scope.register_resolver("database", lambda: Database())

# Use dependency injection
@inject
def create_user(name: str, config: dict = Inject["config"], db: Database = Inject["database"]):
    return User.create(name, config["database_url"], db)

# Use within scope context for automatic injection
with scope:
    user = create_user("Alice")

Key Characteristics

  • No global state: Each scope manages its own dependencies
  • Context managers: Use with scope: to activate dependency injection
  • Type checking: Works with mypy for compile-time validation
  • Thread isolation: Multiple threads can use separate or shared scopes safely

Installation

pip install injectipy

Or with Poetry:

poetry add injectipy

Documentation

Basic Usage

Function Injection

from injectipy import inject, Inject, DependencyScope

scope = DependencyScope()
scope.register_value("config", {"debug": True})

@inject
def my_function(config: dict = Inject["config"]):
    return config["debug"]

with scope:
    result = my_function()  # Returns True

Factory Functions

def create_database(host=Inject["db_host"], port=Inject["db_port"]):
    return Database(host, port)

scope = DependencyScope()
scope.register_value("db_host", "localhost")
scope.register_value("db_port", 5432)
scope.register_resolver("database", create_database)

with scope:
    db = scope["database"]  # Factory called with injected dependencies

Async/Await Support

import asyncio
from injectipy import inject, Inject, DependencyScope

scope = DependencyScope()
scope.register_value("api_key", "secret-key")

@inject
async def fetch_data(endpoint: str, api_key: str = Inject["api_key"]) -> dict:
    # Simulate async API call
    await asyncio.sleep(0.1)
    return {"endpoint": endpoint, "authenticated": bool(api_key)}

async def main():
    async with scope:  # Use async context manager
        data = await fetch_data("/users")
        print(data)

asyncio.run(main())

Use Cases

  • Web Applications: Inject database connections, configuration, services
  • CLI Tools: Manage application configuration and resources
  • Testing: Easy mocking and test isolation
  • Microservices: Clean dependency management across services
  • Data Processing: Inject processors, validators, and transformers

License

MIT License - see LICENSE for details.