Browse Source

♻️ Refactor dependencies, allow a default scope of None

pull/14262/head
Sebastián Ramírez 9 months ago
parent
commit
87bec2962c
  1. 16
      fastapi/dependencies/models.py
  2. 17
      fastapi/dependencies/utils.py
  3. 4
      fastapi/param_functions.py
  4. 2
      fastapi/params.py
  5. 3
      fastapi/types.py

16
fastapi/dependencies/models.py

@ -1,8 +1,10 @@
from dataclasses import dataclass, field
from typing import Any, Callable, List, Optional, Sequence, Tuple
from functools import cached_property
from typing import Any, Callable, List, Optional, Sequence, Union
from fastapi._compat import ModelField
from fastapi.security.base import SecurityBase
from fastapi.types import DependencyCacheKey
from typing_extensions import Literal
@ -32,14 +34,12 @@ class Dependant:
security_scopes: Optional[List[str]] = None
use_cache: bool = True
path: Optional[str] = None
scope: Literal["function", "request"] = "request"
cache_key: Tuple[Optional[Callable[..., Any]], Tuple[str, ...], str] = field(
init=False
)
scope: Union[Literal["function", "request"], None] = None
def __post_init__(self) -> None:
self.cache_key = (
@cached_property
def cache_key(self) -> DependencyCacheKey:
return (
self.call,
tuple(sorted(set(self.security_scopes or []))),
self.scope,
self.scope or "",
)

17
fastapi/dependencies/utils.py

@ -60,6 +60,7 @@ from fastapi.logger import logger
from fastapi.security.base import SecurityBase
from fastapi.security.oauth2 import OAuth2, SecurityScopes
from fastapi.security.open_id_connect_url import OpenIdConnect
from fastapi.types import DependencyCacheKey
from fastapi.utils import create_model_field, get_path_param_names
from pydantic import BaseModel
from pydantic.fields import FieldInfo
@ -138,14 +139,11 @@ def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> De
)
CacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...]]
def get_flat_dependant(
dependant: Dependant,
*,
skip_repeats: bool = False,
visited: Optional[List[CacheKey]] = None,
visited: Optional[List[DependencyCacheKey]] = None,
) -> Dependant:
if visited is None:
visited = []
@ -238,7 +236,7 @@ def get_dependant(
name: Optional[str] = None,
security_scopes: Optional[List[str]] = None,
use_cache: bool = True,
scope: Literal["function", "request"] = "request",
scope: Union[Literal["function", "request"], None] = None,
) -> Dependant:
dependant = Dependant(
call=call,
@ -254,7 +252,7 @@ def get_dependant(
if isinstance(call, SecurityBase):
use_scopes: List[str] = []
if isinstance(call, (OAuth2, OpenIdConnect)):
use_scopes = security_scopes
use_scopes = security_scopes or use_scopes
security_requirement = SecurityRequirement(
security_scheme=call, scopes=use_scopes
)
@ -581,7 +579,7 @@ class SolvedDependency:
errors: List[Any]
background_tasks: Optional[StarletteBackgroundTasks]
response: Response
dependency_cache: Dict[Tuple[Callable[..., Any], Tuple[str]], Any]
dependency_cache: Dict[DependencyCacheKey, Any]
async def solve_dependencies(
@ -592,7 +590,7 @@ async def solve_dependencies(
background_tasks: Optional[StarletteBackgroundTasks] = None,
response: Optional[Response] = None,
dependency_overrides_provider: Optional[Any] = None,
dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
dependency_cache: Optional[Dict[DependencyCacheKey, Any]] = None,
# TODO: remove this parameter later, no longer used, not removing it yet as some
# people might be monkey patching this function (although that's not supported)
async_exit_stack: AsyncExitStack,
@ -616,9 +614,6 @@ async def solve_dependencies(
dependency_cache = {}
for sub_dependant in dependant.dependencies:
sub_dependant.call = cast(Callable[..., Any], sub_dependant.call)
sub_dependant.cache_key = cast(
Tuple[Callable[..., Any], Tuple[str]], sub_dependant.cache_key
)
call = sub_dependant.call
use_sub_dependant = sub_dependant
if (

4
fastapi/param_functions.py

@ -2246,7 +2246,7 @@ def Depends( # noqa: N802
),
] = True,
scope: Annotated[
Literal["function", "request"],
Union[Literal["function", "request"], None],
Doc(
"""
Mainly for dependencies with `yield`, define when the dependency function
@ -2264,7 +2264,7 @@ def Depends( # noqa: N802
function will be executed *around* the **request** and response cycle.
"""
),
] = "request",
] = None,
) -> Any:
"""
Declare a FastAPI dependency.

2
fastapi/params.py

@ -766,7 +766,7 @@ class File(Form): # type: ignore[misc]
class Depends:
dependency: Optional[Callable[..., Any]] = None
use_cache: bool = True
scope: Literal["function", "request"] = "request"
scope: Union[Literal["function", "request"], None] = None
@dataclass

3
fastapi/types.py

@ -1,6 +1,6 @@
import types
from enum import Enum
from typing import Any, Callable, Dict, Set, Type, TypeVar, Union
from typing import Any, Callable, Dict, Optional, Set, Tuple, Type, TypeVar, Union
from pydantic import BaseModel
@ -8,3 +8,4 @@ DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
UnionType = getattr(types, "UnionType", Union)
ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str]
IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]]
DependencyCacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...], str]

Loading…
Cancel
Save