diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 84dfa4d03..8100a83cb 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -1,4 +1,5 @@ import inspect +import sys from contextlib import AsyncExitStack, contextmanager from copy import copy, deepcopy from dataclasses import dataclass @@ -229,7 +230,10 @@ def get_flat_params(dependant: Dependant) -> List[ModelField]: def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature: - signature = inspect.signature(call) + if sys.version_info >= (3, 10): + signature = inspect.signature(call, eval_str=True) + else: + signature = inspect.signature(call) globalns = getattr(call, "__globals__", {}) typed_params = [ inspect.Parameter( @@ -252,7 +256,10 @@ def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any: def get_typed_return_annotation(call: Callable[..., Any]) -> Any: - signature = inspect.signature(call) + if sys.version_info >= (3, 10): + signature = inspect.signature(call, eval_str=True) + else: + signature = inspect.signature(call) annotation = signature.return_annotation if annotation is inspect.Signature.empty: diff --git a/tests/test_future/__init__.py b/tests/test_future/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_future/login_tool.py b/tests/test_future/login_tool.py new file mode 100644 index 000000000..e522c7ec8 --- /dev/null +++ b/tests/test_future/login_tool.py @@ -0,0 +1,10 @@ +from functools import wraps + + +def login_required(func): + @wraps(func) + def wrapper(*args, **kwargs): + # login functionality could come here + return func(*args, **kwargs) + + return wrapper diff --git a/tests/test_future/test_future_6465.py b/tests/test_future/test_future_6465.py new file mode 100644 index 000000000..f300d6dc6 --- /dev/null +++ b/tests/test_future/test_future_6465.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from typing import Optional + +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + +from ..utils import needs_py310 +from .login_tool import login_required + +app = FastAPI() +client = TestClient(app) + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + + +@needs_py310 +def test_future_6465(): + @app.get("/items/") + @login_required + def get_item(item_id: int) -> Item: + return Item(name="name", price=42.42) + + res = client.get("/items?item_id=3") + assert res.status_code == 200 diff --git a/tests/test_future/test_future_9095.py b/tests/test_future/test_future_9095.py new file mode 100644 index 000000000..0f59fc7cf --- /dev/null +++ b/tests/test_future/test_future_9095.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +from fastapi import Depends, FastAPI +from fastapi.testclient import TestClient +from starlette.requests import Request + +from ..utils import needs_py310 + +app = FastAPI() + +client = TestClient(app) + + +class Test: + def __call__(self, request: Request): + return "test" + + +@needs_py310 +def test_call(): + @app.get("/test/") + def call(test: str = Depends(Test())): + return {"test": test} + + response = client.get("/test") + assert response.status_code == 200