fastapi/dependencies/models.py PYTHON 235 lines View on github.com → Search inside
1import inspect2import sys3from collections.abc import Callable4from dataclasses import dataclass, field5from functools import lru_cache, partial6from typing import Any, Literal78from fastapi._compat import ModelField9from fastapi.security.base import SecurityBase10from fastapi.types import DependencyCacheKey1112if sys.version_info >= (3, 13):  # pragma: no cover13    from inspect import iscoroutinefunction14else:  # pragma: no cover15    from asyncio import iscoroutinefunction161718def _unwrapped_call(call: Callable[..., Any] | None) -> Any:19    if call is None:20        return call  # pragma: no cover21    unwrapped = inspect.unwrap(_impartial(call))22    return unwrapped232425def _impartial(func: Callable[..., Any]) -> Callable[..., Any]:26    while isinstance(func, partial):27        func = func.func28    return func293031@dataclass(slots=True)32class Dependant:33    path_params: list[ModelField] = field(default_factory=list)34    query_params: list[ModelField] = field(default_factory=list)35    header_params: list[ModelField] = field(default_factory=list)36    cookie_params: list[ModelField] = field(default_factory=list)37    body_params: list[ModelField] = field(default_factory=list)38    dependencies: list["Dependant"] = field(default_factory=list)39    name: str | None = None40    call: Callable[..., Any] | None = None41    request_param_name: str | None = None42    websocket_param_name: str | None = None43    http_connection_param_name: str | None = None44    response_param_name: str | None = None45    background_tasks_param_name: str | None = None46    security_scopes_param_name: str | None = None47    own_oauth_scopes: list[str] | None = None48    parent_oauth_scopes: list[str] | None = None49    use_cache: bool = True50    path: str | None = None51    scope: Literal["function", "request"] | None = None525354_UsesScopesCache = dict[int, tuple[Dependant, bool]]55_CALLABLE_CLASSIFICATION_CACHE_SIZE = 4096565758class _CallIdentity:59    __slots__ = ("call",)6061    def __init__(self, call: Callable[..., Any]) -> None:62        self.call = call6364    def __hash__(self) -> int:65        return id(self.call)6667    def __eq__(self, other: object) -> bool:68        return isinstance(other, _CallIdentity) and self.call is other.call697071def _get_oauth_scopes(*, dependant: Dependant) -> list[str]:72    scopes = (73        dependant.parent_oauth_scopes.copy() if dependant.parent_oauth_scopes else []74    )75    # This doesn't use a set to preserve order, just in case76    for scope in dependant.own_oauth_scopes or []:77        if scope not in scopes:78            scopes.append(scope)79    return scopes808182def _get_cache_key(83    *,84    dependant: Dependant,85    uses_scopes_cache: _UsesScopesCache | None = None,86) -> DependencyCacheKey:87    scopes_for_cache = (88        tuple(sorted(set(_get_oauth_scopes(dependant=dependant))))89        if _uses_scopes(dependant=dependant, cache=uses_scopes_cache)90        else ()91    )92    return (93        dependant.call,94        scopes_for_cache,95        _get_computed_scope(dependant=dependant) or "",96    )979899def _uses_scopes(100    *, dependant: Dependant, cache: _UsesScopesCache | None = None101) -> bool:102    if cache is None:103        cache = {}104    cache_key = id(dependant)105    cached = cache.get(cache_key)106    if cached is not None and cached[0] is dependant:107        return cached[1]108    if dependant.own_oauth_scopes:109        result = True110    elif dependant.security_scopes_param_name is not None:111        result = True112    elif _is_security_scheme(dependant=dependant):113        result = True114    else:115        result = any(116            _uses_scopes(dependant=sub_dep, cache=cache)117            for sub_dep in dependant.dependencies118        )119    cache[cache_key] = (dependant, result)120    return result121122123def _is_security_scheme(*, dependant: Dependant) -> bool:124    if dependant.call is None:125        return False  # pragma: no cover126    unwrapped = _unwrapped_call(dependant.call)127    return isinstance(unwrapped, SecurityBase)128129130def _get_security_scheme(*, dependant: Dependant) -> SecurityBase:131    # Mainly to get the type of SecurityBase, but it's the same dependant.call132    unwrapped = _unwrapped_call(dependant.call)133    assert isinstance(unwrapped, SecurityBase)134    return unwrapped135136137@lru_cache(maxsize=_CALLABLE_CLASSIFICATION_CACHE_SIZE)138def _is_gen_callable_cached(call_identity: _CallIdentity) -> bool:139    call = call_identity.call140    if inspect.isgeneratorfunction(_impartial(call)) or inspect.isgeneratorfunction(141        _unwrapped_call(call)142    ):143        return True144    if inspect.isclass(_unwrapped_call(call)):145        return False146    dunder_call = getattr(_impartial(call), "__call__", None)  # noqa: B004147    if dunder_call is None:148        return False  # pragma: no cover149    if inspect.isgeneratorfunction(150        _impartial(dunder_call)151    ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):152        return True153    dunder_unwrapped_call = getattr(_unwrapped_call(call), "__call__", None)  # noqa: B004154    if dunder_unwrapped_call is None:155        return False  # pragma: no cover156    return inspect.isgeneratorfunction(157        _impartial(dunder_unwrapped_call)158    ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call))159160161def _is_gen_callable(call: Callable[..., Any] | None) -> bool:162    if call is None:163        return False  # pragma: no cover164    return _is_gen_callable_cached(_CallIdentity(call))165166167@lru_cache(maxsize=_CALLABLE_CLASSIFICATION_CACHE_SIZE)168def _is_async_gen_callable_cached(call_identity: _CallIdentity) -> bool:169    call = call_identity.call170    if inspect.isasyncgenfunction(_impartial(call)) or inspect.isasyncgenfunction(171        _unwrapped_call(call)172    ):173        return True174    if inspect.isclass(_unwrapped_call(call)):175        return False176    dunder_call = getattr(_impartial(call), "__call__", None)  # noqa: B004177    if dunder_call is None:178        return False  # pragma: no cover179    if inspect.isasyncgenfunction(180        _impartial(dunder_call)181    ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):182        return True183    dunder_unwrapped_call = getattr(_unwrapped_call(call), "__call__", None)  # noqa: B004184    if dunder_unwrapped_call is None:185        return False  # pragma: no cover186    return inspect.isasyncgenfunction(187        _impartial(dunder_unwrapped_call)188    ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_unwrapped_call))189190191def _is_async_gen_callable(call: Callable[..., Any] | None) -> bool:192    if call is None:193        return False  # pragma: no cover194    return _is_async_gen_callable_cached(_CallIdentity(call))195196197@lru_cache(maxsize=_CALLABLE_CLASSIFICATION_CACHE_SIZE)198def _is_coroutine_callable_cached(call_identity: _CallIdentity) -> bool:199    call = call_identity.call200    if inspect.isroutine(_impartial(call)) and iscoroutinefunction(_impartial(call)):201        return True202    if inspect.isroutine(_unwrapped_call(call)) and iscoroutinefunction(203        _unwrapped_call(call)204    ):205        return True206    if inspect.isclass(_unwrapped_call(call)):207        return False208    dunder_call = getattr(_impartial(call), "__call__", None)  # noqa: B004209    if dunder_call is None:210        return False  # pragma: no cover211    if iscoroutinefunction(_impartial(dunder_call)) or iscoroutinefunction(212        _unwrapped_call(dunder_call)213    ):214        return True215    dunder_unwrapped_call = getattr(_unwrapped_call(call), "__call__", None)  # noqa: B004216    if dunder_unwrapped_call is None:217        return False  # pragma: no cover218    return iscoroutinefunction(219        _impartial(dunder_unwrapped_call)220    ) or iscoroutinefunction(_unwrapped_call(dunder_unwrapped_call))221222223def _is_coroutine_callable(call: Callable[..., Any] | None) -> bool:224    if call is None:225        return False  # pragma: no cover226    return _is_coroutine_callable_cached(_CallIdentity(call))227228229def _get_computed_scope(*, dependant: Dependant) -> str | None:230    if dependant.scope:231        return dependant.scope232    if _is_gen_callable(dependant.call) or _is_async_gen_callable(dependant.call):233        return "request"234    return None

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.

Generated by searchcode.com · powered by code_get_file + code_get_findings