Browse Source

Run performance tests only on Pydantic v2 (#14608)

pull/13988/merge
Sebastián Ramírez 7 months ago
committed by GitHub
parent
commit
34e884156f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 64
      tests/benchmarks/test_general_performance.py

64
tests/benchmarks/test_general_performance.py

@ -1,13 +1,12 @@
import json import json
import sys import sys
import warnings
from collections.abc import Iterator from collections.abc import Iterator
from typing import Annotated, Any from typing import Annotated, Any
import pytest import pytest
from fastapi import Depends, FastAPI from fastapi import Depends, FastAPI
from fastapi.exceptions import FastAPIDeprecationWarning
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from pydantic import BaseModel
if "--codspeed" not in sys.argv: if "--codspeed" not in sys.argv:
pytest.skip( pytest.skip(
@ -47,74 +46,57 @@ def dep_b(a: Annotated[int, Depends(dep_a)]):
return a + 2 return a + 2
@pytest.fixture( class ItemIn(BaseModel):
scope="module",
params=[
"pydantic-v2",
"pydantic-v1",
],
)
def basemodel_class(request: pytest.FixtureRequest) -> type[Any]:
if request.param == "pydantic-v2":
from pydantic import BaseModel
return BaseModel
else:
from pydantic.v1 import BaseModel
return BaseModel
@pytest.fixture(scope="module")
def app(basemodel_class: type[Any]) -> FastAPI:
class ItemIn(basemodel_class):
name: str name: str
value: int value: int
class ItemOut(basemodel_class):
class ItemOut(BaseModel):
name: str name: str
value: int value: int
dep: int dep: int
class LargeIn(basemodel_class):
class LargeIn(BaseModel):
items: list[dict[str, Any]] items: list[dict[str, Any]]
metadata: dict[str, Any] metadata: dict[str, Any]
class LargeOut(basemodel_class):
class LargeOut(BaseModel):
items: list[dict[str, Any]] items: list[dict[str, Any]]
metadata: dict[str, Any] metadata: dict[str, Any]
app = FastAPI() app = FastAPI()
with warnings.catch_warnings(record=True):
warnings.filterwarnings(
"ignore",
message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*",
category=FastAPIDeprecationWarning,
)
@app.post("/sync/validated", response_model=ItemOut) @app.post("/sync/validated", response_model=ItemOut)
def sync_validated(item: ItemIn, dep: Annotated[int, Depends(dep_b)]): def sync_validated(item: ItemIn, dep: Annotated[int, Depends(dep_b)]):
return ItemOut(name=item.name, value=item.value, dep=dep) return ItemOut(name=item.name, value=item.value, dep=dep)
@app.get("/sync/dict-no-response-model") @app.get("/sync/dict-no-response-model")
def sync_dict_no_response_model(): def sync_dict_no_response_model():
return {"name": "foo", "value": 123} return {"name": "foo", "value": 123}
@app.get("/sync/dict-with-response-model", response_model=ItemOut) @app.get("/sync/dict-with-response-model", response_model=ItemOut)
def sync_dict_with_response_model( def sync_dict_with_response_model(
dep: Annotated[int, Depends(dep_b)], dep: Annotated[int, Depends(dep_b)],
): ):
return {"name": "foo", "value": 123, "dep": dep} return {"name": "foo", "value": 123, "dep": dep}
@app.get("/sync/model-no-response-model") @app.get("/sync/model-no-response-model")
def sync_model_no_response_model(dep: Annotated[int, Depends(dep_b)]): def sync_model_no_response_model(dep: Annotated[int, Depends(dep_b)]):
return ItemOut(name="foo", value=123, dep=dep) return ItemOut(name="foo", value=123, dep=dep)
@app.get("/sync/model-with-response-model", response_model=ItemOut) @app.get("/sync/model-with-response-model", response_model=ItemOut)
def sync_model_with_response_model(dep: Annotated[int, Depends(dep_b)]): def sync_model_with_response_model(dep: Annotated[int, Depends(dep_b)]):
return ItemOut(name="foo", value=123, dep=dep) return ItemOut(name="foo", value=123, dep=dep)
@app.post("/async/validated", response_model=ItemOut) @app.post("/async/validated", response_model=ItemOut)
async def async_validated( async def async_validated(
item: ItemIn, item: ItemIn,
@ -122,73 +104,85 @@ def app(basemodel_class: type[Any]) -> FastAPI:
): ):
return ItemOut(name=item.name, value=item.value, dep=dep) return ItemOut(name=item.name, value=item.value, dep=dep)
@app.post("/sync/large-receive") @app.post("/sync/large-receive")
def sync_large_receive(payload: LargeIn): def sync_large_receive(payload: LargeIn):
return {"received": len(payload.items)} return {"received": len(payload.items)}
@app.post("/async/large-receive") @app.post("/async/large-receive")
async def async_large_receive(payload: LargeIn): async def async_large_receive(payload: LargeIn):
return {"received": len(payload.items)} return {"received": len(payload.items)}
@app.get("/sync/large-dict-no-response-model") @app.get("/sync/large-dict-no-response-model")
def sync_large_dict_no_response_model(): def sync_large_dict_no_response_model():
return LARGE_PAYLOAD return LARGE_PAYLOAD
@app.get("/sync/large-dict-with-response-model", response_model=LargeOut) @app.get("/sync/large-dict-with-response-model", response_model=LargeOut)
def sync_large_dict_with_response_model(): def sync_large_dict_with_response_model():
return LARGE_PAYLOAD return LARGE_PAYLOAD
@app.get("/sync/large-model-no-response-model") @app.get("/sync/large-model-no-response-model")
def sync_large_model_no_response_model(): def sync_large_model_no_response_model():
return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA) return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA)
@app.get("/sync/large-model-with-response-model", response_model=LargeOut) @app.get("/sync/large-model-with-response-model", response_model=LargeOut)
def sync_large_model_with_response_model(): def sync_large_model_with_response_model():
return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA) return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA)
@app.get("/async/large-dict-no-response-model") @app.get("/async/large-dict-no-response-model")
async def async_large_dict_no_response_model(): async def async_large_dict_no_response_model():
return LARGE_PAYLOAD return LARGE_PAYLOAD
@app.get("/async/large-dict-with-response-model", response_model=LargeOut) @app.get("/async/large-dict-with-response-model", response_model=LargeOut)
async def async_large_dict_with_response_model(): async def async_large_dict_with_response_model():
return LARGE_PAYLOAD return LARGE_PAYLOAD
@app.get("/async/large-model-no-response-model") @app.get("/async/large-model-no-response-model")
async def async_large_model_no_response_model(): async def async_large_model_no_response_model():
return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA) return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA)
@app.get("/async/large-model-with-response-model", response_model=LargeOut) @app.get("/async/large-model-with-response-model", response_model=LargeOut)
async def async_large_model_with_response_model(): async def async_large_model_with_response_model():
return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA) return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA)
@app.get("/async/dict-no-response-model") @app.get("/async/dict-no-response-model")
async def async_dict_no_response_model(): async def async_dict_no_response_model():
return {"name": "foo", "value": 123} return {"name": "foo", "value": 123}
@app.get("/async/dict-with-response-model", response_model=ItemOut) @app.get("/async/dict-with-response-model", response_model=ItemOut)
async def async_dict_with_response_model( async def async_dict_with_response_model(
dep: Annotated[int, Depends(dep_b)], dep: Annotated[int, Depends(dep_b)],
): ):
return {"name": "foo", "value": 123, "dep": dep} return {"name": "foo", "value": 123, "dep": dep}
@app.get("/async/model-no-response-model") @app.get("/async/model-no-response-model")
async def async_model_no_response_model( async def async_model_no_response_model(
dep: Annotated[int, Depends(dep_b)], dep: Annotated[int, Depends(dep_b)],
): ):
return ItemOut(name="foo", value=123, dep=dep) return ItemOut(name="foo", value=123, dep=dep)
@app.get("/async/model-with-response-model", response_model=ItemOut) @app.get("/async/model-with-response-model", response_model=ItemOut)
async def async_model_with_response_model( async def async_model_with_response_model(
dep: Annotated[int, Depends(dep_b)], dep: Annotated[int, Depends(dep_b)],
): ):
return ItemOut(name="foo", value=123, dep=dep) return ItemOut(name="foo", value=123, dep=dep)
return app
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def client(app: FastAPI) -> Iterator[TestClient]: def client() -> Iterator[TestClient]:
with TestClient(app) as client: with TestClient(app) as client:
yield client yield client

Loading…
Cancel
Save