Basic usage

Sync

To use FunDI in synchronous mode you need to use inject function and ExitStack class

from fundi import Scope, from_, inject, scan


def require_user() -> str:
    return "user"


def application(user: str = from_(require_user)):
    print(f"Application started with {user = }")


inject(Scope(), scan(application))

Async

To use FunDI with asynchronous code - you need to use ainject function and AsyncExitStack class

import asyncio

from fundi import Scope, from_, ainject, scan


async def require_user() -> str:
    return "user"


async def application(user: str = from_(require_user)):
    print(f"Application started with {user = }")


async def main():
    await ainject(Scope(), scan(application))


if __name__ == "__main__":
    asyncio.run(main())

Mixed

You can mix async and sync dependencies using ainject function

import asyncio

from fundi import Scope, from_, ainject, scan


def require_user() -> str:
    return "user"


async def application(user: str = from_(require_user)):
    print(f"Application started with {user = }")


async def main():
    await ainject(Scope(), scan(application))


if __name__ == "__main__":
    asyncio.run(main())

Positional dependencies

You may want to define dependencies inside a positional parameter. To do so, you need to use typing.Annotated in pair of from_()

from typing import Annotated

from fundi import Scope, from_, inject, scan


def require_int() -> int:
    return 255


def application(value: Annotated[int, from_(require_int)], scope_value: str):
    print(f"Application started with {value = } and {scope_value = !r}")


inject(Scope({"scope_value": "17/03/2026"}), scan(application))