Metadata-Version: 2.5
Name: fastapi-cache-di
Version: 0.3.0
Summary: Speed up FastAPI startup by caching dependency-tree introspection
Project-URL: Homepage, https://github.com/Toilal/fastapi-cache-di
Project-URL: Repository, https://github.com/Toilal/fastapi-cache-di
Project-URL: Changelog, https://github.com/Toilal/fastapi-cache-di/blob/develop/CHANGELOG.md
Project-URL: Issues, https://github.com/Toilal/fastapi-cache-di/issues
Author-email: Rémi Alvergnat <toilal.dev@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: cache,dependency-injection,fastapi,performance,startup
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: fastapi<1.0,>=0.112.4
Description-Content-Type: text/markdown

# fastapi-cache-di

[![Latest Version](https://img.shields.io/pypi/v/fastapi-cache-di.svg)](https://pypi.python.org/pypi/fastapi-cache-di)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Toilal/fastapi-cache-di/blob/develop/LICENSE)
[![Build Status](https://img.shields.io/github/actions/workflow/status/Toilal/fastapi-cache-di/ci.yml?branch=develop)](https://github.com/Toilal/fastapi-cache-di/actions/workflows/ci.yml)
[![Codecov](https://img.shields.io/codecov/c/github/Toilal/fastapi-cache-di)](https://codecov.io/gh/Toilal/fastapi-cache-di)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/relekang/python-semantic-release)

Speed up **FastAPI startup** by caching its dependency-tree introspection.

At startup, FastAPI re-introspects every route's dependency tree with no caching,
so dependencies shared across many routes (auth checks, DB handles, role guards …)
are parsed from scratch again and again. `fastapi-cache-di` memoizes that work for
the duration of route loading, turning `O(routes × tree-depth)` into
`O(routes + unique-deps)`, then restores FastAPI's originals.

## Install

```bash
pip install fastapi-cache-di
# or
uv add fastapi-cache-di
```

## Usage

Wrap the code that loads your routes with the context manager:

```python
from fastapi import APIRouter, FastAPI

from fastapi_cache_di import fastapi_deps_cache

app = FastAPI()
users = APIRouter()
orders = APIRouter()
billing = APIRouter()

with fastapi_deps_cache():
    # Registering routes introspects each dependency tree; caching is active here.
    app.include_router(users)
    app.include_router(orders)
    app.include_router(billing)
# originals restored here; cache memory freed
```

Manual patch/unpatch, sharing and inspecting the cache, and the cache-key details
are covered in the documentation.

## Calling loop-safe dependencies inline

At **request time**, FastAPI calls every dependency that is neither a coroutine
nor a generator through the threadpool: every `Depends(SomeClass)` and every
plain `def` dependency costs a round trip to a worker thread, often far more
than a class whose `__init__` only stores its arguments.

`patch_fastapi_run_in_threadpool()` lets such dependencies run directly on the
event loop. It is opt-in, because the library cannot tell whether a call blocks:

- `loop_safe` marks one sync function or class (it returns the same object, so
  `Depends(...)` and `dependency_overrides` keep working);
- `inline_classes=True` treats every class as loop-safe;
- everything else still goes through the threadpool, as do sync generator
  dependencies and sync endpoints.

```python
from typing import Annotated

from fastapi import Depends, FastAPI

from fastapi_cache_di import loop_safe, patch_fastapi_run_in_threadpool

patch_fastapi_run_in_threadpool(inline_classes=True)


@loop_safe
def get_tenant_id() -> str:
    return "acme"


class UserRepository:
    def __init__(self, tenant_id: Annotated[str, Depends(get_tenant_id)]) -> None:
        self.tenant_id = tenant_id


app = FastAPI()


@app.get("/users")
async def list_users(repo: Annotated[UserRepository, Depends()]) -> str:
    return repo.tenant_id
```

**A loop-safe callable must never block**: no I/O, no lock, no heavy
computation. A blocking call on the event loop stalls every in-flight request.
See the documentation for overrides and the marker shared with
[fastapi-standalone-di](https://github.com/Toilal/fastapi-standalone-di).

## Skipping the sub-tree of cached dependencies

At **request time**, FastAPI solves the whole sub-tree of a dependency before
checking whether its value is already in the request's cache, so a dependency
shared across a deep tree is solved again at every occurrence.
`patch_fastapi_solve_dependencies()` stops that walk as soon as the value is
cached. It is opt-in and stays active for the app's lifetime:

```python
from fastapi import FastAPI

from fastapi_cache_di import patch_fastapi_solve_dependencies

patch_fastapi_solve_dependencies()

app = FastAPI()
```

The values injected into endpoints are unchanged; see the documentation for the
details.

## Documentation

Full documentation is available at
[toilal.github.io/fastapi-cache-di](https://toilal.github.io/fastapi-cache-di/)
(usage guide, internals, and API reference).

## Requirements

- Python ≥ 3.12
- FastAPI ≥ 0.112.4

## License

[MIT](./LICENSE) © Rémi Alvergnat


# CHANGELOG

<!-- version list -->

## v0.3.0 (2026-10-16)

### Bug Fixes

- Patch get_flat_dependant only where FastAPI still defines it
  ([#14](https://github.com/Toilal/fastapi-cache-di/pull/14),
  [`30fbb28`](https://github.com/Toilal/fastapi-cache-di/commit/30fbb2898aa08e1163b493fb3a7833f9cd4b6e12))

- Support FastAPI 0.141+ where get_flat_dependant no longer exists
  ([#14](https://github.com/Toilal/fastapi-cache-di/pull/14),
  [`30fbb28`](https://github.com/Toilal/fastapi-cache-di/commit/30fbb2898aa08e1163b493fb3a7833f9cd4b6e12))

### Features

- Call loop-safe dependencies on the event loop instead of a threadpool hop
  ([#16](https://github.com/Toilal/fastapi-cache-di/pull/16),
  [`a37d214`](https://github.com/Toilal/fastapi-cache-di/commit/a37d214e0c31012062d0edca3184aa49cbffb28a))

- Skip cached sub-trees when dependency_overrides is set too
  ([#15](https://github.com/Toilal/fastapi-cache-di/pull/15),
  [`bb8a2f7`](https://github.com/Toilal/fastapi-cache-di/commit/bb8a2f7d61764740a79b7ce0fe9b0d4bec016cb3))

- Skip re-walking the sub-tree of already-cached dependencies at request time
  ([#15](https://github.com/Toilal/fastapi-cache-di/pull/15),
  [`bb8a2f7`](https://github.com/Toilal/fastapi-cache-di/commit/bb8a2f7d61764740a79b7ce0fe9b0d4bec016cb3))


## v0.2.1 (2026-07-06)

### Bug Fixes

- Ship py.typed marker for PEP 561 type information
  ([#11](https://github.com/Toilal/fastapi-cache-di/pull/11),
  [`1a7eb6f`](https://github.com/Toilal/fastapi-cache-di/commit/1a7eb6f89c79b17910ad7e6642f2f229532cf98d))


## v0.2.0 (2026-07-05)

### Features

- Support Python 3.11 ([#10](https://github.com/Toilal/fastapi-cache-di/pull/10),
  [`d593d6f`](https://github.com/Toilal/fastapi-cache-di/commit/d593d6f55f56ebff80af0b4608066c8f426dcaad))


## v0.1.0 (2026-07-05)

- Initial Release

Changelog entries are generated automatically by
[python-semantic-release](https://python-semantic-release.readthedocs.io/) from
[Conventional Commits](https://www.conventionalcommits.org/) on release.
