Browse Source

🎨 [pre-commit.ci] Auto format from pre-commit.com hooks

pull/12529/head
pre-commit-ci[bot] 9 months ago
parent
commit
b189030589
  1. 4
      docs_src/dependencies/tutorial013c_an_py39.py
  2. 3
      fastapi/applications.py
  3. 3
      fastapi/dependencies/models.py
  4. 68
      fastapi/dependencies/utils.py
  5. 8
      fastapi/exceptions.py
  6. 4
      fastapi/params.py
  7. 18
      fastapi/utils.py
  8. 8
      tests/test_lifespan_scoped_dependencies/test_dependency_overrides.py
  9. 12
      tests/test_lifespan_scoped_dependencies/test_endpoint_usage.py
  10. 1
      tests/test_params_repr.py

4
docs_src/dependencies/tutorial013c_an_py39.py

@ -32,9 +32,7 @@ async def get_configuration() -> dict:
} }
GlobalConfiguration = Annotated[ GlobalConfiguration = Annotated[dict, Depends(get_configuration, scope="lifespan")]
dict, Depends(get_configuration, scope="lifespan")
]
async def get_database_connection(configuration: GlobalConfiguration): async def get_database_connection(configuration: GlobalConfiguration):

3
fastapi/applications.py

@ -36,9 +36,8 @@ from fastapi.openapi.utils import get_openapi
from fastapi.params import Depends from fastapi.params import Depends
from fastapi.routing import merge_lifespan_context from fastapi.routing import merge_lifespan_context
from fastapi.types import DecoratedCallable, IncEx from fastapi.types import DecoratedCallable, IncEx
from fastapi.utils import generate_unique_id, call_asynchronously from fastapi.utils import call_asynchronously, generate_unique_id
from starlette.applications import Starlette from starlette.applications import Starlette
from starlette.concurrency import run_in_threadpool
from starlette.datastructures import State from starlette.datastructures import State
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.middleware import Middleware from starlette.middleware import Middleware

3
fastapi/dependencies/models.py

@ -2,7 +2,7 @@ import inspect
import sys import sys
from dataclasses import dataclass, field from dataclasses import dataclass, field
from functools import cached_property from functools import cached_property
from typing import Any, Callable, List, Optional, Sequence, Union, Tuple, cast from typing import Any, Callable, List, Optional, Sequence, Tuple, Union, cast
from fastapi._compat import ModelField from fastapi._compat import ModelField
from fastapi.security.base import SecurityBase from fastapi.security.base import SecurityBase
@ -65,6 +65,7 @@ class LifespanDependant:
) )
return self.caller, self.index return self.caller, self.index
@dataclass @dataclass
class EndpointDependant: class EndpointDependant:
path_params: List[ModelField] = field(default_factory=list) path_params: List[ModelField] = field(default_factory=list)

68
fastapi/dependencies/utils.py

@ -53,8 +53,16 @@ from fastapi.concurrency import (
asynccontextmanager, asynccontextmanager,
contextmanager_in_threadpool, contextmanager_in_threadpool,
) )
from fastapi.dependencies.models import EndpointDependant, LifespanDependant, SecurityRequirement from fastapi.dependencies.models import (
from fastapi.exceptions import DependencyScopeError, InvalidDependencyScope, UninitializedLifespanDependency EndpointDependant,
LifespanDependant,
SecurityRequirement,
)
from fastapi.exceptions import (
DependencyScopeError,
InvalidDependencyScope,
UninitializedLifespanDependency,
)
from fastapi.logger import logger from fastapi.logger import logger
from fastapi.security.base import SecurityBase from fastapi.security.base import SecurityBase
from fastapi.security.oauth2 import OAuth2, SecurityScopes from fastapi.security.oauth2 import OAuth2, SecurityScopes
@ -122,7 +130,7 @@ def ensure_multipart_is_installed() -> None:
def get_parameterless_sub_dependant( def get_parameterless_sub_dependant(
*, depends: params.Depends, path: str, caller: Callable[..., Any], index: int *, depends: params.Depends, path: str, caller: Callable[..., Any], index: int
) -> Union[EndpointDependant, LifespanDependant]: ) -> Union[EndpointDependant, LifespanDependant]:
assert callable(depends.dependency), ( assert callable(depends.dependency), (
"A parameter-less dependency must have a callable dependency" "A parameter-less dependency must have a callable dependency"
@ -135,7 +143,7 @@ def get_parameterless_sub_dependant(
path=path, path=path,
call=depends.dependency, call=depends.dependency,
security_scopes=use_security_scopes, security_scopes=use_security_scopes,
index=index index=index,
) )
elif depends.scope == "lifespan": elif depends.scope == "lifespan":
return get_lifespan_dependant( return get_lifespan_dependant(
@ -146,8 +154,7 @@ def get_parameterless_sub_dependant(
) )
else: else:
raise InvalidDependencyScope( raise InvalidDependencyScope(
f'Dependency "{index}" of {caller} has an invalid ' f'Dependency "{index}" of {caller} has an invalid scope: "{depends.scope}"'
f'scope: "{depends.scope}"'
) )
@ -267,7 +274,7 @@ def get_lifespan_dependant(
raise DependencyScopeError( raise DependencyScopeError(
f'Dependency "{dependant.name}" has "lifespan" scope, but was defined' f'Dependency "{dependant.name}" has "lifespan" scope, but was defined'
f'with an invalid argument: "{param_name}" which is ' f'with an invalid argument: "{param_name}" which is '
f'not a valid sub-dependency. Lifespan scoped dependencies may only ' f"not a valid sub-dependency. Lifespan scoped dependencies may only "
f"use lifespan scoped sub-dependencies." f"use lifespan scoped sub-dependencies."
) )
@ -275,7 +282,7 @@ def get_lifespan_dependant(
raise DependencyScopeError( raise DependencyScopeError(
f'Dependency "{dependant.name}" has "lifespan" scope, but was defined with the ' f'Dependency "{dependant.name}" has "lifespan" scope, but was defined with the '
f'sub-dependency "{param_name}" which has "{param_details.depends.scope}" scope. Lifespan scoped ' f'sub-dependency "{param_name}" which has "{param_details.depends.scope}" scope. Lifespan scoped '
f'dependencies may only use lifespan scoped sub-dependencies.' f"dependencies may only use lifespan scoped sub-dependencies."
) )
assert param_details.depends.dependency is not None assert param_details.depends.dependency is not None
@ -346,23 +353,27 @@ def get_endpoint_dependant(
if param_details.depends.scopes: if param_details.depends.scopes:
use_security_scopes.extend(param_details.depends.scopes) use_security_scopes.extend(param_details.depends.scopes)
if param_details.depends.scope == "lifespan": if param_details.depends.scope == "lifespan":
dependant.lifespan_dependencies.append(get_lifespan_dependant( dependant.lifespan_dependencies.append(
caller=call, get_lifespan_dependant(
call=param_details.depends.dependency, caller=call,
name=param_name, call=param_details.depends.dependency,
use_cache=param_details.depends.use_cache, name=param_name,
index=index use_cache=param_details.depends.use_cache,
)) index=index,
)
)
elif param_details.depends.scope in ("request", "function", None): elif param_details.depends.scope in ("request", "function", None):
dependant.endpoint_dependencies.append(get_endpoint_dependant( dependant.endpoint_dependencies.append(
path=path, get_endpoint_dependant(
call=param_details.depends.dependency, path=path,
name=param_name, call=param_details.depends.dependency,
security_scopes=use_security_scopes, name=param_name,
use_cache=param_details.depends.use_cache, security_scopes=use_security_scopes,
index=index, use_cache=param_details.depends.use_cache,
scope=param_details.depends.scope index=index,
)) scope=param_details.depends.scope,
)
)
else: else:
raise InvalidDependencyScope( raise InvalidDependencyScope(
f'Dependency "{name}" of {call} has an invalid ' f'Dependency "{name}" of {call} has an invalid '
@ -628,7 +639,10 @@ def add_param_to_fields(*, field: ModelField, dependant: EndpointDependant) -> N
async def _solve_generator( async def _solve_generator(
*, dependant: Union[EndpointDependant, LifespanDependant], stack: AsyncExitStack, sub_values: Dict[str, Any] *,
dependant: Union[EndpointDependant, LifespanDependant],
stack: AsyncExitStack,
sub_values: Dict[str, Any],
) -> Any: ) -> Any:
assert dependant.call assert dependant.call
if dependant.is_gen_callable: if dependant.is_gen_callable:
@ -690,7 +704,9 @@ async def solve_lifespan_dependant(
if dependant_to_solve.is_gen_callable or dependant_to_solve.is_async_gen_callable: if dependant_to_solve.is_gen_callable or dependant_to_solve.is_async_gen_callable:
value = await _solve_generator( value = await _solve_generator(
dependant=dependant_to_solve, stack=async_exit_stack, sub_values=dependency_arguments dependant=dependant_to_solve,
stack=async_exit_stack,
sub_values=dependency_arguments,
) )
elif dependant_to_solve.is_coroutine_callable: elif dependant_to_solve.is_coroutine_callable:
value = await call(**dependency_arguments) value = await call(**dependency_arguments)

8
fastapi/exceptions.py

@ -146,31 +146,39 @@ class FastAPIError(RuntimeError):
A generic, FastAPI-specific error. A generic, FastAPI-specific error.
""" """
class DependencyError(FastAPIError): class DependencyError(FastAPIError):
""" """
A generic error regarding to dependencies. A generic error regarding to dependencies.
""" """
pass pass
class InvalidDependencyScope(DependencyError): class InvalidDependencyScope(DependencyError):
""" """
A dependency was declared with an unsupported scope value. A dependency was declared with an unsupported scope value.
""" """
pass pass
class DependencyScopeError(DependencyError): class DependencyScopeError(DependencyError):
""" """
A dependency declared that it depends on another dependency with an invalid A dependency declared that it depends on another dependency with an invalid
(narrower) scope. (narrower) scope.
""" """
class UninitializedLifespanDependency(DependencyError): class UninitializedLifespanDependency(DependencyError):
""" """
A bug in FastAPI caused a lifespan-scoped dependency to not initialize properly A bug in FastAPI caused a lifespan-scoped dependency to not initialize properly
at the point where we handled a request that depended on it. at the point where we handled a request that depended on it.
""" """
pass pass
class ValidationException(Exception): class ValidationException(Exception):
def __init__(self, errors: Sequence[Any]) -> None: def __init__(self, errors: Sequence[Any]) -> None:
self._errors = errors self._errors = errors

4
fastapi/params.py

@ -773,7 +773,9 @@ class Depends:
def __post_init__(self): def __post_init__(self):
if self.scope not in ("lifespan", "request", "function", None): if self.scope not in ("lifespan", "request", "function", None):
raise InvalidDependencyScope(f"Dependency received an invalid scope: \"{self.scope}\"") raise InvalidDependencyScope(
f'Dependency received an invalid scope: "{self.scope}"'
)
@dataclass @dataclass

18
fastapi/utils.py

@ -7,18 +7,18 @@ from dataclasses import is_dataclass
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
Awaitable,
Dict, Dict,
MutableMapping, MutableMapping,
Optional, Optional,
Set, Set,
Type, Type,
TypeVar,
Union, Union,
cast, Awaitable, TypeVar, cast,
) )
from weakref import WeakKeyDictionary from weakref import WeakKeyDictionary
from starlette.concurrency import run_in_threadpool
import fastapi import fastapi
from fastapi._compat import ( from fastapi._compat import (
PYDANTIC_V2, PYDANTIC_V2,
@ -35,7 +35,8 @@ from fastapi._compat import (
from fastapi.datastructures import DefaultPlaceholder, DefaultType from fastapi.datastructures import DefaultPlaceholder, DefaultType
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.fields import FieldInfo from pydantic.fields import FieldInfo
from typing_extensions import Literal, TypeIs, ParamSpec from starlette.concurrency import run_in_threadpool
from typing_extensions import Literal, ParamSpec, TypeIs
if TYPE_CHECKING: # pragma: nocover if TYPE_CHECKING: # pragma: nocover
from .routing import APIRoute from .routing import APIRoute
@ -269,7 +270,7 @@ def get_value_or_default(
def _is_coroutine_callable( def _is_coroutine_callable(
callable_: Callable[..., Any] callable_: Callable[..., Any],
) -> TypeIs[Callable[..., Awaitable[Any]]]: ) -> TypeIs[Callable[..., Awaitable[Any]]]:
if inspect.isroutine(callable_): if inspect.isroutine(callable_):
return iscoroutinefunction(callable_) return iscoroutinefunction(callable_)
@ -278,10 +279,11 @@ def _is_coroutine_callable(
dunder_call = getattr(callable_, "__call__", None) # noqa: B004 dunder_call = getattr(callable_, "__call__", None) # noqa: B004
return iscoroutinefunction(dunder_call) return iscoroutinefunction(dunder_call)
async def call_asynchronously( async def call_asynchronously(
callable_: Union[Callable[_P, _T], Callable[_P, Awaitable[_T]]], callable_: Union[Callable[_P, _T], Callable[_P, Awaitable[_T]]],
*args: _P.args, *args: _P.args,
**kwargs: _P.kwargs **kwargs: _P.kwargs,
) -> _T: ) -> _T:
if _is_coroutine_callable(callable_): if _is_coroutine_callable(callable_):
return await callable_(*args, **kwargs) return await callable_(*args, **kwargs)

8
tests/test_lifespan_scoped_dependencies/test_dependency_overrides.py

@ -494,9 +494,7 @@ def test_override_lifespan_scoped_dependency_cannot_use_endpoint_scoped_paramete
router=app, router=app,
path="/test", path="/test",
is_websocket=is_websocket, is_websocket=is_websocket,
annotation=Annotated[ annotation=Annotated[None, Depends(dependency_func, scope="lifespan")],
None, Depends(dependency_func, scope="lifespan")
],
) )
with pytest.raises(DependencyScopeError): with pytest.raises(DependencyScopeError):
@ -567,9 +565,7 @@ def test_override_lifespan_scoped_dependency_cannot_use_endpoint_scoped_dependen
router=app, router=app,
path="/test", path="/test",
is_websocket=is_websocket, is_websocket=is_websocket,
annotation=Annotated[ annotation=Annotated[None, Depends(dependency_func, scope="lifespan")],
None, Depends(dependency_func, scope="lifespan")
],
) )
app.dependency_overrides[dependency_func] = override_dependency_func app.dependency_overrides[dependency_func] = override_dependency_func

12
tests/test_lifespan_scoped_dependencies/test_endpoint_usage.py

@ -453,9 +453,7 @@ def test_lifespan_scoped_dependency_cannot_use_endpoint_scoped_parameters(
router=app, router=app,
path="/test", path="/test",
is_websocket=is_websocket, is_websocket=is_websocket,
annotation=Annotated[ annotation=Annotated[None, Depends(dependency_func, scope="lifespan")],
None, Depends(dependency_func, scope="lifespan")
],
) )
@ -519,7 +517,9 @@ def test_the_same_dependency_can_work_in_different_scopes(
is_websocket=is_websocket, is_websocket=is_websocket,
annotation1=Annotated[ annotation1=Annotated[
int, int,
Depends(dependency_factory.get_dependency(), scope=endpoint_dependency_scope), Depends(
dependency_factory.get_dependency(), scope=endpoint_dependency_scope
),
], ],
annotation2=Annotated[ annotation2=Annotated[
int, int,
@ -659,9 +659,7 @@ def test_lifespan_scoped_dependency_cannot_use_endpoint_scoped_dependencies(
router=app, router=app,
path="/test", path="/test",
is_websocket=is_websocket, is_websocket=is_websocket,
annotation=Annotated[ annotation=Annotated[None, Depends(dependency_func, scope="lifespan")],
None, Depends(dependency_func, scope="lifespan")
],
) )

1
tests/test_params_repr.py

@ -1,6 +1,5 @@
from typing import Any, List from typing import Any, List
import pytest
from dirty_equals import IsOneOf from dirty_equals import IsOneOf
from fastapi.params import Body, Cookie, Header, Param, Path, Query from fastapi.params import Body, Cookie, Header, Param, Path, Query

Loading…
Cancel
Save