Skip to main content

Python Dependency Injection Library

Project description

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+.

📚 Documentation | 🎮 Demo Application


⚡ Key Features

  • Inject services and configuration.
  • Interfaces and abstract classes.
  • Factory pattern.
  • Singleton and transient dependencies.
  • Framework-agnostic.
  • Apply the container as a decorator.
  • Service Locator.
  • Simplified use with Django, Flask, and FastAPI.
  • Share service layer between cli and api.

📋 Quickstart

1. Set up

import wireup

container = wireup.create_container(
    # Parameters serve as application/service configuration.
    parameters={
        "redis_url": os.environ["APP_REDIS_URL"],
        "weather_api_key": os.environ["APP_WEATHER_API_KEY"]
    },
    # Top-level modules containing service registrations.
    service_modules=[services]
)

2. Declare 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:
    # 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 # Can be used alongside dataclasses to simplify init boilerplate.
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.

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

Use factories (sync and async) if service requires special initialization or cleanup.

@service
async def make_db(dsn: Annotated[str, Inject(param="db_dsn")]) -> AsyncIterator[Connection]:
    async with Connection(dsn) as conn:
        yield conn

Note: If you use generator factories, call container.{close,aclose} on termination for the necessary cleanup to take place.

3. Use

Use the container as a service locator or apply it as a decorator to have it perform injection.

weather_service = container.get(WeatherService)
@app.get("/weather/forecast")
# ⬇️ Decorate functions to perform Dependency Injection.
# No longer required when using the provided integrations.
@container.autowire
def get_weather_forecast_view(weather_service: WeatherService, request):
    return weather_service.get_forecast(request.lat, request.lon)

4. Test

Wireup does not patch your services which means they can be instantiated and tested independently of the container.

To substitute dependencies on autowired targets such as views in a web application you can override dependencies with new ones on the fly.

with container.override.service(WeatherService, new=test_weather_service):
    response = client.get("/weather/forecast")

Requests to inject WeatherService during the lifetime of the context manager will result in test_weather_service being injected instead.

Share service layer betwen app/api and cli

Many projects have a web application as well as a cli in the same project which provides useful commands.

Wireup makes it extremely easy to share the service layer between them without code duplication. For examples refer to maldoinc/wireup-demo.

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wireup-0.13.0.tar.gz (24.7 kB view details)

Uploaded Source

Built Distribution

wireup-0.13.0-py3-none-any.whl (30.4 kB view details)

Uploaded Python 3

File details

Details for the file wireup-0.13.0.tar.gz.

File metadata

  • Download URL: wireup-0.13.0.tar.gz
  • Upload date:
  • Size: 24.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.4 CPython/3.10.12 Linux/6.8.0-48-generic

File hashes

Hashes for wireup-0.13.0.tar.gz
Algorithm Hash digest
SHA256 2d61247039d819a5bfba2d490761344b56fa81ff7d3ee80c4fc53213cb0f9e31
MD5 d7a8a069c6444e929ee38b342ac46814
BLAKE2b-256 1cd07918e9d8d9e0f646117641e0a34006ce9aaa1ee2205308fcd7db13f62629

See more details on using hashes here.

File details

Details for the file wireup-0.13.0-py3-none-any.whl.

File metadata

  • Download URL: wireup-0.13.0-py3-none-any.whl
  • Upload date:
  • Size: 30.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.4 CPython/3.10.12 Linux/6.8.0-48-generic

File hashes

Hashes for wireup-0.13.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5c261dbc089836485b7ebf7ef94366f952832bccecac66d3502dd912ff3cf5ba
MD5 932e97b5e4114c4fd89205c1ac2cef43
BLAKE2b-256 308f2e6e8bc4f0b432b0198042d482275207b83fe17847d908824c6eda2160cb

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page