{"id":42085191,"url":"https://github.com/maksimzayats/diwire","last_synced_at":"2026-02-24T11:15:20.588Z","repository":{"id":334555848,"uuid":"1141834163","full_name":"maksimzayats/diwire","owner":"maksimzayats","description":"🔌 Type-safe dependency injection for Python with auto-wiring, scopes, async factories, and zero deps","archived":false,"fork":false,"pushed_at":"2026-01-30T15:34:55.000Z","size":435,"stargazers_count":18,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-31T00:43:17.034Z","etag":null,"topics":["asyncio","dependency-injection","di","ioc","python","type-hints"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/diwire/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maksimzayats.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-25T14:11:23.000Z","updated_at":"2026-01-30T17:50:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/maksimzayats/diwire","commit_stats":null,"previous_names":["maksimzayats/diwire"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/maksimzayats/diwire","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maksimzayats%2Fdiwire","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maksimzayats%2Fdiwire/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maksimzayats%2Fdiwire/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maksimzayats%2Fdiwire/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maksimzayats","download_url":"https://codeload.github.com/maksimzayats/diwire/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maksimzayats%2Fdiwire/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28939485,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T10:18:23.202Z","status":"ssl_error","status_checked_at":"2026-01-31T10:18:22.693Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","dependency-injection","di","ioc","python","type-hints"],"created_at":"2026-01-26T10:16:35.673Z","updated_at":"2026-02-20T07:01:37.503Z","avatar_url":"https://github.com/maksimzayats.png","language":"Python","funding_links":[],"categories":["Software"],"sub_categories":["DI Frameworks / Containers"],"readme":"# diwire\n\n**Type-driven dependency injection for Python. Zero dependencies. Zero boilerplate.**\n\n[![PyPI version](https://img.shields.io/pypi/v/diwire.svg)](https://pypi.org/project/diwire/)\n[![Python versions](https://img.shields.io/pypi/pyversions/diwire.svg)](https://pypi.org/project/diwire/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![codecov](https://codecov.io/gh/MaksimZayats/diwire/graph/badge.svg)](https://codecov.io/gh/MaksimZayats/diwire)\n[![Docs](https://img.shields.io/badge/docs-diwire.dev-blue)](https://docs.diwire.dev)\n\ndiwire is a dependency injection container for Python 3.10+ that builds your object graph from type hints. It supports\nscopes + deterministic cleanup, async resolution, open generics, fast steady-state resolution via compiled\nresolvers, and free-threaded Python (no-GIL) — all with zero runtime dependencies.\n\n## Why diwire\n\n- **Zero runtime dependencies**: easy to adopt anywhere. ([Why diwire](https://docs.diwire.dev/why-diwire.html))\n- **Scopes + deterministic cleanup**: generator/async-generator providers clean up on scope exit. ([Scopes](https://docs.diwire.dev/core/scopes.html))\n- **Async resolution**: ``aresolve()`` mirrors ``resolve()`` and async providers are first-class. ([Async](https://docs.diwire.dev/core/async.html))\n- **Open generics**: register once, resolve for many type parameters. ([Open generics](https://docs.diwire.dev/core/open-generics.html))\n- **Function injection**: ``Injected[T]`` and ``FromContext[T]`` for ergonomic handlers. ([Function injection](https://docs.diwire.dev/core/function-injection.html))\n- **Named components + collect-all**: ``Component(\"name\")`` and ``All[T]``. ([Components](https://docs.diwire.dev/core/components.html))\n- **Concurrency + free-threaded builds**: configurable locking via ``LockMode``. ([Concurrency](https://docs.diwire.dev/howto/advanced/concurrency.html))\n\n## Performance (benchmarked)\n\nBenchmarks + methodology live in the docs: [Performance](https://docs.diwire.dev/howto/advanced/performance.html).\n\nIn this benchmark suite on CPython ``3.14.3`` (Apple M3 Pro, strict mode):\n\n- Speedup over ``rodi`` ranges from **1.54×** to **6.04×**.\n- Speedup over ``dishka`` ranges from **2.94×** to **30.14×**.\n- Speedup over ``wireup`` ranges from **1.84×** to **4.98×**.\n- Resolve-only comparisons (includes ``punq`` in non-scope scenarios): speedup over ``punq`` ranges from **5.27×** to **595.70×**.\n- Current benchmark totals: **10** full-suite scenarios and **4** resolve-only scenarios.\n\nResults vary by environment, Python version, and hardware. Re-run ``make benchmark-report`` and\n``make benchmark-report-resolve`` on your target runtime before drawing final conclusions for production workloads.\n\n## Installation\n\n```bash\nuv add diwire\n```\n\n```bash\npip install diwire\n```\n\n## Quick start (auto-wiring)\n\nDefine your classes. Resolve the top-level one. diwire figures out the rest.\n\n```python\nfrom dataclasses import dataclass, field\n\nfrom diwire import Container\n\n\n@dataclass\nclass Database:\n    host: str = field(default=\"localhost\", init=False)\n\n\n@dataclass\nclass UserRepository:\n    db: Database\n\n\n@dataclass\nclass UserService:\n    repo: UserRepository\n\ncontainer = Container()\nservice = container.resolve(UserService)\nprint(service.repo.db.host)  # =\u003e localhost\n```\n\n## Registration\n\nUse explicit registrations when you need configuration objects, interfaces/protocols, cleanup, or multiple\nimplementations.\n\n**Strict mode (opt-in):**\n\n```python\nfrom diwire import Container, DependencyRegistrationPolicy, MissingPolicy\n\ncontainer = Container(\n    missing_policy=MissingPolicy.ERROR,\n    dependency_registration_policy=DependencyRegistrationPolicy.IGNORE,\n)\n```\n\n``Container()`` enables recursive auto-wiring by default. Use strict mode when you need full\ncontrol over registration and want missing dependencies to fail fast.\n\n```python\nfrom typing import Protocol\n\nfrom diwire import Container, Lifetime\n\n\nclass Clock(Protocol):\n    def now(self) -\u003e str: ...\n\n\nclass SystemClock:\n    def now(self) -\u003e str:\n        return \"now\"\n\n\ncontainer = Container()\ncontainer.add(\n    SystemClock,\n    provides=Clock,\n    lifetime=Lifetime.SCOPED,\n)\n\nprint(container.resolve(Clock).now())  # =\u003e now\n```\n\nRegister factories directly:\n\n```python\nfrom diwire import Container\n\ncontainer = Container()\n\n\ndef build_answer() -\u003e int:\n    return 42\n\ncontainer.add_factory(build_answer)\n\nprint(container.resolve(int))  # =\u003e 42\n```\n\n## Scopes \u0026 cleanup\n\nUse `Lifetime.SCOPED` for per-request/per-job caching. Use generator/async-generator providers for deterministic\ncleanup on scope exit.\n\n```python\nfrom collections.abc import Generator\n\nfrom diwire import Container, Lifetime, Scope\n\n\nclass Session:\n    def __init__(self) -\u003e None:\n        self.closed = False\n\n    def close(self) -\u003e None:\n        self.closed = True\n\n\ndef session_factory() -\u003e Generator[Session, None, None]:\n    session = Session()\n    try:\n        yield session\n    finally:\n        session.close()\n\n\ncontainer = Container()\ncontainer.add_generator(\n    session_factory,\n    provides=Session,\n    scope=Scope.REQUEST,\n    lifetime=Lifetime.SCOPED,\n)\n\nwith container.enter_scope() as request_scope:\n    session = request_scope.resolve(Session)\n    print(session.closed)  # =\u003e False\n\nprint(session.closed)  # =\u003e True\n```\n\n## Function injection\n\nMark injected parameters as `Injected[T]` and wrap callables with `@resolver_context.inject`.\n\n```python\nfrom diwire import Container, Injected, resolver_context\n\n\nclass Service:\n    def run(self) -\u003e str:\n        return \"ok\"\n\n\ncontainer = Container()\ncontainer.add(Service)\n\n\n@resolver_context.inject\ndef handler(service: Injected[Service]) -\u003e str:\n    return service.run()\n\n\nprint(handler())  # =\u003e ok\n```\n\n## Named components\n\nUse `Annotated[T, Component(\"name\")]` when you need multiple registrations for the same base type.\nFor registration ergonomics, you can also pass `component=\"name\"` to `add_*` methods.\n\n```python\nfrom typing import Annotated, TypeAlias\n\nfrom diwire import All, Component, Container\n\n\nclass Cache:\n    def __init__(self, label: str) -\u003e None:\n        self.label = label\n\n\nPrimaryCache: TypeAlias = Annotated[Cache, Component(\"primary\")]\nFallbackCache: TypeAlias = Annotated[Cache, Component(\"fallback\")]\n\n\ncontainer = Container()\ncontainer.add_instance(Cache(label=\"redis\"), provides=Cache, component=\"primary\")\ncontainer.add_instance(Cache(label=\"memory\"), provides=Cache, component=\"fallback\")\n\nprint(container.resolve(PrimaryCache).label)  # =\u003e redis\nprint(container.resolve(FallbackCache).label)  # =\u003e memory\nprint([cache.label for cache in container.resolve(All[Cache])])  # =\u003e ['redis', 'memory']\n```\n\nResolution/injection keys are still `Annotated[..., Component(...)]` at runtime.\n\n## resolver_context (optional)\n\nIf you can't (or don't want to) pass a resolver everywhere, use `resolver_context`.\nIt is a `contextvars`-based helper used by `@resolver_context.inject` and (by default) by `Container` resolution methods.\nInside `with container.enter_scope(...):`, injected callables resolve from the bound scope resolver; otherwise they fall\nback to the container registered as the `resolver_context` fallback (`Container(..., use_resolver_context=True)` is the\ndefault).\n\n```python\nfrom diwire import Container, FromContext, Scope, resolver_context\n\ncontainer = Container()\n\n\n@resolver_context.inject(scope=Scope.REQUEST)\ndef handler(value: FromContext[int]) -\u003e int:\n    return value\n\n\nwith container.enter_scope(Scope.REQUEST, context={int: 7}):\n    print(handler())  # =\u003e 7\n```\n\n## Stability\n\ndiwire targets a stable, small public API.\n\n- Backward-incompatible changes only happen in major releases.\n- Deprecations are announced first and kept for at least one minor release (when practical).\n\n## Docs\n\n- [Tutorial (runnable examples)](https://docs.diwire.dev/howto/examples/)\n- [Examples (repo)](https://github.com/maksimzayats/diwire/blob/main/examples/README.md)\n- [Core concepts](https://docs.diwire.dev/core/)\n- [API reference](https://docs.diwire.dev/reference/)\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaksimzayats%2Fdiwire","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaksimzayats%2Fdiwire","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaksimzayats%2Fdiwire/lists"}