Lightweight, container-agnostic dependency injection for Python — typed, explicit, composable.
Project description
typewirepy
Lightweight, container-agnostic dependency injection for Python — typed, explicit, composable.
Features
- Zero runtime dependencies — only stdlib
- Fully typed — strict mypy + pyright out of the box
- Async-first — native
async/await; sync wrappers included - Immutable wires — safe to share across threads and modules
- Scopes — singleton (default) and transient
- Generator lifecycle —
yield-based creators with automatic cleanup - FastAPI integration —
WireDepends()bridges wires to FastAPI'sDepends()
Installation
pip install typewirepy
With FastAPI support:
pip install typewirepy[fastapi]
Quick Start
Async (primary)
from typewirepy import Scope, TypeWireContainer, type_wire_group_of, type_wire_of
config_wire = type_wire_of(token="Config", creator=lambda: {"db_url": "sqlite://"})
db_wire = type_wire_of(
token="Database",
imports={"config": config_wire},
create_with=lambda *, config: f"db({config['db_url']})",
)
app_wires = type_wire_group_of([config_wire, db_wire])
async def main():
async with TypeWireContainer() as container:
await app_wires.apply(container)
db = await db_wire.get_instance(container)
print(db) # "db(sqlite://)"
Sync
from typewirepy import TypeWireContainer, type_wire_of
wire = type_wire_of(token="Greeting", creator=lambda: "hello")
with TypeWireContainer.sync() as container:
wire.apply_sync(container)
print(wire.get_instance_sync(container)) # "hello"
Key Concepts
Wires
A wire is an immutable description of a dependency — its token (name), how to create it, and what it depends on. Create wires with type_wire_of():
- Simple wire — uses
creator(zero-arg callable, no dependencies) - Composed wire — uses
create_with+importsto receive resolved dependencies
Imports
Imports declare which other wires a composed wire depends on. They're passed as a dict[str, TypeWire] and delivered to create_with as keyword arguments:
# Keyword-only parameters (works with lambdas too)
svc_wire = type_wire_of(token="Svc", imports={"db": db_wire}, create_with=lambda *, db: Service(db))
# Named function
def create_svc(*, db: Database) -> Service: ...
svc_wire = type_wire_of(token="Svc", imports={"db": db_wire}, create_with=create_svc)
Scopes
Scope.SINGLETON(default) — resolved once, cached for the container's lifetimeScope.TRANSIENT— resolved fresh on every call
Groups
A TypeWireGroup bundles wires together for batch application:
group = type_wire_group_of([config_wire, db_wire, service_wire])
await group.apply(container)
# Read-only access to the group's wires
group.wires # [TypeWire(...), TypeWire(...), ...]
# Resolve all wires concurrently
instances = await group.get_all_instances(container)
Override wires for testing with with_extra_wires():
test_group = group.with_extra_wires([service_wire.with_creator(lambda _ctx: mock_svc)])
Combine multiple groups into one with combine_wire_groups():
from typewirepy import combine_wire_groups
infra = type_wire_group_of([config_wire, db_wire])
domain = type_wire_group_of([service_wire])
all_wires = combine_wire_groups([infra, domain])
Use the 2-arg form of with_creator to spy on or decorate the original creator:
async def spy(ctx, original_creator):
instance = await original_creator() # zero-arg closure
instance.log = MagicMock(wraps=instance.log)
return instance
test_group = group.with_extra_wires([service_wire.with_creator(spy)])
Introspection
Every wire exposes read-only properties for inspecting the dependency graph at runtime:
wire = type_wire_of(
token="UserService",
imports={"db": db_wire},
create_with=lambda *, db: UserService(db),
scope=Scope.TRANSIENT,
)
wire.token # WireToken('UserService')
wire.token_label # "UserService"
wire.scope # Scope.TRANSIENT
wire.imports # {"db": TypeWire(...)} (shallow copy — safe to mutate)
Use these to build dependency graphs, generate documentation, or debug resolution order.
Best Practices
For conventions on wire visibility, creator patterns, and file organization, see Best Practices.
FastAPI Integration
from contextlib import asynccontextmanager
from fastapi import FastAPI
from typewirepy import TypeWireContainer, type_wire_group_of, type_wire_of
from typewirepy.integrations.fastapi import WireDepends
db_wire = type_wire_of(token="DB", creator=lambda: "db_connection")
app_wires = type_wire_group_of([db_wire])
@asynccontextmanager
async def lifespan(app: FastAPI):
async with TypeWireContainer() as container:
await app_wires.apply(container)
app.state.typewire_container = container
yield
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def root(db: str = WireDepends(db_wire)):
return {"db": db}
Contributing
See CONTRIBUTING.md.
License
MIT
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file typewirepy-0.1.6.tar.gz.
File metadata
- Download URL: typewirepy-0.1.6.tar.gz
- Upload date:
- Size: 71.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4cf5238a4c4241205cccaeefa3dc6f0c8f2f566be26865a7e36e30dbacd26d3a
|
|
| MD5 |
dca5526095c38dc30971cdba5bd611fb
|
|
| BLAKE2b-256 |
9d0e2d571713f4b1222a7d539e2e4976561d24d038ece798bdb82bb6daa65d3a
|
File details
Details for the file typewirepy-0.1.6-py3-none-any.whl.
File metadata
- Download URL: typewirepy-0.1.6-py3-none-any.whl
- Upload date:
- Size: 14.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63630cca533775468f6fef6fb140b2a4415b415f59219860b4586950462d8a07
|
|
| MD5 |
1ae28a8376ffacb0ad15665c2f2d4946
|
|
| BLAKE2b-256 |
56ca65fe9e519c3062c60765e7ab12f6a16202dfcabcf865229559c0322401fb
|