]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🔊 Add a custom `FastAPIDeprecationWarning` (#14605)
authorSebastián Ramírez <tiangolo@gmail.com>
Fri, 26 Dec 2025 12:45:20 +0000 (04:45 -0800)
committerGitHub <noreply@github.com>
Fri, 26 Dec 2025 12:45:20 +0000 (12:45 +0000)
19 files changed:
fastapi/dependencies/utils.py
fastapi/exceptions.py
fastapi/openapi/utils.py
fastapi/params.py
fastapi/routing.py
fastapi/temp_pydantic_v1_params.py
fastapi/utils.py
tests/benchmarks/test_general_performance.py
tests/test_compat_params_v1.py
tests/test_pydantic_v1_deprecation_warnings.py
tests/test_regex_deprecated_body.py
tests/test_regex_deprecated_params.py
tests/test_schema_extra_examples.py
tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial002.py
tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial003.py
tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial004.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py
tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py
tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py

index 39d0bd89cd42358be811855fd80359e85cfa64ce..af2bed9ad996c451f996bf3fd8e9fdcba5b00014 100644 (file)
@@ -51,7 +51,7 @@ from fastapi.concurrency import (
     contextmanager_in_threadpool,
 )
 from fastapi.dependencies.models import Dependant
-from fastapi.exceptions import DependencyScopeError
+from fastapi.exceptions import DependencyScopeError, FastAPIDeprecationWarning
 from fastapi.logger import logger
 from fastapi.security.oauth2 import SecurityScopes
 from fastapi.types import DependencyCacheKey
@@ -327,7 +327,7 @@ def get_dependant(
             warnings.warn(
                 "pydantic.v1 is deprecated and will soon stop being supported by FastAPI."
                 f" Please update the param {param_name}: {param_details.type_annotation!r}.",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=5,
             )
         if isinstance(
index 8e0c55902306b2d2445a84d61a104ec1a87ab17e..53e5052818eb0dde47d71f52bc0152c0d89f54a5 100644 (file)
@@ -231,3 +231,10 @@ class ResponseValidationError(ValidationException):
     ) -> None:
         super().__init__(errors, endpoint_ctx=endpoint_ctx)
         self.body = body
+
+
+class FastAPIDeprecationWarning(UserWarning):
+    """
+    A custom deprecation warning as DeprecationWarning is ignored
+    Ref: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries
+    """
index a99d4188e75f2d84b22ddcb4d6e7fbf14ab6cc53..6180fcde6aa10de589d7397e22f0ac29de462d15 100644 (file)
@@ -23,6 +23,7 @@ from fastapi.dependencies.utils import (
     get_validation_alias,
 )
 from fastapi.encoders import jsonable_encoder
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX
 from fastapi.openapi.models import OpenAPI
 from fastapi.params import Body, ParamTypes
@@ -215,9 +216,9 @@ def generate_operation_id(
     *, route: routing.APIRoute, method: str
 ) -> str:  # pragma: nocover
     warnings.warn(
-        "fastapi.openapi.utils.generate_operation_id() was deprecated, "
+        message="fastapi.openapi.utils.generate_operation_id() was deprecated, "
         "it is not used internally, and will be removed soon",
-        DeprecationWarning,
+        category=FastAPIDeprecationWarning,
         stacklevel=2,
     )
     if route.operation_id:
index c776c4a59efebcabc4b74315f74917ba0a95dbf6..cc2934f44d8b1b7b6742c019df0533f7be021a97 100644 (file)
@@ -4,6 +4,7 @@ from dataclasses import dataclass
 from enum import Enum
 from typing import Annotated, Any, Callable, Optional, Union
 
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.openapi.models import Example
 from pydantic.fields import FieldInfo
 from typing_extensions import Literal, deprecated
@@ -75,7 +76,7 @@ class Param(FieldInfo):  # type: ignore[misc]
         if example is not _Unset:
             warnings.warn(
                 "`example` has been deprecated, please use `examples` instead",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=4,
             )
         self.example = example
@@ -105,7 +106,7 @@ class Param(FieldInfo):  # type: ignore[misc]
         if regex is not None:
             warnings.warn(
                 "`regex` has been deprecated, please use `pattern` instead",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=4,
             )
         current_json_schema_extra = json_schema_extra or extra
@@ -530,7 +531,7 @@ class Body(FieldInfo):  # type: ignore[misc]
         if example is not _Unset:
             warnings.warn(
                 "`example` has been deprecated, please use `examples` instead",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=4,
             )
         self.example = example
@@ -560,7 +561,7 @@ class Body(FieldInfo):  # type: ignore[misc]
         if regex is not None:
             warnings.warn(
                 "`regex` has been deprecated, please use `pattern` instead",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=4,
             )
         current_json_schema_extra = json_schema_extra or extra
index 2770e3253dacce9a7143de3135826727e4f27061..3f78e93e84c7f8700e5260b27e536ecd3b3994dd 100644 (file)
@@ -47,6 +47,7 @@ from fastapi.dependencies.utils import (
 from fastapi.encoders import jsonable_encoder
 from fastapi.exceptions import (
     EndpointContext,
+    FastAPIDeprecationWarning,
     FastAPIError,
     RequestValidationError,
     ResponseValidationError,
@@ -640,7 +641,7 @@ class APIRoute(routing.Route):
                 warnings.warn(
                     "pydantic.v1 is deprecated and will soon stop being supported by FastAPI."
                     f" Please update the response model {self.response_model!r}.",
-                    category=DeprecationWarning,
+                    category=FastAPIDeprecationWarning,
                     stacklevel=4,
                 )
             self.response_field = create_model_field(
@@ -680,7 +681,7 @@ class APIRoute(routing.Route):
                     warnings.warn(
                         "pydantic.v1 is deprecated and will soon stop being supported by FastAPI."
                         f" In responses={{}}, please update {model}.",
-                        category=DeprecationWarning,
+                        category=FastAPIDeprecationWarning,
                         stacklevel=4,
                     )
                 response_field = create_model_field(
index 1bda0ea9b2ad329eff4859a804f3364cb970f6f5..62230e42cfbce4b6b3079a10725191db7124d7c1 100644 (file)
@@ -1,6 +1,7 @@
 import warnings
 from typing import Annotated, Any, Callable, Optional, Union
 
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.openapi.models import Example
 from fastapi.params import ParamTypes
 from typing_extensions import deprecated
@@ -63,7 +64,7 @@ class Param(FieldInfo):
         if example is not _Unset:
             warnings.warn(
                 "`example` has been deprecated, please use `examples` instead",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=4,
             )
         self.example = example
@@ -93,7 +94,7 @@ class Param(FieldInfo):
         if regex is not None:
             warnings.warn(
                 "`regex` has been deprecated, please use `pattern` instead",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=4,
             )
         current_json_schema_extra = json_schema_extra or extra
@@ -503,7 +504,7 @@ class Body(FieldInfo):
         if example is not _Unset:
             warnings.warn(
                 "`example` has been deprecated, please use `examples` instead",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=4,
             )
         self.example = example
@@ -533,7 +534,7 @@ class Body(FieldInfo):
         if regex is not None:
             warnings.warn(
                 "`regex` has been deprecated, please use `pattern` instead",
-                category=DeprecationWarning,
+                category=FastAPIDeprecationWarning,
                 stacklevel=4,
             )
         current_json_schema_extra = json_schema_extra or extra
index c4631d7ed224e7393faa816f2808a48a7b6f681d..8ae50aa145a1d81529b423f06522429c0f75acf0 100644 (file)
@@ -23,6 +23,7 @@ from fastapi._compat import (
     may_v1,
 )
 from fastapi.datastructures import DefaultPlaceholder, DefaultType
+from fastapi.exceptions import FastAPIDeprecationWarning
 from pydantic import BaseModel
 from pydantic.fields import FieldInfo
 from typing_extensions import Literal
@@ -195,9 +196,9 @@ def generate_operation_id_for_path(
     *, name: str, path: str, method: str
 ) -> str:  # pragma: nocover
     warnings.warn(
-        "fastapi.utils.generate_operation_id_for_path() was deprecated, "
+        message="fastapi.utils.generate_operation_id_for_path() was deprecated, "
         "it is not used internally, and will be removed soon",
-        DeprecationWarning,
+        category=FastAPIDeprecationWarning,
         stacklevel=2,
     )
     operation_id = f"{name}{path}"
index 2da74b95c57300e08f636884b7208b9e4ba295b8..dac297e4ed50117eb8b511bf4a8ca03fdc6890f1 100644 (file)
@@ -6,6 +6,7 @@ from typing import Annotated, Any
 
 import pytest
 from fastapi import Depends, FastAPI
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.testclient import TestClient
 
 if "--codspeed" not in sys.argv:
@@ -89,7 +90,7 @@ def app(basemodel_class: type[Any]) -> FastAPI:
         warnings.filterwarnings(
             "ignore",
             message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*",
-            category=DeprecationWarning,
+            category=FastAPIDeprecationWarning,
         )
 
         @app.post("/sync/validated", response_model=ItemOut)
index 2ac96993a86a6a47e52fa1053cd923d0dfa44c02..704b3f77a6d32338263309de49e5a1e67bc4d0bc 100644 (file)
@@ -3,6 +3,7 @@ import warnings
 from typing import Optional
 
 import pytest
+from fastapi.exceptions import FastAPIDeprecationWarning
 
 from tests.utils import skip_module_if_py_gte_314
 
@@ -504,23 +505,23 @@ def test_body_repr():
 
 # Deprecation warning tests for regex parameter
 def test_query_regex_deprecation_warning():
-    with pytest.warns(DeprecationWarning, match="`regex` has been deprecated"):
+    with pytest.warns(FastAPIDeprecationWarning, match="`regex` has been deprecated"):
         Query(regex="^test$")
 
 
 def test_body_regex_deprecation_warning():
-    with pytest.warns(DeprecationWarning, match="`regex` has been deprecated"):
+    with pytest.warns(FastAPIDeprecationWarning, match="`regex` has been deprecated"):
         Body(regex="^test$")
 
 
 # Deprecation warning tests for example parameter
 def test_query_example_deprecation_warning():
-    with pytest.warns(DeprecationWarning, match="`example` has been deprecated"):
+    with pytest.warns(FastAPIDeprecationWarning, match="`example` has been deprecated"):
         Query(example="test example")
 
 
 def test_body_example_deprecation_warning():
-    with pytest.warns(DeprecationWarning, match="`example` has been deprecated"):
+    with pytest.warns(FastAPIDeprecationWarning, match="`example` has been deprecated"):
         Body(example={"test": "example"})
 
 
index e0008e2183fe748e4dd07d9230a5e41c7ba2d5d1..89ca6a8658b724815ba27d7b0c8a89c691ed445c 100644 (file)
@@ -1,6 +1,7 @@
 import sys
 
 import pytest
+from fastapi.exceptions import FastAPIDeprecationWarning
 
 from tests.utils import skip_module_if_py_gte_314
 
@@ -19,7 +20,7 @@ def test_warns_pydantic_v1_model_in_endpoint_param() -> None:
     app = FastAPI()
 
     with pytest.warns(
-        DeprecationWarning,
+        FastAPIDeprecationWarning,
         match=r"pydantic\.v1 is deprecated.*Please update the param data:",
     ):
 
@@ -40,7 +41,7 @@ def test_warns_pydantic_v1_model_in_return_type() -> None:
     app = FastAPI()
 
     with pytest.warns(
-        DeprecationWarning,
+        FastAPIDeprecationWarning,
         match=r"pydantic\.v1 is deprecated.*Please update the response model",
     ):
 
@@ -61,7 +62,7 @@ def test_warns_pydantic_v1_model_in_response_model() -> None:
     app = FastAPI()
 
     with pytest.warns(
-        DeprecationWarning,
+        FastAPIDeprecationWarning,
         match=r"pydantic\.v1 is deprecated.*Please update the response model",
     ):
 
@@ -82,7 +83,7 @@ def test_warns_pydantic_v1_model_in_additional_responses_model() -> None:
     app = FastAPI()
 
     with pytest.warns(
-        DeprecationWarning,
+        FastAPIDeprecationWarning,
         match=r"pydantic\.v1 is deprecated.*In responses=\{\}, please update",
     ):
 
index cfbff19c87a86c7f340566e1b498d019bb3a0d4b..9d58c5dae17224fff25a9f2c9a0abe967d69693b 100644 (file)
@@ -3,6 +3,7 @@ from typing import Annotated
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Form
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.testclient import TestClient
 
 from .utils import needs_py310
@@ -10,7 +11,7 @@ from .utils import needs_py310
 
 def get_client():
     app = FastAPI()
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.post("/items/")
         async def read_items(
index 7d9988f9f8f6eec00fd0ea6816d8b2be6282f871..8973657a9034c64f2cbd666fef6c094df2cee426 100644 (file)
@@ -3,6 +3,7 @@ from typing import Annotated
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Query
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.testclient import TestClient
 
 from .utils import needs_py310
@@ -10,7 +11,7 @@ from .utils import needs_py310
 
 def get_client():
     app = FastAPI()
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/items/")
         async def read_items(
index 176b5588d7e5d03cc72ba7c80c3bc7d783550865..8f5195ba11001f34ed5ce37438c36a045a29cd81 100644 (file)
@@ -3,6 +3,7 @@ from typing import Union
 import pytest
 from dirty_equals import IsDict
 from fastapi import Body, Cookie, FastAPI, Header, Path, Query
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, ConfigDict
 
@@ -21,7 +22,7 @@ def create_app():
     def schema_extra(item: Item):
         return item
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.post("/example/")
         def example(item: Item = Body(example={"data": "Data in Body example"})):
@@ -38,7 +39,7 @@ def create_app():
     ):
         return item
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.post("/example_examples/")
         def example_examples(
@@ -83,7 +84,7 @@ def create_app():
     # ):
     #     return lastname
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/path_example/{item_id}")
         def path_example(
@@ -101,7 +102,7 @@ def create_app():
     ):
         return item_id
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/path_example_examples/{item_id}")
         def path_example_examples(
@@ -112,7 +113,7 @@ def create_app():
         ):
             return item_id
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/query_example/")
         def query_example(
@@ -132,7 +133,7 @@ def create_app():
     ):
         return data
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/query_example_examples/")
         def query_example_examples(
@@ -144,7 +145,7 @@ def create_app():
         ):
             return data
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/header_example/")
         def header_example(
@@ -167,7 +168,7 @@ def create_app():
     ):
         return data
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/header_example_examples/")
         def header_example_examples(
@@ -179,7 +180,7 @@ def create_app():
         ):
             return data
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/cookie_example/")
         def cookie_example(
@@ -199,7 +200,7 @@ def create_app():
     ):
         return data
 
-    with pytest.warns(DeprecationWarning):
+    with pytest.warns(FastAPIDeprecationWarning):
 
         @app.get("/cookie_example_examples/")
         def cookie_example_examples(
index ab7e1d8a772b83a9f282dc134063238313a6cd78..9d1baf853046a3f3cae2e1e5e29d5ac40fd6b81c 100644 (file)
@@ -2,6 +2,7 @@ import sys
 import warnings
 
 import pytest
+from fastapi.exceptions import FastAPIDeprecationWarning
 from inline_snapshot import snapshot
 
 from tests.utils import skip_module_if_py_gte_314
@@ -29,7 +30,7 @@ def get_client(request: pytest.FixtureRequest):
         warnings.filterwarnings(
             "ignore",
             message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*",
-            category=DeprecationWarning,
+            category=FastAPIDeprecationWarning,
         )
         mod = importlib.import_module(f"docs_src.pydantic_v1_in_v2.{request.param}")
 
index c45e04248472022f411279853c7d6df86140e3c5..23b236888de8bf77a2873614db12ddb0e4773097 100644 (file)
@@ -2,6 +2,7 @@ import sys
 import warnings
 
 import pytest
+from fastapi.exceptions import FastAPIDeprecationWarning
 from inline_snapshot import snapshot
 
 from tests.utils import skip_module_if_py_gte_314
@@ -29,7 +30,7 @@ def get_client(request: pytest.FixtureRequest):
         warnings.filterwarnings(
             "ignore",
             message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*",
-            category=DeprecationWarning,
+            category=FastAPIDeprecationWarning,
         )
         mod = importlib.import_module(f"docs_src.pydantic_v1_in_v2.{request.param}")
 
index f3da849e040a49913fb0a600983cbfa13138cbc3..61c0f6357150cd66fbcbfcbd33b26f575f213298 100644 (file)
@@ -2,6 +2,7 @@ import sys
 import warnings
 
 import pytest
+from fastapi.exceptions import FastAPIDeprecationWarning
 from inline_snapshot import snapshot
 
 from tests.utils import skip_module_if_py_gte_314
@@ -29,7 +30,7 @@ def get_client(request: pytest.FixtureRequest):
         warnings.filterwarnings(
             "ignore",
             message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*",
-            category=DeprecationWarning,
+            category=FastAPIDeprecationWarning,
         )
         mod = importlib.import_module(f"docs_src.pydantic_v1_in_v2.{request.param}")
 
index 95efab2dc7530d895d21fb570e75cf2ebb245288..585989a8275403be86d7a1df1cef650c708c2324 100644 (file)
@@ -18,7 +18,7 @@ from ...utils import needs_py310
             marks=(
                 needs_py310,
                 pytest.mark.filterwarnings(
-                    "ignore:`regex` has been deprecated, please use `pattern` instead:DeprecationWarning"
+                    "ignore:`regex` has been deprecated, please use `pattern` instead:fastapi.exceptions.FastAPIDeprecationWarning"
                 ),
             ),
         ),
index 515a5a8d786c6ed5daa4948f21784d5c50d5d635..50be458962b8973e9868c516023517380b5ca5d8 100644 (file)
@@ -2,6 +2,7 @@ import importlib
 import warnings
 
 import pytest
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.testclient import TestClient
 
 from ...utils import needs_pydanticv1
@@ -19,7 +20,7 @@ def get_client(request: pytest.FixtureRequest):
         warnings.filterwarnings(
             "ignore",
             message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*",
-            category=DeprecationWarning,
+            category=FastAPIDeprecationWarning,
         )
         mod = importlib.import_module(f"docs_src.request_form_models.{request.param}")
 
index c5526b19cd26acb513425e80f32c2f9b04b183ae..83c71765679e52ab6846778ab4ab82f51ec3ca90 100644 (file)
@@ -2,6 +2,7 @@ import importlib
 import warnings
 
 import pytest
+from fastapi.exceptions import FastAPIDeprecationWarning
 from fastapi.testclient import TestClient
 from inline_snapshot import snapshot
 
@@ -20,7 +21,7 @@ def get_client(request: pytest.FixtureRequest):
         warnings.filterwarnings(
             "ignore",
             message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*",
-            category=DeprecationWarning,
+            category=FastAPIDeprecationWarning,
         )
         mod = importlib.import_module(f"docs_src.schema_extra_example.{request.param}")