Skip to content

Function Injection

The @inject_from_container decorator injects dependencies directly into function parameters. Use this when building your own integration or using Wireup in a framework without built-in support.

Basic Usage

Decorate any function and annotate the parameters you want injected:

from typing import Annotated
from wireup import Inject, Injected, inject_from_container


@inject_from_container(container)
def process_order(
    order_service: Injected[OrderService],
    db_url: Annotated[str, Inject(config="database_url")],
) -> None:
    order_service.process()

The decorator:

  1. Creates a new scope before the function runs
  2. Injects all annotated parameters from that scope
  3. Closes the scope when the function returns (triggering cleanup)

Async Functions

The decorator works with async functions. The container must be created using wireup.create_async_container.

@inject_from_container(container)
async def process_data(service: Injected[DataService]):
    await service.process()

Annotations Required

Only parameters annotated with Injected[T] or Annotated[T, Inject(...)] are injected. Unannotated parameters are left alone for the caller to provide.

Advanced Usage

Using an Existing Scope

If a scope already exists (e.g., created by middleware), pass a callable that returns it as the second argument. The decorator will use that scope instead of creating a new one.

from contextvars import ContextVar
from wireup import ScopedSyncContainer, inject_from_container

scoped_container: ContextVar[ScopedSyncContainer] = ContextVar(
    "scoped_container"
)


@inject_from_container(container, scoped_container.get)
def handle_request(service: Injected[RequestService]) -> None: ...

Creating a Decorator Alias

For cleaner code, create an alias:

inject = inject_from_container(container, scoped_container.get)


@inject
def handle_request(service: Injected[RequestService]) -> None: ...

Framework Integrations

If you're using FastAPI, Flask, Django, or another supported framework, the integration handles this for you. See Integrations.

API Reference

wireup.inject_from_container

Inject dependencies into the decorated function based on annotations. Wireup containers will attempt to provide only parameters annotated with Inject.

See the documentation for more details: https://maldoinc.github.io/wireup/latest/function_injection/

Parameters:

Name Type Description Default
container SyncContainer | AsyncContainer

The root container created via wireup.create_sync_container or wireup.create_async_container.

required
scoped_container_supplier Callable[[], ScopedSyncContainer | ScopedAsyncContainer] | None

An optional callable that returns the current scoped container instance. If provided, it will be used to create scoped dependencies. If not provided, the container will automatically enter a scope. Provide a scoped_container_supplier if you need to manage the container's scope manually.

None
middleware Callable[[ScopedSyncContainer | ScopedAsyncContainer, tuple[Any, ...], dict[str, Any]], AbstractContextManager[None]] | None

A context manager that wraps the execution of the target function.

None
hide_annotated_names bool

If True, the parameters annotated with Wireup annotations will be removed from the signature of the decorated function.

False