From b32b4bfefb77112fb354d0be8d9442ab0df78ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 21 Dec 2025 16:24:11 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=87=20Filter=20warnings=20for=20tests?= =?UTF-8?q?=20with=20Pydantic=20v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_compat_params_v1.py | 187 ++++++------ tests/test_pydantic_v1_v2_01.py | 48 +-- tests/test_pydantic_v1_v2_list.py | 75 +++-- tests/test_pydantic_v1_v2_mixed.py | 315 ++++++++++---------- tests/test_pydantic_v1_v2_multifile/main.py | 217 +++++++------- tests/test_pydantic_v1_v2_noneable.py | 123 ++++---- 6 files changed, 483 insertions(+), 482 deletions(-) diff --git a/tests/test_compat_params_v1.py b/tests/test_compat_params_v1.py index b4ca861be..2ac96993a 100644 --- a/tests/test_compat_params_v1.py +++ b/tests/test_compat_params_v1.py @@ -1,4 +1,5 @@ import sys +import warnings from typing import Optional import pytest @@ -33,94 +34,90 @@ class Item(BaseModel): app = FastAPI() - -@app.get("/items/{item_id}") -def get_item_with_path( - item_id: Annotated[int, Path(title="The ID of the item", ge=1, le=1000)], -): - return {"item_id": item_id} - - -@app.get("/items/") -def get_items_with_query( - q: Annotated[ - Optional[str], Query(min_length=3, max_length=50, pattern="^[a-zA-Z0-9 ]+$") - ] = None, - skip: Annotated[int, Query(ge=0)] = 0, - limit: Annotated[int, Query(ge=1, le=100, examples=[5])] = 10, -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/users/") -def get_user_with_header( - x_custom: Annotated[Optional[str], Header()] = None, - x_token: Annotated[Optional[str], Header(convert_underscores=True)] = None, -): - return {"x_custom": x_custom, "x_token": x_token} - - -@app.get("/cookies/") -def get_cookies( - session_id: Annotated[Optional[str], Cookie()] = None, - tracking_id: Annotated[Optional[str], Cookie(min_length=10)] = None, -): - return {"session_id": session_id, "tracking_id": tracking_id} - - -@app.post("/items/") -def create_item( - item: Annotated[ - Item, - Body(examples=[{"name": "Foo", "price": 35.4, "description": "The Foo item"}]), - ], -): - return {"item": item} - - -@app.post("/items-embed/") -def create_item_embed( - item: Annotated[Item, Body(embed=True)], -): - return {"item": item} - - -@app.put("/items/{item_id}") -def update_item( - item_id: Annotated[int, Path(ge=1)], - item: Annotated[Item, Body()], - importance: Annotated[int, Body(gt=0, le=10)], -): - return {"item": item, "importance": importance} - - -@app.post("/form-data/") -def submit_form( - username: Annotated[str, Form(min_length=3, max_length=50)], - password: Annotated[str, Form(min_length=8)], - email: Annotated[Optional[str], Form()] = None, -): - return {"username": username, "password": password, "email": email} - - -@app.post("/upload/") -def upload_file( - file: Annotated[bytes, File()], - description: Annotated[Optional[str], Form()] = None, -): - return {"file_size": len(file), "description": description} - - -@app.post("/upload-multiple/") -def upload_multiple_files( - files: Annotated[list[bytes], File()], - note: Annotated[str, Form()] = "", -): - return { - "file_count": len(files), - "total_size": sum(len(f) for f in files), - "note": note, - } +with warnings.catch_warnings(record=True): + warnings.simplefilter("always") + + @app.get("/items/{item_id}") + def get_item_with_path( + item_id: Annotated[int, Path(title="The ID of the item", ge=1, le=1000)], + ): + return {"item_id": item_id} + + @app.get("/items/") + def get_items_with_query( + q: Annotated[ + Optional[str], + Query(min_length=3, max_length=50, pattern="^[a-zA-Z0-9 ]+$"), + ] = None, + skip: Annotated[int, Query(ge=0)] = 0, + limit: Annotated[int, Query(ge=1, le=100, examples=[5])] = 10, + ): + return {"q": q, "skip": skip, "limit": limit} + + @app.get("/users/") + def get_user_with_header( + x_custom: Annotated[Optional[str], Header()] = None, + x_token: Annotated[Optional[str], Header(convert_underscores=True)] = None, + ): + return {"x_custom": x_custom, "x_token": x_token} + + @app.get("/cookies/") + def get_cookies( + session_id: Annotated[Optional[str], Cookie()] = None, + tracking_id: Annotated[Optional[str], Cookie(min_length=10)] = None, + ): + return {"session_id": session_id, "tracking_id": tracking_id} + + @app.post("/items/") + def create_item( + item: Annotated[ + Item, + Body( + examples=[{"name": "Foo", "price": 35.4, "description": "The Foo item"}] + ), + ], + ): + return {"item": item} + + @app.post("/items-embed/") + def create_item_embed( + item: Annotated[Item, Body(embed=True)], + ): + return {"item": item} + + @app.put("/items/{item_id}") + def update_item( + item_id: Annotated[int, Path(ge=1)], + item: Annotated[Item, Body()], + importance: Annotated[int, Body(gt=0, le=10)], + ): + return {"item": item, "importance": importance} + + @app.post("/form-data/") + def submit_form( + username: Annotated[str, Form(min_length=3, max_length=50)], + password: Annotated[str, Form(min_length=8)], + email: Annotated[Optional[str], Form()] = None, + ): + return {"username": username, "password": password, "email": email} + + @app.post("/upload/") + def upload_file( + file: Annotated[bytes, File()], + description: Annotated[Optional[str], Form()] = None, + ): + return {"file_size": len(file), "description": description} + + @app.post("/upload-multiple/") + def upload_multiple_files( + files: Annotated[list[bytes], File()], + note: Annotated[str, Form()] = "", + ): + return { + "file_count": len(files), + "total_size": sum(len(f) for f in files), + "note": note, + } client = TestClient(app) @@ -211,10 +208,10 @@ def test_header_params_none(): # Cookie parameter tests def test_cookie_params(): - with TestClient(app) as client: - client.cookies.set("session_id", "abc123") - client.cookies.set("tracking_id", "1234567890abcdef") - response = client.get("/cookies/") + with TestClient(app) as test_client: + test_client.cookies.set("session_id", "abc123") + test_client.cookies.set("tracking_id", "1234567890abcdef") + response = test_client.get("/cookies/") assert response.status_code == 200 assert response.json() == { "session_id": "abc123", @@ -223,9 +220,9 @@ def test_cookie_params(): def test_cookie_tracking_id_too_short(): - with TestClient(app) as client: - client.cookies.set("tracking_id", "short") - response = client.get("/cookies/") + with TestClient(app) as test_client: + test_client.cookies.set("tracking_id", "short") + response = test_client.get("/cookies/") assert response.status_code == 422 assert response.json() == snapshot( { diff --git a/tests/test_pydantic_v1_v2_01.py b/tests/test_pydantic_v1_v2_01.py index 83536cafa..4868e5d22 100644 --- a/tests/test_pydantic_v1_v2_01.py +++ b/tests/test_pydantic_v1_v2_01.py @@ -1,4 +1,5 @@ import sys +import warnings from typing import Any, Union from tests.utils import skip_module_if_py_gte_314 @@ -26,30 +27,29 @@ class Item(BaseModel): app = FastAPI() - -@app.post("/simple-model") -def handle_simple_model(data: SubItem) -> SubItem: - return data - - -@app.post("/simple-model-filter", response_model=SubItem) -def handle_simple_model_filter(data: SubItem) -> Any: - extended_data = data.dict() - extended_data.update({"secret_price": 42}) - return extended_data - - -@app.post("/item") -def handle_item(data: Item) -> Item: - return data - - -@app.post("/item-filter", response_model=Item) -def handle_item_filter(data: Item) -> Any: - extended_data = data.dict() - extended_data.update({"secret_data": "classified", "internal_id": 12345}) - extended_data["sub"].update({"internal_id": 67890}) - return extended_data +with warnings.catch_warnings(record=True): + warnings.simplefilter("always") + + @app.post("/simple-model") + def handle_simple_model(data: SubItem) -> SubItem: + return data + + @app.post("/simple-model-filter", response_model=SubItem) + def handle_simple_model_filter(data: SubItem) -> Any: + extended_data = data.dict() + extended_data.update({"secret_price": 42}) + return extended_data + + @app.post("/item") + def handle_item(data: Item) -> Item: + return data + + @app.post("/item-filter", response_model=Item) + def handle_item_filter(data: Item) -> Any: + extended_data = data.dict() + extended_data.update({"secret_data": "classified", "internal_id": 12345}) + extended_data["sub"].update({"internal_id": 67890}) + return extended_data client = TestClient(app) diff --git a/tests/test_pydantic_v1_v2_list.py b/tests/test_pydantic_v1_v2_list.py index 4ddcbf240..108f231fa 100644 --- a/tests/test_pydantic_v1_v2_list.py +++ b/tests/test_pydantic_v1_v2_list.py @@ -1,4 +1,5 @@ import sys +import warnings from typing import Any, Union from tests.utils import skip_module_if_py_gte_314 @@ -27,49 +28,47 @@ class Item(BaseModel): app = FastAPI() -@app.post("/item") -def handle_item(data: Item) -> list[Item]: - return [data, data] +with warnings.catch_warnings(record=True): + warnings.simplefilter("always") + @app.post("/item") + def handle_item(data: Item) -> list[Item]: + return [data, data] -@app.post("/item-filter", response_model=list[Item]) -def handle_item_filter(data: Item) -> Any: - extended_data = data.dict() - extended_data.update({"secret_data": "classified", "internal_id": 12345}) - extended_data["sub"].update({"internal_id": 67890}) - return [extended_data, extended_data] - - -@app.post("/item-list") -def handle_item_list(data: list[Item]) -> Item: - if data: - return data[0] - return Item(title="", size=0, sub=SubItem(name="")) - - -@app.post("/item-list-filter", response_model=Item) -def handle_item_list_filter(data: list[Item]) -> Any: - if data: - extended_data = data[0].dict() - extended_data.update({"secret_data": "classified", "internal_id": 12345}) - extended_data["sub"].update({"internal_id": 67890}) - return extended_data - return Item(title="", size=0, sub=SubItem(name="")) - - -@app.post("/item-list-to-list") -def handle_item_list_to_list(data: list[Item]) -> list[Item]: - return data - - -@app.post("/item-list-to-list-filter", response_model=list[Item]) -def handle_item_list_to_list_filter(data: list[Item]) -> Any: - if data: - extended_data = data[0].dict() + @app.post("/item-filter", response_model=list[Item]) + def handle_item_filter(data: Item) -> Any: + extended_data = data.dict() extended_data.update({"secret_data": "classified", "internal_id": 12345}) extended_data["sub"].update({"internal_id": 67890}) return [extended_data, extended_data] - return [] + + @app.post("/item-list") + def handle_item_list(data: list[Item]) -> Item: + if data: + return data[0] + return Item(title="", size=0, sub=SubItem(name="")) + + @app.post("/item-list-filter", response_model=Item) + def handle_item_list_filter(data: list[Item]) -> Any: + if data: + extended_data = data[0].dict() + extended_data.update({"secret_data": "classified", "internal_id": 12345}) + extended_data["sub"].update({"internal_id": 67890}) + return extended_data + return Item(title="", size=0, sub=SubItem(name="")) + + @app.post("/item-list-to-list") + def handle_item_list_to_list(data: list[Item]) -> list[Item]: + return data + + @app.post("/item-list-to-list-filter", response_model=list[Item]) + def handle_item_list_to_list_filter(data: list[Item]) -> Any: + if data: + extended_data = data[0].dict() + extended_data.update({"secret_data": "classified", "internal_id": 12345}) + extended_data["sub"].update({"internal_id": 67890}) + return [extended_data, extended_data] + return [] client = TestClient(app) diff --git a/tests/test_pydantic_v1_v2_mixed.py b/tests/test_pydantic_v1_v2_mixed.py index 61e5bb582..895835a4c 100644 --- a/tests/test_pydantic_v1_v2_mixed.py +++ b/tests/test_pydantic_v1_v2_mixed.py @@ -1,4 +1,5 @@ import sys +import warnings from typing import Any, Union from tests.utils import skip_module_if_py_gte_314 @@ -39,179 +40,181 @@ class NewItem(NewBaseModel): app = FastAPI() +with warnings.catch_warnings(record=True): + warnings.simplefilter("always") -@app.post("/v1-to-v2/item") -def handle_v1_item_to_v2(data: Item) -> NewItem: - return NewItem( - new_title=data.title, - new_size=data.size, - new_description=data.description, - new_sub=NewSubItem(new_sub_name=data.sub.name), - new_multi=[NewSubItem(new_sub_name=s.name) for s in data.multi], - ) - - -@app.post("/v1-to-v2/item-filter", response_model=NewItem) -def handle_v1_item_to_v2_filter(data: Item) -> Any: - result = { - "new_title": data.title, - "new_size": data.size, - "new_description": data.description, - "new_sub": {"new_sub_name": data.sub.name, "new_sub_secret": "sub_hidden"}, - "new_multi": [ - {"new_sub_name": s.name, "new_sub_secret": "sub_hidden"} for s in data.multi - ], - "secret": "hidden_v1_to_v2", - } - return result - - -@app.post("/v2-to-v1/item") -def handle_v2_item_to_v1(data: NewItem) -> Item: - return Item( - title=data.new_title, - size=data.new_size, - description=data.new_description, - sub=SubItem(name=data.new_sub.new_sub_name), - multi=[SubItem(name=s.new_sub_name) for s in data.new_multi], - ) - - -@app.post("/v2-to-v1/item-filter", response_model=Item) -def handle_v2_item_to_v1_filter(data: NewItem) -> Any: - result = { - "title": data.new_title, - "size": data.new_size, - "description": data.new_description, - "sub": {"name": data.new_sub.new_sub_name, "sub_secret": "sub_hidden"}, - "multi": [ - {"name": s.new_sub_name, "sub_secret": "sub_hidden"} for s in data.new_multi - ], - "secret": "hidden_v2_to_v1", - } - return result - + @app.post("/v1-to-v2/item") + def handle_v1_item_to_v2(data: Item) -> NewItem: + return NewItem( + new_title=data.title, + new_size=data.size, + new_description=data.description, + new_sub=NewSubItem(new_sub_name=data.sub.name), + new_multi=[NewSubItem(new_sub_name=s.name) for s in data.multi], + ) -@app.post("/v1-to-v2/item-to-list") -def handle_v1_item_to_v2_list(data: Item) -> list[NewItem]: - converted = NewItem( - new_title=data.title, - new_size=data.size, - new_description=data.description, - new_sub=NewSubItem(new_sub_name=data.sub.name), - new_multi=[NewSubItem(new_sub_name=s.name) for s in data.multi], - ) - return [converted, converted] + @app.post("/v1-to-v2/item-filter", response_model=NewItem) + def handle_v1_item_to_v2_filter(data: Item) -> Any: + result = { + "new_title": data.title, + "new_size": data.size, + "new_description": data.description, + "new_sub": { + "new_sub_name": data.sub.name, + "new_sub_secret": "sub_hidden", + }, + "new_multi": [ + {"new_sub_name": s.name, "new_sub_secret": "sub_hidden"} + for s in data.multi + ], + "secret": "hidden_v1_to_v2", + } + return result + @app.post("/v2-to-v1/item") + def handle_v2_item_to_v1(data: NewItem) -> Item: + return Item( + title=data.new_title, + size=data.new_size, + description=data.new_description, + sub=SubItem(name=data.new_sub.new_sub_name), + multi=[SubItem(name=s.new_sub_name) for s in data.new_multi], + ) -@app.post("/v1-to-v2/list-to-list") -def handle_v1_list_to_v2_list(data: list[Item]) -> list[NewItem]: - result = [] - for item in data: - result.append( - NewItem( + @app.post("/v2-to-v1/item-filter", response_model=Item) + def handle_v2_item_to_v1_filter(data: NewItem) -> Any: + result = { + "title": data.new_title, + "size": data.new_size, + "description": data.new_description, + "sub": {"name": data.new_sub.new_sub_name, "sub_secret": "sub_hidden"}, + "multi": [ + {"name": s.new_sub_name, "sub_secret": "sub_hidden"} + for s in data.new_multi + ], + "secret": "hidden_v2_to_v1", + } + return result + + @app.post("/v1-to-v2/item-to-list") + def handle_v1_item_to_v2_list(data: Item) -> list[NewItem]: + converted = NewItem( + new_title=data.title, + new_size=data.size, + new_description=data.description, + new_sub=NewSubItem(new_sub_name=data.sub.name), + new_multi=[NewSubItem(new_sub_name=s.name) for s in data.multi], + ) + return [converted, converted] + + @app.post("/v1-to-v2/list-to-list") + def handle_v1_list_to_v2_list(data: list[Item]) -> list[NewItem]: + result = [] + for item in data: + result.append( + NewItem( + new_title=item.title, + new_size=item.size, + new_description=item.description, + new_sub=NewSubItem(new_sub_name=item.sub.name), + new_multi=[NewSubItem(new_sub_name=s.name) for s in item.multi], + ) + ) + return result + + @app.post("/v1-to-v2/list-to-list-filter", response_model=list[NewItem]) + def handle_v1_list_to_v2_list_filter(data: list[Item]) -> Any: + result = [] + for item in data: + converted = { + "new_title": item.title, + "new_size": item.size, + "new_description": item.description, + "new_sub": { + "new_sub_name": item.sub.name, + "new_sub_secret": "sub_hidden", + }, + "new_multi": [ + {"new_sub_name": s.name, "new_sub_secret": "sub_hidden"} + for s in item.multi + ], + "secret": "hidden_v2_to_v1", + } + result.append(converted) + return result + + @app.post("/v1-to-v2/list-to-item") + def handle_v1_list_to_v2_item(data: list[Item]) -> NewItem: + if data: + item = data[0] + return NewItem( new_title=item.title, new_size=item.size, new_description=item.description, new_sub=NewSubItem(new_sub_name=item.sub.name), new_multi=[NewSubItem(new_sub_name=s.name) for s in item.multi], ) + return NewItem(new_title="", new_size=0, new_sub=NewSubItem(new_sub_name="")) + + @app.post("/v2-to-v1/item-to-list") + def handle_v2_item_to_v1_list(data: NewItem) -> list[Item]: + converted = Item( + title=data.new_title, + size=data.new_size, + description=data.new_description, + sub=SubItem(name=data.new_sub.new_sub_name), + multi=[SubItem(name=s.new_sub_name) for s in data.new_multi], ) - return result - - -@app.post("/v1-to-v2/list-to-list-filter", response_model=list[NewItem]) -def handle_v1_list_to_v2_list_filter(data: list[Item]) -> Any: - result = [] - for item in data: - converted = { - "new_title": item.title, - "new_size": item.size, - "new_description": item.description, - "new_sub": {"new_sub_name": item.sub.name, "new_sub_secret": "sub_hidden"}, - "new_multi": [ - {"new_sub_name": s.name, "new_sub_secret": "sub_hidden"} - for s in item.multi - ], - "secret": "hidden_v2_to_v1", - } - result.append(converted) - return result - - -@app.post("/v1-to-v2/list-to-item") -def handle_v1_list_to_v2_item(data: list[Item]) -> NewItem: - if data: - item = data[0] - return NewItem( - new_title=item.title, - new_size=item.size, - new_description=item.description, - new_sub=NewSubItem(new_sub_name=item.sub.name), - new_multi=[NewSubItem(new_sub_name=s.name) for s in item.multi], - ) - return NewItem(new_title="", new_size=0, new_sub=NewSubItem(new_sub_name="")) - - -@app.post("/v2-to-v1/item-to-list") -def handle_v2_item_to_v1_list(data: NewItem) -> list[Item]: - converted = Item( - title=data.new_title, - size=data.new_size, - description=data.new_description, - sub=SubItem(name=data.new_sub.new_sub_name), - multi=[SubItem(name=s.new_sub_name) for s in data.new_multi], - ) - return [converted, converted] - - -@app.post("/v2-to-v1/list-to-list") -def handle_v2_list_to_v1_list(data: list[NewItem]) -> list[Item]: - result = [] - for item in data: - result.append( - Item( + return [converted, converted] + + @app.post("/v2-to-v1/list-to-list") + def handle_v2_list_to_v1_list(data: list[NewItem]) -> list[Item]: + result = [] + for item in data: + result.append( + Item( + title=item.new_title, + size=item.new_size, + description=item.new_description, + sub=SubItem(name=item.new_sub.new_sub_name), + multi=[SubItem(name=s.new_sub_name) for s in item.new_multi], + ) + ) + return result + + @app.post("/v2-to-v1/list-to-list-filter", response_model=list[Item]) + def handle_v2_list_to_v1_list_filter(data: list[NewItem]) -> Any: + result = [] + for item in data: + converted = { + "title": item.new_title, + "size": item.new_size, + "description": item.new_description, + "sub": { + "name": item.new_sub.new_sub_name, + "sub_secret": "sub_hidden", + }, + "multi": [ + {"name": s.new_sub_name, "sub_secret": "sub_hidden"} + for s in item.new_multi + ], + "secret": "hidden_v2_to_v1", + } + result.append(converted) + return result + + @app.post("/v2-to-v1/list-to-item") + def handle_v2_list_to_v1_item(data: list[NewItem]) -> Item: + if data: + item = data[0] + return Item( title=item.new_title, size=item.new_size, description=item.new_description, sub=SubItem(name=item.new_sub.new_sub_name), multi=[SubItem(name=s.new_sub_name) for s in item.new_multi], ) - ) - return result - - -@app.post("/v2-to-v1/list-to-list-filter", response_model=list[Item]) -def handle_v2_list_to_v1_list_filter(data: list[NewItem]) -> Any: - result = [] - for item in data: - converted = { - "title": item.new_title, - "size": item.new_size, - "description": item.new_description, - "sub": {"name": item.new_sub.new_sub_name, "sub_secret": "sub_hidden"}, - "multi": [ - {"name": s.new_sub_name, "sub_secret": "sub_hidden"} - for s in item.new_multi - ], - "secret": "hidden_v2_to_v1", - } - result.append(converted) - return result - - -@app.post("/v2-to-v1/list-to-item") -def handle_v2_list_to_v1_item(data: list[NewItem]) -> Item: - if data: - item = data[0] - return Item( - title=item.new_title, - size=item.new_size, - description=item.new_description, - sub=SubItem(name=item.new_sub.new_sub_name), - multi=[SubItem(name=s.new_sub_name) for s in item.new_multi], - ) - return Item(title="", size=0, sub=SubItem(name="")) + return Item(title="", size=0, sub=SubItem(name="")) client = TestClient(app) diff --git a/tests/test_pydantic_v1_v2_multifile/main.py b/tests/test_pydantic_v1_v2_multifile/main.py index 9397368ab..4180ec3bf 100644 --- a/tests/test_pydantic_v1_v2_multifile/main.py +++ b/tests/test_pydantic_v1_v2_multifile/main.py @@ -1,140 +1,137 @@ +import warnings + from fastapi import FastAPI from . import modelsv1, modelsv2, modelsv2b app = FastAPI() +with warnings.catch_warnings(record=True): + warnings.simplefilter("always") -@app.post("/v1-to-v2/item") -def handle_v1_item_to_v2(data: modelsv1.Item) -> modelsv2.Item: - return modelsv2.Item( - new_title=data.title, - new_size=data.size, - new_description=data.description, - new_sub=modelsv2.SubItem(new_sub_name=data.sub.name), - new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in data.multi], - ) - - -@app.post("/v2-to-v1/item") -def handle_v2_item_to_v1(data: modelsv2.Item) -> modelsv1.Item: - return modelsv1.Item( - title=data.new_title, - size=data.new_size, - description=data.new_description, - sub=modelsv1.SubItem(name=data.new_sub.new_sub_name), - multi=[modelsv1.SubItem(name=s.new_sub_name) for s in data.new_multi], - ) - + @app.post("/v1-to-v2/item") + def handle_v1_item_to_v2(data: modelsv1.Item) -> modelsv2.Item: + return modelsv2.Item( + new_title=data.title, + new_size=data.size, + new_description=data.description, + new_sub=modelsv2.SubItem(new_sub_name=data.sub.name), + new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in data.multi], + ) -@app.post("/v1-to-v2/item-to-list") -def handle_v1_item_to_v2_list(data: modelsv1.Item) -> list[modelsv2.Item]: - converted = modelsv2.Item( - new_title=data.title, - new_size=data.size, - new_description=data.description, - new_sub=modelsv2.SubItem(new_sub_name=data.sub.name), - new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in data.multi], - ) - return [converted, converted] + @app.post("/v2-to-v1/item") + def handle_v2_item_to_v1(data: modelsv2.Item) -> modelsv1.Item: + return modelsv1.Item( + title=data.new_title, + size=data.new_size, + description=data.new_description, + sub=modelsv1.SubItem(name=data.new_sub.new_sub_name), + multi=[modelsv1.SubItem(name=s.new_sub_name) for s in data.new_multi], + ) + @app.post("/v1-to-v2/item-to-list") + def handle_v1_item_to_v2_list(data: modelsv1.Item) -> list[modelsv2.Item]: + converted = modelsv2.Item( + new_title=data.title, + new_size=data.size, + new_description=data.description, + new_sub=modelsv2.SubItem(new_sub_name=data.sub.name), + new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in data.multi], + ) + return [converted, converted] + + @app.post("/v1-to-v2/list-to-list") + def handle_v1_list_to_v2_list(data: list[modelsv1.Item]) -> list[modelsv2.Item]: + result = [] + for item in data: + result.append( + modelsv2.Item( + new_title=item.title, + new_size=item.size, + new_description=item.description, + new_sub=modelsv2.SubItem(new_sub_name=item.sub.name), + new_multi=[ + modelsv2.SubItem(new_sub_name=s.name) for s in item.multi + ], + ) + ) + return result -@app.post("/v1-to-v2/list-to-list") -def handle_v1_list_to_v2_list(data: list[modelsv1.Item]) -> list[modelsv2.Item]: - result = [] - for item in data: - result.append( - modelsv2.Item( + @app.post("/v1-to-v2/list-to-item") + def handle_v1_list_to_v2_item(data: list[modelsv1.Item]) -> modelsv2.Item: + if data: + item = data[0] + return modelsv2.Item( new_title=item.title, new_size=item.size, new_description=item.description, new_sub=modelsv2.SubItem(new_sub_name=item.sub.name), new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in item.multi], ) - ) - return result - - -@app.post("/v1-to-v2/list-to-item") -def handle_v1_list_to_v2_item(data: list[modelsv1.Item]) -> modelsv2.Item: - if data: - item = data[0] return modelsv2.Item( - new_title=item.title, - new_size=item.size, - new_description=item.description, - new_sub=modelsv2.SubItem(new_sub_name=item.sub.name), - new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in item.multi], + new_title="", new_size=0, new_sub=modelsv2.SubItem(new_sub_name="") ) - return modelsv2.Item( - new_title="", new_size=0, new_sub=modelsv2.SubItem(new_sub_name="") - ) - - -@app.post("/v2-to-v1/item-to-list") -def handle_v2_item_to_v1_list(data: modelsv2.Item) -> list[modelsv1.Item]: - converted = modelsv1.Item( - title=data.new_title, - size=data.new_size, - description=data.new_description, - sub=modelsv1.SubItem(name=data.new_sub.new_sub_name), - multi=[modelsv1.SubItem(name=s.new_sub_name) for s in data.new_multi], - ) - return [converted, converted] + @app.post("/v2-to-v1/item-to-list") + def handle_v2_item_to_v1_list(data: modelsv2.Item) -> list[modelsv1.Item]: + converted = modelsv1.Item( + title=data.new_title, + size=data.new_size, + description=data.new_description, + sub=modelsv1.SubItem(name=data.new_sub.new_sub_name), + multi=[modelsv1.SubItem(name=s.new_sub_name) for s in data.new_multi], + ) + return [converted, converted] + + @app.post("/v2-to-v1/list-to-list") + def handle_v2_list_to_v1_list(data: list[modelsv2.Item]) -> list[modelsv1.Item]: + result = [] + for item in data: + result.append( + modelsv1.Item( + title=item.new_title, + size=item.new_size, + description=item.new_description, + sub=modelsv1.SubItem(name=item.new_sub.new_sub_name), + multi=[ + modelsv1.SubItem(name=s.new_sub_name) for s in item.new_multi + ], + ) + ) + return result -@app.post("/v2-to-v1/list-to-list") -def handle_v2_list_to_v1_list(data: list[modelsv2.Item]) -> list[modelsv1.Item]: - result = [] - for item in data: - result.append( - modelsv1.Item( + @app.post("/v2-to-v1/list-to-item") + def handle_v2_list_to_v1_item(data: list[modelsv2.Item]) -> modelsv1.Item: + if data: + item = data[0] + return modelsv1.Item( title=item.new_title, size=item.new_size, description=item.new_description, sub=modelsv1.SubItem(name=item.new_sub.new_sub_name), multi=[modelsv1.SubItem(name=s.new_sub_name) for s in item.new_multi], ) - ) - return result - + return modelsv1.Item(title="", size=0, sub=modelsv1.SubItem(name="")) -@app.post("/v2-to-v1/list-to-item") -def handle_v2_list_to_v1_item(data: list[modelsv2.Item]) -> modelsv1.Item: - if data: - item = data[0] + @app.post("/v2-to-v1/same-name") + def handle_v2_same_name_to_v1( + item1: modelsv2.Item, item2: modelsv2b.Item + ) -> modelsv1.Item: return modelsv1.Item( - title=item.new_title, - size=item.new_size, - description=item.new_description, - sub=modelsv1.SubItem(name=item.new_sub.new_sub_name), - multi=[modelsv1.SubItem(name=s.new_sub_name) for s in item.new_multi], + title=item1.new_title, + size=item2.dup_size, + description=item1.new_description, + sub=modelsv1.SubItem(name=item1.new_sub.new_sub_name), + multi=[modelsv1.SubItem(name=s.dup_sub_name) for s in item2.dup_multi], ) - return modelsv1.Item(title="", size=0, sub=modelsv1.SubItem(name="")) - - -@app.post("/v2-to-v1/same-name") -def handle_v2_same_name_to_v1( - item1: modelsv2.Item, item2: modelsv2b.Item -) -> modelsv1.Item: - return modelsv1.Item( - title=item1.new_title, - size=item2.dup_size, - description=item1.new_description, - sub=modelsv1.SubItem(name=item1.new_sub.new_sub_name), - multi=[modelsv1.SubItem(name=s.dup_sub_name) for s in item2.dup_multi], - ) - -@app.post("/v2-to-v1/list-of-items-to-list-of-items") -def handle_v2_items_in_list_to_v1_item_in_list( - data1: list[modelsv2.ItemInList], data2: list[modelsv2b.ItemInList] -) -> list[modelsv1.ItemInList]: - result = [] - item1 = data1[0] - item2 = data2[0] - result = [ - modelsv1.ItemInList(name1=item1.name2), - modelsv1.ItemInList(name1=item2.dup_name2), - ] - return result + @app.post("/v2-to-v1/list-of-items-to-list-of-items") + def handle_v2_items_in_list_to_v1_item_in_list( + data1: list[modelsv2.ItemInList], data2: list[modelsv2b.ItemInList] + ) -> list[modelsv1.ItemInList]: + item1 = data1[0] + item2 = data2[0] + return [ + modelsv1.ItemInList(name1=item1.name2), + modelsv1.ItemInList(name1=item2.dup_name2), + ] diff --git a/tests/test_pydantic_v1_v2_noneable.py b/tests/test_pydantic_v1_v2_noneable.py index 2cb6c3d6b..ba98b5653 100644 --- a/tests/test_pydantic_v1_v2_noneable.py +++ b/tests/test_pydantic_v1_v2_noneable.py @@ -1,4 +1,5 @@ import sys +import warnings from typing import Any, Union from tests.utils import skip_module_if_py_gte_314 @@ -39,65 +40,69 @@ class NewItem(NewBaseModel): app = FastAPI() - -@app.post("/v1-to-v2/") -def handle_v1_item_to_v2(data: Item) -> Union[NewItem, None]: - if data.size < 0: - return None - return NewItem( - new_title=data.title, - new_size=data.size, - new_description=data.description, - new_sub=NewSubItem(new_sub_name=data.sub.name), - new_multi=[NewSubItem(new_sub_name=s.name) for s in data.multi], - ) - - -@app.post("/v1-to-v2/item-filter", response_model=Union[NewItem, None]) -def handle_v1_item_to_v2_filter(data: Item) -> Any: - if data.size < 0: - return None - result = { - "new_title": data.title, - "new_size": data.size, - "new_description": data.description, - "new_sub": {"new_sub_name": data.sub.name, "new_sub_secret": "sub_hidden"}, - "new_multi": [ - {"new_sub_name": s.name, "new_sub_secret": "sub_hidden"} for s in data.multi - ], - "secret": "hidden_v1_to_v2", - } - return result - - -@app.post("/v2-to-v1/item") -def handle_v2_item_to_v1(data: NewItem) -> Union[Item, None]: - if data.new_size < 0: - return None - return Item( - title=data.new_title, - size=data.new_size, - description=data.new_description, - sub=SubItem(name=data.new_sub.new_sub_name), - multi=[SubItem(name=s.new_sub_name) for s in data.new_multi], - ) - - -@app.post("/v2-to-v1/item-filter", response_model=Union[Item, None]) -def handle_v2_item_to_v1_filter(data: NewItem) -> Any: - if data.new_size < 0: - return None - result = { - "title": data.new_title, - "size": data.new_size, - "description": data.new_description, - "sub": {"name": data.new_sub.new_sub_name, "sub_secret": "sub_hidden"}, - "multi": [ - {"name": s.new_sub_name, "sub_secret": "sub_hidden"} for s in data.new_multi - ], - "secret": "hidden_v2_to_v1", - } - return result +with warnings.catch_warnings(record=True): + warnings.simplefilter("always") + + @app.post("/v1-to-v2/") + def handle_v1_item_to_v2(data: Item) -> Union[NewItem, None]: + if data.size < 0: + return None + return NewItem( + new_title=data.title, + new_size=data.size, + new_description=data.description, + new_sub=NewSubItem(new_sub_name=data.sub.name), + new_multi=[NewSubItem(new_sub_name=s.name) for s in data.multi], + ) + + @app.post("/v1-to-v2/item-filter", response_model=Union[NewItem, None]) + def handle_v1_item_to_v2_filter(data: Item) -> Any: + if data.size < 0: + return None + result = { + "new_title": data.title, + "new_size": data.size, + "new_description": data.description, + "new_sub": { + "new_sub_name": data.sub.name, + "new_sub_secret": "sub_hidden", + }, + "new_multi": [ + {"new_sub_name": s.name, "new_sub_secret": "sub_hidden"} + for s in data.multi + ], + "secret": "hidden_v1_to_v2", + } + return result + + @app.post("/v2-to-v1/item") + def handle_v2_item_to_v1(data: NewItem) -> Union[Item, None]: + if data.new_size < 0: + return None + return Item( + title=data.new_title, + size=data.new_size, + description=data.new_description, + sub=SubItem(name=data.new_sub.new_sub_name), + multi=[SubItem(name=s.new_sub_name) for s in data.new_multi], + ) + + @app.post("/v2-to-v1/item-filter", response_model=Union[Item, None]) + def handle_v2_item_to_v1_filter(data: NewItem) -> Any: + if data.new_size < 0: + return None + result = { + "title": data.new_title, + "size": data.new_size, + "description": data.new_description, + "sub": {"name": data.new_sub.new_sub_name, "sub_secret": "sub_hidden"}, + "multi": [ + {"name": s.new_sub_name, "sub_secret": "sub_hidden"} + for s in data.new_multi + ], + "secret": "hidden_v2_to_v1", + } + return result client = TestClient(app)