Skip to content

Wireme

Tiny, typed dependency injection for Python.

Powered by FastDepends. Explicit, opinionated, and small enough to learn in an afternoon: four names cover the whole core.


Declare how a dependency is created once, then let every function, method, constructor, or FastAPI endpoint receive it automatically. Injected parameters disappear from public signatures, stay fully typed, and swap cleanly in tests.

from typing import Annotated

from wireme import Wired, wire, wired


class Database:
    def write(self, value: str) -> None: ...


def get_database() -> Database:
    return Database()


type DatabaseDep = Annotated[Database, wired(get_database)]


@wire
def create_user(username: str, *, database: DatabaseDep = Wired()) -> None:
    database.write(username)


create_user("mo")  # database is resolved automatically

Install

uv add wireme              # framework-independent core
uv add 'wireme[fastapi]'   # + the FastAPI integration
pip install wireme
pip install 'wireme[fastapi]'

Wireme requires Python 3.12 or newer.

New here? Start with Getting started, skim The Wireme way for the house style, or jump into the recipes.

Highlights

  • Four names. wire, wired, Wired, override_dependency cover the core; the optional FastAPI integration adds FromWeb and override_web_dependency. Nothing else to memorize.
  • Typed end to end. PEP 695 type aliases carry the dependency and the static type together; BasedPyright strict passes on every example.
  • Hidden wiring. Injected parameters vanish from runtime signatures, so editors, help(), and OpenAPI schemas see only real inputs.
  • Validation for free. Any pydantic annotation constrains a parameter, no BaseModel or TypeAdapter needed for one value.
  • Real lifecycles. Generator factories open and close resources around the call, or around the whole request under FastAPI, including streaming.
  • Test-first overrides. Nested-safe, exception-safe factory replacement for the core and for FastAPI apps.

Ownership, split deliberately

FastAPI owns the request-facing dependency lifecycle. Wireme owns the internal dependency graph behind your constructors and factories. FromWeb bridges the two without either side losing its semantics:

from fastapi import FastAPI

from wireme.fastapi import FromWeb


app = FastAPI()


@app.post("/users/{username}")
def create_user(username: str, database: FromWeb[DatabaseDep]) -> None:
    database.write(username)

Every capability has a small runnable example in the example index, and every design decision has an architecture decision record.