@ -302,6 +302,8 @@ def get_dependant(
own_oauth_scopes = own_oauth_scopes ,
own_oauth_scopes = own_oauth_scopes ,
parent_oauth_scopes = parent_oauth_scopes ,
parent_oauth_scopes = parent_oauth_scopes ,
)
)
unwrapped_call = inspect . unwrap ( call )
globalns = getattr ( unwrapped_call , " __globals__ " , { } )
current_scopes = ( parent_oauth_scopes or [ ] ) + ( own_oauth_scopes or [ ] )
current_scopes = ( parent_oauth_scopes or [ ] ) + ( own_oauth_scopes or [ ] )
path_param_names = get_path_param_names ( path )
path_param_names = get_path_param_names ( path )
endpoint_signature = get_typed_signature ( call )
endpoint_signature = get_typed_signature ( call )
@ -313,6 +315,7 @@ def get_dependant(
annotation = param . annotation ,
annotation = param . annotation ,
value = param . default ,
value = param . default ,
is_path_param = is_path_param ,
is_path_param = is_path_param ,
globalns = globalns ,
)
)
if param_details . depends is not None :
if param_details . depends is not None :
assert param_details . depends . dependency
assert param_details . depends . dependency
@ -396,6 +399,7 @@ def analyze_param(
annotation : Any ,
annotation : Any ,
value : Any ,
value : Any ,
is_path_param : bool ,
is_path_param : bool ,
globalns : dict [ str , Any ] | None = None ,
) - > ParamDetails :
) - > ParamDetails :
field_info = None
field_info = None
depends = None
depends = None
@ -407,10 +411,39 @@ def analyze_param(
if annotation is not inspect . Signature . empty :
if annotation is not inspect . Signature . empty :
use_annotation = annotation
use_annotation = annotation
type_annotation = annotation
type_annotation = annotation
# When ``from __future__ import annotations`` is active, the annotation
# may still be a ForwardRef (e.g. ``Annotated[Potato, Depends(...)]``
# where *Potato* hasn't been defined yet). The lenient evaluator leaves
# it as a ForwardRef because it cannot resolve *Potato*, but we still
# need to unpack the Annotated wrapper so that FastAPI-specific markers
# (Depends / Field / Body) are discovered. We use ``eval`` with a
# dict that turns undefined names into ForwardRef objects, which gives
# us the same partial-evaluation behaviour that the normal code-path
# expects.
if isinstance ( use_annotation , ForwardRef ) :
if globalns is not None :
try :
_safe_ns : dict [ str , Any ] = dict ( globalns )
_missing = ForwardRef # noqa: F811
class _SafeDict ( dict ) :
def __missing__ ( self , key ) : # type: ignore[override]
return _missing ( key )
use_annotation = eval (
use_annotation . __forward_arg__ , { " __builtins__ " : { } } , _SafeDict ( _safe_ns )
)
if use_annotation is not inspect . Signature . empty :
type_annotation = use_annotation
except Exception :
pass
# Extract Annotated info
# Extract Annotated info
if get_origin ( use_annotation ) is Annotated :
if get_origin ( use_annotation ) is Annotated :
annotated_args = get_args ( annotation )
annotated_args = get_args ( use_ annotation)
type_annotation = annotated_args [ 0 ]
type_annotation = annotated_args [ 0 ]
# Resolve forward references in the inner type (e.g. when using
# ``from __future__ import annotations`` with Annotated[..., Depends()])
if isinstance ( type_annotation , ( str , ForwardRef ) ) :
if globalns is not None :
type_annotation = get_typed_annotation ( type_annotation , globalns )
fastapi_annotations = [
fastapi_annotations = [
arg
arg
for arg in annotated_args [ 1 : ]
for arg in annotated_args [ 1 : ]