Browse Source

Merge 7f85a410a3 into 6db05770f6

pull/10647/merge
Pastukhov Nikita 3 days ago
committed by GitHub
parent
commit
af9aebbde3
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 37
      fastapi/dependencies/utils.py
  2. 32
      tests/test_get_request_body.py

37
fastapi/dependencies/utils.py

@ -231,12 +231,17 @@ def get_flat_params(dependant: Dependant) -> List[ModelField]:
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
signature = inspect.signature(call)
globalns = getattr(call, "__globals__", {})
typed_params = [
inspect.Parameter(
name=param.name,
kind=param.kind,
default=param.default,
annotation=get_typed_annotation(param.annotation, globalns),
annotation=get_typed_annotation(
param.annotation,
globalns,
collect_outer_locals(),
),
)
for param in signature.parameters.values()
]
@ -244,10 +249,30 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
return typed_signature
def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:
def collect_outer_locals() -> Dict[str, Any]:
frame = inspect.currentframe()
locals = {}
finded = False
while frame is not None:
if finded:
locals.update(frame.f_locals)
# Find first FastAPI outer frame
if frame.f_code.co_name == "decorator":
finded = True
frame = frame.f_back
return locals
def get_typed_annotation(
annotation: Any, globalns: Dict[str, Any], localns: Dict[str, Any]
) -> Any:
if isinstance(annotation, str):
annotation = ForwardRef(annotation)
annotation = evaluate_forwardref(annotation, globalns, globalns)
annotation = evaluate_forwardref(annotation, globalns, localns)
return annotation
@ -259,7 +284,11 @@ def get_typed_return_annotation(call: Callable[..., Any]) -> Any:
return None
globalns = getattr(call, "__globals__", {})
return get_typed_annotation(annotation, globalns)
return get_typed_annotation(
annotation,
globalns,
collect_outer_locals(),
)
def get_dependant(

32
tests/test_get_request_body.py

@ -1,3 +1,7 @@
from __future__ import annotations
from typing import Any
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
@ -105,3 +109,31 @@ def test_openapi_schema():
}
},
}
def test_get_with_local_declared_body():
def wrap(application: FastAPI, *args: Any):
def wrapper(func):
return application.get(*args)(func)
return wrapper
def init_app() -> FastAPI:
application = FastAPI()
class LocalProduct(BaseModel):
name: str
description: str = None # type: ignore
price: float
@wrap(application, "/product")
async def create_item(product: LocalProduct) -> LocalProduct:
return product
return application
client = TestClient(init_app())
body = {"name": "Foo", "description": "Some description", "price": 5.5}
response = client.request("GET", "/product", json=body)
assert response.json() == body

Loading…
Cancel
Save