fastapi/dependencies/models.py PYTHON 194 lines View on github.com → Search inside
1import inspect2import sys3from collections.abc import Callable4from dataclasses import dataclass, field5from functools import cached_property, 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@dataclass32class 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 = None5253    @cached_property54    def oauth_scopes(self) -> list[str]:55        scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else []56        # This doesn't use a set to preserve order, just in case57        for scope in self.own_oauth_scopes or []:58            if scope not in scopes:59                scopes.append(scope)60        return scopes6162    @cached_property63    def cache_key(self) -> DependencyCacheKey:64        scopes_for_cache = (65            tuple(sorted(set(self.oauth_scopes or []))) if self._uses_scopes else ()66        )67        return (68            self.call,69            scopes_for_cache,70            self.computed_scope or "",71        )7273    @cached_property74    def _uses_scopes(self) -> bool:75        if self.own_oauth_scopes:76            return True77        if self.security_scopes_param_name is not None:78            return True79        if self._is_security_scheme:80            return True81        for sub_dep in self.dependencies:82            if sub_dep._uses_scopes:83                return True84        return False8586    @cached_property87    def _is_security_scheme(self) -> bool:88        if self.call is None:89            return False  # pragma: no cover90        unwrapped = _unwrapped_call(self.call)91        return isinstance(unwrapped, SecurityBase)9293    # Mainly to get the type of SecurityBase, but it's the same self.call94    @cached_property95    def _security_scheme(self) -> SecurityBase:96        unwrapped = _unwrapped_call(self.call)97        assert isinstance(unwrapped, SecurityBase)98        return unwrapped99100    @cached_property101    def _security_dependencies(self) -> list["Dependant"]:102        security_deps = [dep for dep in self.dependencies if dep._is_security_scheme]103        return security_deps104105    @cached_property106    def is_gen_callable(self) -> bool:107        if self.call is None:108            return False  # pragma: no cover109        if inspect.isgeneratorfunction(110            _impartial(self.call)111        ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):112            return True113        if inspect.isclass(_unwrapped_call(self.call)):114            return False115        dunder_call = getattr(_impartial(self.call), "__call__", None)  # noqa: B004116        if dunder_call is None:117            return False  # pragma: no cover118        if inspect.isgeneratorfunction(119            _impartial(dunder_call)120        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):121            return True122        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None)  # noqa: B004123        if dunder_unwrapped_call is None:124            return False  # pragma: no cover125        if inspect.isgeneratorfunction(126            _impartial(dunder_unwrapped_call)127        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):128            return True129        return False130131    @cached_property132    def is_async_gen_callable(self) -> bool:133        if self.call is None:134            return False  # pragma: no cover135        if inspect.isasyncgenfunction(136            _impartial(self.call)137        ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)):138            return True139        if inspect.isclass(_unwrapped_call(self.call)):140            return False141        dunder_call = getattr(_impartial(self.call), "__call__", None)  # noqa: B004142        if dunder_call is None:143            return False  # pragma: no cover144        if inspect.isasyncgenfunction(145            _impartial(dunder_call)146        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):147            return True148        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None)  # noqa: B004149        if dunder_unwrapped_call is None:150            return False  # pragma: no cover151        if inspect.isasyncgenfunction(152            _impartial(dunder_unwrapped_call)153        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_unwrapped_call)):154            return True155        return False156157    @cached_property158    def is_coroutine_callable(self) -> bool:159        if self.call is None:160            return False  # pragma: no cover161        if inspect.isroutine(_impartial(self.call)) and iscoroutinefunction(162            _impartial(self.call)163        ):164            return True165        if inspect.isroutine(_unwrapped_call(self.call)) and iscoroutinefunction(166            _unwrapped_call(self.call)167        ):168            return True169        if inspect.isclass(_unwrapped_call(self.call)):170            return False171        dunder_call = getattr(_impartial(self.call), "__call__", None)  # noqa: B004172        if dunder_call is None:173            return False  # pragma: no cover174        if iscoroutinefunction(_impartial(dunder_call)) or iscoroutinefunction(175            _unwrapped_call(dunder_call)176        ):177            return True178        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None)  # noqa: B004179        if dunder_unwrapped_call is None:180            return False  # pragma: no cover181        if iscoroutinefunction(182            _impartial(dunder_unwrapped_call)183        ) or iscoroutinefunction(_unwrapped_call(dunder_unwrapped_call)):184            return True185        return False186187    @cached_property188    def computed_scope(self) -> str | None:189        if self.scope:190            return self.scope191        if self.is_gen_callable or self.is_async_gen_callable:192            return "request"193        return None

Code quality findings 9

Overuse may indicate design issues; consider polymorphism
isinstance-overuse
while isinstance(func, partial):
Ensure functions have docstrings for documentation
missing-docstring
def oauth_scopes(self) -> list[str]:
Ensure functions have docstrings for documentation
missing-docstring
def cache_key(self) -> DependencyCacheKey:
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
return isinstance(unwrapped, SecurityBase)
Overuse may indicate design issues; consider polymorphism
isinstance-overuse
assert isinstance(unwrapped, SecurityBase)
Ensure functions have docstrings for documentation
missing-docstring
def is_gen_callable(self) -> bool:
Ensure functions have docstrings for documentation
missing-docstring
def is_async_gen_callable(self) -> bool:
Ensure functions have docstrings for documentation
missing-docstring
def is_coroutine_callable(self) -> bool:
Ensure functions have docstrings for documentation
missing-docstring
def computed_scope(self) -> str | None:

Get this view in your editor

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