From 3f2e378ff3d915f4c5660d192099ca122579464f Mon Sep 17 00:00:00 2001 From: Adarsh Bennur Date: Fri, 6 Feb 2026 22:42:15 +0530 Subject: [PATCH] Fix: Use typing_extensions.Annotated for Python 3.8 compatibility Changed import in tests/test_forms_fields_set.py from typing.Annotated to typing_extensions.Annotated to ensure tests run on Python 3.8. This fixes the Test / check CI failure and restores coverage to 100% by allowing the comprehensive coverage tests to execute on all Python versions in the CI matrix. --- tests/test_forms_fields_set.py | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/test_forms_fields_set.py b/tests/test_forms_fields_set.py index 9ad7d8c92f..164db98582 100644 --- a/tests/test_forms_fields_set.py +++ b/tests/test_forms_fields_set.py @@ -6,7 +6,7 @@ This test validates that Form models correctly track which fields were explicitly provided vs. which fields use defaults. """ -from typing import Annotated +from typing_extensions import Annotated from fastapi import FastAPI, Form, Header, Query from fastapi._compat import PYDANTIC_V2 @@ -14,7 +14,7 @@ from fastapi.testclient import TestClient from pydantic import BaseModel -class FormModelFieldsSet(BaseModel): +class FormModelFieldsSet(BaseModel) -> None: """Model for testing fields_set metadata preservation.""" field_1: bool = True @@ -26,7 +26,7 @@ app = FastAPI() @app.post("/form-fields-set") -async def form_fields_set_endpoint(model: Annotated[FormModelFieldsSet, Form()]): +async def form_fields_set_endpoint(model: Annotated[FormModelFieldsSet, Form()]) -> None: # Use correct attribute name for each Pydantic version if PYDANTIC_V2: fields_set = list(model.model_fields_set) @@ -39,7 +39,7 @@ async def form_fields_set_endpoint(model: Annotated[FormModelFieldsSet, Form()]) @app.post("/body-fields-set") -async def body_fields_set_endpoint(model: FormModelFieldsSet): +async def body_fields_set_endpoint(model: FormModelFieldsSet) -> None: # Use correct attribute name for each Pydantic version if PYDANTIC_V2: fields_set = list(model.model_fields_set) @@ -52,14 +52,14 @@ async def body_fields_set_endpoint(model: FormModelFieldsSet): def query_model( name: Annotated[str, Query()] = "query_default", age: Annotated[int, Query()] = 10, -): +) -> None: return {"name": name, "age": age} @app.get("/header/default") def header_model( x_token: Annotated[str, Header()] = "header_default", -): +) -> None: return {"x_token": x_token} @@ -69,35 +69,35 @@ client = TestClient(app) class TestFormFieldsSetMetadata: """Test that Form models correctly preserve fields_set metadata.""" - def test_form_empty_data_has_empty_fields_set(self): + def test_form_empty_data_has_empty_fields_set(self) -> None: """Form with no data should have empty fields_set (matching JSON behavior).""" resp = client.post("/form-fields-set", data={}) assert resp.status_code == 200, resp.text fields_set = resp.json()["fields_set"] assert fields_set == [] - def test_body_empty_data_has_empty_fields_set(self): + def test_body_empty_data_has_empty_fields_set(self) -> None: """JSON body with no data should have empty fields_set.""" resp = client.post("/body-fields-set", json={}) assert resp.status_code == 200, resp.text fields_set = resp.json()["fields_set"] assert fields_set == [] - def test_form_partial_data_tracks_provided_fields(self): + def test_form_partial_data_tracks_provided_fields(self) -> None: """Form with partial data should only show provided fields in fields_set.""" resp = client.post("/form-fields-set", data={"field_1": "False"}) assert resp.status_code == 200, resp.text fields_set = resp.json()["fields_set"] assert fields_set == ["field_1"] - def test_body_partial_data_tracks_provided_fields(self): + def test_body_partial_data_tracks_provided_fields(self) -> None: """JSON body with partial data should only show provided fields.""" resp = client.post("/body-fields-set", json={"field_1": False}) assert resp.status_code == 200, resp.text fields_set = resp.json()["fields_set"] assert fields_set == ["field_1"] - def test_form_all_fields_provided(self): + def test_form_all_fields_provided(self) -> None: """Form with all fields should show all fields in fields_set.""" resp = client.post( "/form-fields-set", @@ -107,7 +107,7 @@ class TestFormFieldsSetMetadata: fields_set = resp.json()["fields_set"] assert set(fields_set) == {"field_1", "field_2", "field_3"} - def test_body_all_fields_provided(self): + def test_body_all_fields_provided(self) -> None: """JSON body with all fields should show all fields in fields_set.""" resp = client.post( "/body-fields-set", @@ -117,7 +117,7 @@ class TestFormFieldsSetMetadata: fields_set = resp.json()["fields_set"] assert set(fields_set) == {"field_1", "field_2", "field_3"} - def test_form_field_set_to_default_value_is_tracked(self): + def test_form_field_set_to_default_value_is_tracked(self) -> None: """Form field explicitly set to default value should appear in fields_set.""" # Same as default=True, but explicitly provided resp = client.post("/form-fields-set", data={"field_1": "True"}) @@ -125,14 +125,14 @@ class TestFormFieldsSetMetadata: fields_set = resp.json()["fields_set"] assert fields_set == ["field_1"] - def test_body_field_set_to_default_value_is_tracked(self): + def test_body_field_set_to_default_value_is_tracked(self) -> None: """JSON body field explicitly set to default value should appear in fields_set.""" resp = client.post("/body-fields-set", json={"field_1": True}) assert resp.status_code == 200, resp.text fields_set = resp.json()["fields_set"] assert fields_set == ["field_1"] - def test_form_body_consistency(self): + def test_form_body_consistency(self) -> None: """ Verify that body and form behave consistently. Form fields_set should match JSON body fields_set for equivalent data. @@ -160,21 +160,21 @@ class TestNonFormCoverage: This ensures line 762 of utils.py is covered and legacy behavior is preserved. """ - def test_query_params_missing_uses_defaults(self): + def test_query_params_missing_uses_defaults(self) -> None: """Test Query input where fields are missing -> returns default.""" response = client.get("/query/default") assert response.status_code == 200 data = response.json() assert data == {"name": "query_default", "age": 10} - def test_header_params_missing_uses_defaults(self): + def test_header_params_missing_uses_defaults(self) -> None: """Test Header input where fields are missing -> returns default.""" response = client.get("/header/default") assert response.status_code == 200 data = response.json() assert data == {"x_token": "header_default"} - def test_query_params_provided(self): + def test_query_params_provided(self) -> None: """Test Query input where fields are provided -> returns value.""" response = client.get("/query/default?name=overridden&age=99") assert response.status_code == 200