Skip to main content

mountaineer-di

Common dependency injection utilities for Mountaineer and related projects, with pydantic as the only hard dependency.

This package provides a robust set of defining and injecting function dependencies. It works on its own, and when FastAPI is installed it can also interoperate with fastapi.Depends(...) and request-bound parameters in the same dependency graph.

Installation

Install the package with uv:

uv add mountaineer-di

What It Does

mountaineer-di lets you declare dependencies on normal Python callables and resolve them outside a framework request cycle.

It supports:

  • Native Depends(...) markers
  • Nested dependency graphs
  • Seeded caller-provided kwargs
  • Async and sync dependencies
  • Generator and context-manager dependency lifecycles
  • FastAPI request/query/path/header/cookie/body extraction when FastAPI is installed
  • Runtime dependency overrides
  • Callable-level dependency overrides via @dependency_override(...)

Quick Start

Use Depends(...) to declare dependencies, then call the resolver and invoke the target with the returned kwargs:

from typing import Annotated

from mountaineer_di import Depends, provide_dependencies


def get_prefix() -> str:
    return "hello"


def get_message(prefix: str = Depends(get_prefix)) -> str:
    return f"{prefix} world"


async def handler(message: Annotated[str, Depends(get_message)]) -> str:
    return message


async with provide_dependencies(handler) as kwargs:
    result = await handler(**kwargs)

print(result)  # hello world

The resolver is an async context manager because generator dependencies and returned context managers stay alive until the async with block exits.

Resolver Entry Points

There are two public ways to resolve a callable:

provide_dependencies(...)

This is the primary entry point:

async with provide_dependencies(
    handler,
    {"prefix": "hi"},
    request=request,
    path="/items/{item_id}",
    dependency_overrides={original_dep: override_dep},
) as kwargs:
    result = await handler(**kwargs)

Use it when you want the generic parameter names:

  • func: target callable
  • kwargs: seeded values that should already exist in the dependency graph
  • request: request-like object for request-aware resolution
  • path: route template used to infer path parameters
  • dependency_overrides: per-call override mapping

Native Usage

Seeded kwargs are available to nested dependencies before the handler runs:

from mountaineer_di import Depends, provide_dependencies


def get_message(prefix: str) -> str:
    return f"{prefix} world"


async def handler(prefix: str, message: str = Depends(get_message)) -> str:
    return message


async with provide_dependencies(handler, {"prefix": "seeded"}) as kwargs:
    result = await handler(**kwargs)

print(result)  # seeded world

Request-Bound Resolution

When FastAPI and Starlette are installed, the resolver can populate request parameters and FastAPI field markers:

from fastapi import Query, Request

from mountaineer_di import Depends, get_function_dependencies


def get_token(request: Request) -> str:
    return request.headers["x-token"]


async def handler(
    item_id: int,
    q: str = Query(),
    token: str = Depends(get_token),
) -> tuple[int, str, str]:
    return (item_id, q, token)


async with get_function_dependencies(
    callable=handler,
    request=request,
    url="/items/{item_id}",
) as kwargs:
    result = await handler(**kwargs)

If the request contains GET /items/7?q=test, result becomes:

(7, "test", "<x-token header>")

FastAPI Interop

You can mix native and FastAPI dependency markers in the same graph:

from fastapi import Depends as FastAPIDepends, Request

from mountaineer_di import Depends, get_function_dependencies


def get_user_agent(request: Request) -> str | None:
    return request.headers.get("user-agent")


def get_context(
    user_agent: str | None = FastAPIDepends(get_user_agent),
) -> str:
    return user_agent or "unknown"


async def task(context: str = Depends(get_context)) -> str:
    return context


async with get_function_dependencies(
    callable=task,
    request=request,
) as kwargs:
    result = await task(**kwargs)

Dependency Overrides

There are two ways to override dependencies.

Per-call overrides

Pass a dependency_overrides mapping when resolving a callable:

from mountaineer_di import Depends, provide_dependencies


def get_prefix() -> str:
    return "original"


def get_message(prefix: str = Depends(get_prefix)) -> str:
    return f"value:{prefix}"


def mocked_prefix() -> str:
    return "mocked"


async with provide_dependencies(
    get_message,
    dependency_overrides={get_prefix: mocked_prefix},
) as kwargs:
    result = get_message(**kwargs)

print(result)  # value:mocked

Callable-level overrides

Use @dependency_override(...) when a specific callable should always resolve with a local override. Stack multiple decorators to attach multiple local overrides:

from mountaineer_di import Depends, dependency_override, provide_dependencies


def require_valid_user() -> str:
    return "request-user"


def get_billing_user_from_request() -> str:
    return "billing-user"


@dependency_override(require_valid_user, get_billing_user_from_request)
async def bill_for_metered_type(
    user: str = Depends(require_valid_user),
) -> str:
    return user


async with provide_dependencies(bill_for_metered_type) as kwargs:
    result = await bill_for_metered_type(**kwargs)

print(result)  # billing-user

Callable-level overrides are merged with per-call overrides. If the same dependency appears in both places, the explicit per-call override wins.

Development

Development commands are available through the repo Makefile, with lint, ci-lint, lint-ruff, lint-ty, and test targets following the same pattern as sibling Mountaineer repositories.

Metadata

Release files for mountaineer-di 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mountaineer-di 0.3.0
File Size Uploaded
mountaineer_di-0.3.0.tar.gz 46.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mountaineer-di 0.3.0
File Interpreter ABI Platform
mountaineer_di-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 59.0 kB

Release files / mountaineer_di-0.3.0.tar.gz

Download URL mountaineer_di-0.3.0.tar.gz
Size 46.4 kB
Tags Source
SHA-256 checksum
How to use checksums
b0e95cff4b9e3d0afd9063c7508b9a13aad447b6d158a740fc85afd99d159147
BLAKE2b-256 checksum
How to use checksums
5a9f4220d35915f063ff284243cf33406a4f6b1f7f1c2e9edb8158edb890e113
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / mountaineer_di-0.3.0-py3-none-any.whl

Download URL mountaineer_di-0.3.0-py3-none-any.whl
Size 12.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
42481ab3a62dcd6082a983214b7ed7d957a17914ed2297d519a3369fa32ef2a4
BLAKE2b-256 checksum
How to use checksums
f0567ced07ef849899bd1c89e8bf2ed9cc269e04e877a988a934d0d73ec9fdf6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page