Skip to main content
Join the official 2020 Python Developers SurveyStart the survey!

Botox is a dependency injection implementation based on Python type annotations.

Project description


Botox Injector is a dependency injection implementation based on Python type annotations. It helps deliver the configured functional objects, decreasing coupling between a class and its dependencies.


Global variables? Proxy objects? Application context?

There should be one (and preferably only one) obvious way to do it.

Botox helps you isolate a class from the impact of different design changes and defects. Meaning that, instead of thinking about interdependence between application modules you will now find yourself spending your time having to focus a class on the task it is designed for.


Monkey-patching? Decorators?

Explicit is better than implicit.

Botox allows a class the flexibility of being configurable. The class rely on dependencies interface that he expect. Explicit configurations can be written separately for different situations that require different implementations of dependencies.


Now is better than never.

Botox doesn’t require any change in code behavior it can be applied to legacy code as a refactoring.


Install and update using pip:

pip install -U botox-di


Class Injection

Can be used to reduce boilerplate code in the application classes since all work to initialize or set up dependencies is handled separately.

from botox import Injector

class PaymentService:

class BillingService:

class SalesService:

    def __init__(self, payment_service: PaymentService, billing_service: BillingService):
        self.payment_service = payment_service
        self.billing_service = billing_service

injector = Injector()

sales = injector.deliver(SalesService)

assert isinstance(sales.payment_service, PaymentService)
assert isinstance(sales.billing_service, BillingService)

The result is class that is easier to unit test in isolation using stubs or mock objects that simulate other objects.

injector.prepare(PaymentService, PaymentServiceStub)

Value Injection

Can be used when exactly one object is needed to coordinate actions across the system.

from botox import Injector

class AppSettings:

settings = AppSettings()

injector = Injector()
injector.prepare(AppSettings, settings)

assert injector.deliver(AppSettings) is settings

Lambda Injection

Can be used to wrap Proxy objects in legacy code as refactoring.

from botox import Injector
from flask import g
from sqlalchemy.orm import Session

injector = Injector()
injector.prepare(Session, lambda: g.session)

Function Injection

Can be used to make factory functions with dependencies.

from botox import Injector

def create_api_client(settings: Settings):
    return ApiClient(settings.base_url, settings.key)

injector = Injector()
injector.prepare(ApiClient, create_api_client)

Sequence Injection

Can be used to provide collection of dependencies.

class PaymentService(metaclass=ABCMeta):
    name: str

class GooglePayService(PaymentService):

class ApplePayService(PaymentService):

class FlowService:

    def __init__(self, payment_services: List[PaymentService]):
        self.payment_services = payment_services

    def get_available_payment_methods(self):
        for payment_service in self.payment_services:

injector = Injector()
injector.prepare(List[PaymentService], [GooglePayService, ApplePayService])


You can define a different application base task class to deliver dependencies into a task call.

from celery import Celery, Task
from botox import Injector

class Calculator:
    def add(self, x, y):
        return x + y

class AppTask(Task):
    def __call__(self, *args, **kwargs):
        run =, skip=len(args))
        return run(*args, **kwargs)

app = Celery('tasks', broker='pyamqp://guest@localhost//', task_cls=AppTask)
app.injector = Injector()

def add(x, y, calculator: Calculator):
    return calculator.add(x, y)


You can use a middleware to deliver dependencies into a request handler. Asynchronous functions also supported.

from aiohttp import web
from botox import Injector

class HelloService:
    def get_hello_message(self, name):
        return f'Hello, {name}!'

async def handle(request, service: HelloService):
    name = request.match_info.get('name', 'Anonymous')
    text = service.get_hello_message(name)
    return web.Response(text=text)

async def dependency_injection(request, handler):
    handler =, skip=1)
    return await handler(request)

app = web.Application(middlewares=[dependency_injection])
app.injector = Injector()
    web.get('/', handle),
    web.get('/{name}', handle)


Project details

Download files

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

Files for botox-di, version 1.5.0
Filename, size File type Python version Upload date Hashes
Filename, size botox_di-1.5.0-py3-none-any.whl (6.2 kB) File type Wheel Python version py3 Upload date Hashes View
Filename, size botox-di-1.5.0.tar.gz (5.6 kB) File type Source Python version None Upload date Hashes View

Supported by

Pingdom Pingdom Monitoring Google Google Object Storage and Download Analytics Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page