Python Dependency Injection Library


Keywords
flask, django, injector, dependency, injection, container, dependency-injection, dependency-injection-container, dependency-injector, python
License
MIT
Install
pip install wireup==0.8.0

Documentation

Wireup

Modern Dependency Injection for Python.

GitHub GitHub Workflow Status (with event) Code Climate maintainability Coverage PyPI - Python Version PyPI - Version

Wireup is a performant, concise, and easy-to-use dependency injection container for Python 3.8+.


⚡ Key Features

  • Effortlessly Inject services and configuration.
  • Support for interfaces and abstract classes.
  • Factory pattern.
  • Singleton and transient dependencies.
  • Truly declrative container.
  • Framework-agnostic.
  • Simplified integration with Django, Flask, and FastAPI.

📋 Quickstart

Example showcasing a Redis wrapper and a weather service that calls an external API and caches results as needed.

1. Set up

from wireup import container, initialize_container
def create_app():
    app = ...
    
    # ⬇️ Expose configuration by populating container.params.
    container.params.put("redis_url", os.environ["APP_REDIS_URL"])
    container.params.put("weather_api_key", os.environ["APP_WEATHER_API_KEY"])

    # Bulk update is possible via the "update" method.
    container.params.update(Settings().model_dump())
    
    # Start the container: This registers and initializes services.
    # `service_modules` contains top-level modules containing registrations.
    # ⬇️
    initialize_container(container, service_modules=[services])

    return app

2. Register services

Use a declarative syntax to describe services, and let the container handle the rest.

from wireup import service, Inject

@service # ⬅️ Decorator tells the container this is a service.
class KeyValueStore:
                                           # This tells the container to inject the value
                                           # of the parameter during creation.
                                           # ⬇️ 
    def __init__(self, dsn: Annotated[str, Inject(param="redis_url")]):
        self.client = redis.from_url(dsn)

    def get(self, key: str) -> Any: ...
    def set(self, key: str, value: Any): ...


@service
@dataclass
class WeatherService:
    # Inject the value of the parameter to this field. ⬇️
    api_key: Annotated[str, Inject(param="weather_api_key")]
    kv_store: KeyValueStore # ⬅️ This will be injected automatically without additional metadata.

    def get_forecast(self, lat: float, lon: float) -> WeatherForecast:
        ...

3. Inject

Decorate targets where the library should perform injection.

from wireup import container

@app.get("/weather/forecast")
# ⬇️ Decorating views with autowire enables the container to inject services/parameters.
@container.autowire
def get_weather_forecast_view(weather_service: WeatherService, request):
    return weather_service.get_forecast(request.lat, request.lon)

Installation

# Install using poetry:
poetry add wireup

# Install using pip:
pip install wireup

📑 Documentation

For more information check out the documentation

🎮 Demo application

A demo flask application is available at maldoinc/wireup-demo