Browse Source

Use lenient ForwardRef resolution as fallback

pull/15234/head
giria660 3 months ago
parent
commit
380c4161e4
No known key found for this signature in database GPG Key ID: 3D8290B3CD372BA4
  1. 14
      fastapi/dependencies/utils.py
  2. 20
      tests/test_dependencies_utils.py

14
fastapi/dependencies/utils.py

@ -245,19 +245,23 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
class _LenientTypeResolutionDict(dict[str, Any]): class _LenientTypeResolutionDict(dict[str, Any]):
def __missing__(self, key: str) -> Any: def __missing__(self, key: str) -> Any:
value = vars(builtins).get(key, ForwardRef(key)) return vars(builtins).get(key, ForwardRef(key))
self[key] = value
return value
def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any: def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any:
if isinstance(annotation, str): if isinstance(annotation, str):
annotation = ForwardRef(annotation) annotation = ForwardRef(annotation)
if isinstance(annotation, ForwardRef): if isinstance(annotation, ForwardRef):
lenient_globalns = _LenientTypeResolutionDict(globalns)
annotation = evaluate_forwardref( # ty: ignore[deprecated] annotation = evaluate_forwardref( # ty: ignore[deprecated]
annotation, lenient_globalns, lenient_globalns annotation, globalns, globalns
) )
if isinstance(annotation, ForwardRef):
try:
annotation = eval( # noqa: S307
annotation.__forward_arg__, _LenientTypeResolutionDict(globalns)
)
except Exception:
pass
if annotation is type(None): if annotation is type(None):
return None return None
return annotation return annotation

20
tests/test_dependencies_utils.py

@ -1,3 +1,6 @@
from typing import Annotated, ForwardRef, get_args, get_origin
from fastapi import Depends, params
from fastapi.dependencies.utils import get_typed_annotation from fastapi.dependencies.utils import get_typed_annotation
@ -6,3 +9,20 @@ def test_get_typed_annotation():
annotation = "None" annotation = "None"
typed_annotation = get_typed_annotation(annotation, globals()) typed_annotation = get_typed_annotation(annotation, globals())
assert typed_annotation is None assert typed_annotation is None
def test_get_typed_annotation_falls_back_to_lenient_forwardref_resolution():
def dependency() -> None:
return None
annotation = "Annotated[Potato, Depends(dependency)]"
typed_annotation = get_typed_annotation(
annotation,
{"Annotated": Annotated, "Depends": Depends, "dependency": dependency},
)
assert get_origin(typed_annotation) is Annotated
type_annotation, depends = get_args(typed_annotation)
assert isinstance(type_annotation, ForwardRef)
assert type_annotation.__forward_arg__ == "Potato"
assert isinstance(depends, params.Depends)

Loading…
Cancel
Save