Browse Source

Fixed some linting and python 3.8 compatibility issues.

pull/12529/head
Nir Schulman 8 months ago
parent
commit
c0ad39e073
  1. 3
      fastapi/dependencies/models.py
  2. 87
      fastapi/dependencies/utils.py
  3. 8
      fastapi/exceptions.py
  4. 3
      fastapi/lifespan.py
  5. 6
      fastapi/params.py
  6. 19
      fastapi/utils.py

3
fastapi/dependencies/models.py

@ -11,7 +11,7 @@ from fastapi.types import (
LifespanDependencyCacheKey,
DependencyScope,
LifespanDependencyScope,
EndpointDependencyScope
EndpointDependencyScope,
)
from typing_extensions import TypeAlias
@ -78,6 +78,7 @@ class LifespanDependant(_BaseDependant):
)
return self.caller, self.index
@dataclass
class EndpointDependant(_BaseDependant):
scope: EndpointDependencyScope = None

87
fastapi/dependencies/utils.py

@ -53,13 +53,25 @@ from fastapi.concurrency import (
asynccontextmanager,
contextmanager_in_threadpool,
)
from fastapi.dependencies.models import EndpointDependant, LifespanDependant, SecurityRequirement
from fastapi.exceptions import DependencyScopeError, InvalidDependencyScope, UninitializedLifespanDependency
from fastapi.dependencies.models import (
EndpointDependant,
LifespanDependant,
SecurityRequirement,
)
from fastapi.exceptions import (
DependencyScopeError,
InvalidDependencyScope,
UninitializedLifespanDependency,
)
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 EndpointDependencyCacheKey, LifespanDependencyCacheKey, LifespanDependencyScope
from fastapi.types import (
EndpointDependencyCacheKey,
LifespanDependencyCacheKey,
LifespanDependencyScope,
)
from fastapi.utils import create_model_field, get_path_param_names
from pydantic import BaseModel
from pydantic.fields import FieldInfo
@ -122,7 +134,7 @@ def ensure_multipart_is_installed() -> None:
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]:
assert callable(depends.dependency), (
"A parameter-less dependency must have a callable dependency"
@ -135,7 +147,7 @@ def get_parameterless_sub_dependant(
path=path,
call=depends.dependency,
security_scopes=use_security_scopes,
index=index
index=index,
)
elif depends.scope == "lifespan":
return get_lifespan_dependant(
@ -147,8 +159,7 @@ def get_parameterless_sub_dependant(
)
else:
raise InvalidDependencyScope(
f'Dependency "{index}" of {caller} has an invalid '
f'scope: "{depends.scope}"'
f'Dependency "{index}" of {caller} has an invalid scope: "{depends.scope}"'
)
@ -256,7 +267,12 @@ def get_lifespan_dependant(
dependency_signature = get_typed_signature(call)
signature_params = dependency_signature.parameters
dependant = LifespanDependant(
call=call, name=name, use_cache=use_cache, caller=caller, index=index, scope=scope
call=call,
name=name,
use_cache=use_cache,
caller=caller,
index=index,
scope=scope,
)
for param_name, param in signature_params.items():
param_details = analyze_param(
@ -269,7 +285,7 @@ def get_lifespan_dependant(
raise DependencyScopeError(
f'Dependency "{dependant.name}" has "{scope}" scope, but was defined'
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."
)
@ -277,7 +293,7 @@ def get_lifespan_dependant(
raise DependencyScopeError(
f'Dependency "{dependant.name}" has "{scope}" scope, but was defined with the '
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
@ -287,7 +303,7 @@ def get_lifespan_dependant(
call=param_details.depends.dependency,
use_cache=param_details.depends.use_cache,
caller=call,
scope=scope
scope=scope,
)
dependant.dependencies.append(sub_dependant)
@ -349,24 +365,28 @@ def get_endpoint_dependant(
if param_details.depends.scopes:
use_security_scopes.extend(param_details.depends.scopes)
if param_details.depends.scope == "lifespan":
dependant.lifespan_dependencies.append(get_lifespan_dependant(
caller=call,
call=param_details.depends.dependency,
name=param_name,
use_cache=param_details.depends.use_cache,
index=index,
scope=param_details.depends.scope
))
dependant.lifespan_dependencies.append(
get_lifespan_dependant(
caller=call,
call=param_details.depends.dependency,
name=param_name,
use_cache=param_details.depends.use_cache,
index=index,
scope=param_details.depends.scope,
)
)
elif param_details.depends.scope in ("request", "function", None):
dependant.endpoint_dependencies.append(get_endpoint_dependant(
path=path,
call=param_details.depends.dependency,
name=param_name,
security_scopes=use_security_scopes,
use_cache=param_details.depends.use_cache,
index=index,
scope=param_details.depends.scope
))
dependant.endpoint_dependencies.append(
get_endpoint_dependant(
path=path,
call=param_details.depends.dependency,
name=param_name,
security_scopes=use_security_scopes,
use_cache=param_details.depends.use_cache,
index=index,
scope=param_details.depends.scope,
)
)
else:
raise InvalidDependencyScope(
f'Dependency "{name}" of {call} has an invalid '
@ -628,7 +648,10 @@ def add_param_to_fields(*, field: ModelField, dependant: EndpointDependant) -> N
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:
assert dependant.call
if dependant.is_gen_callable:
@ -672,7 +695,7 @@ async def solve_lifespan_dependant(
name=dependant.name,
use_cache=dependant.use_cache,
index=dependant.index,
scope=dependant.scope
scope=dependant.scope,
)
dependency_arguments: Dict[str, Any] = {}
@ -691,7 +714,9 @@ async def solve_lifespan_dependant(
if dependant_to_solve.is_gen_callable or dependant_to_solve.is_async_gen_callable:
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:
value = await call(**dependency_arguments)

8
fastapi/exceptions.py

@ -146,31 +146,39 @@ class FastAPIError(RuntimeError):
A generic, FastAPI-specific error.
"""
class DependencyError(FastAPIError):
"""
A generic error regarding to dependencies.
"""
pass
class InvalidDependencyScope(DependencyError):
"""
A dependency was declared with an unsupported scope value.
"""
pass
class DependencyScopeError(DependencyError):
"""
A dependency declared that it depends on another dependency with an invalid
(narrower) scope.
"""
class UninitializedLifespanDependency(DependencyError):
"""
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.
"""
pass
class ValidationException(Exception):
def __init__(self, errors: Sequence[Any]) -> None:
self._errors = errors

3
fastapi/lifespan.py

@ -3,9 +3,10 @@ from __future__ import annotations
from contextlib import AsyncExitStack
from typing import TYPE_CHECKING, Any, Callable, Dict, List
from fastapi.dependencies.models import LifespanDependant, LifespanDependencyCacheKey
from fastapi.dependencies.models import LifespanDependant
from fastapi.dependencies.utils import solve_lifespan_dependant
from fastapi.routing import APIRoute, APIWebSocketRoute
from fastapi.types import LifespanDependencyCacheKey
if TYPE_CHECKING: # pragma: nocover
from fastapi import FastAPI

6
fastapi/params.py

@ -770,9 +770,11 @@ class Depends:
use_cache: bool = True
scope: DependencyScope = None
def __post_init__(self):
def __post_init__(self) -> 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

19
fastapi/utils.py

@ -2,7 +2,6 @@ import inspect
import re
import sys
import warnings
from collections.abc import Callable
from dataclasses import is_dataclass
from typing import (
TYPE_CHECKING,
@ -13,7 +12,10 @@ from typing import (
Set,
Type,
Union,
cast, Awaitable, TypeVar,
cast,
Awaitable,
TypeVar,
Callable,
)
from weakref import WeakKeyDictionary
@ -269,8 +271,8 @@ def get_value_or_default(
def _is_coroutine_callable(
callable_: Callable[..., Any]
) -> TypeIs[Callable[..., Awaitable[Any]]]:
callable_: Union[Callable[..., _T], Callable[..., Awaitable[_T]]],
) -> TypeIs[Callable[..., Awaitable[_T]]]:
if inspect.isroutine(callable_):
return iscoroutinefunction(callable_)
if inspect.isclass(callable_):
@ -278,12 +280,13 @@ def _is_coroutine_callable(
dunder_call = getattr(callable_, "__call__", None) # noqa: B004
return iscoroutinefunction(dunder_call)
async def call_asynchronously(
callable_: Union[Callable[_P, _T], Callable[_P, Awaitable[_T]]],
*args: _P.args,
**kwargs: _P.kwargs
callable_: Union[Callable[_P, _T], Callable[_P, Awaitable[_T]]],
*args: _P.args,
**kwargs: _P.kwargs,
) -> _T:
if _is_coroutine_callable(callable_):
return await callable_(*args, **kwargs)
else:
return await run_in_threadpool(callable_, *args, **kwargs)
return await run_in_threadpool(callable_, *args, **kwargs)

Loading…
Cancel
Save