diff --git a/src/air/applications.py b/src/air/applications.py index a1e3fdfe1..d8ad1be79 100644 --- a/src/air/applications.py +++ b/src/air/applications.py @@ -270,6 +270,13 @@ def about(): This preserves most FastAPI initialization parameters while setting: - AirResponse as the default response class. - AirRoute as the default route class. + + Raises: + ValueError: If fastapi_app is None and kwargs contain parameters + that should be passed via fastapi_app instead. These + parameters are: default_response_class, on_startup, + on_shutdown, docs_url, redoc_url, openapi_url, + webhooks, deprecated. """ self.path_separator = path_separator if exception_handlers is None: @@ -290,6 +297,22 @@ def about(): # Create internal FastAPI instance if fastapi_app is None: + fastapi_kwargs_with_fixed_values = { + "default_response_class", + "on_startup", + "on_shutdown", + "docs_url", + "redoc_url", + "openapi_url", + "webhooks", + "deprecated", + } + + if kwargs_supplied := extra.keys() & fastapi_kwargs_with_fixed_values: + kwargs_supplied_str = ", ".join(sorted(f"`{kwarg}`" for kwarg in kwargs_supplied)) + msg = f"Use `fastapi_app` to pass {kwargs_supplied_str} instead." + raise ValueError(msg) + self._app = FastAPI( debug=debug, routes=routes, diff --git a/tests/test_applications.py b/tests/test_applications.py index 51bab27be..aebd3e80b 100644 --- a/tests/test_applications.py +++ b/tests/test_applications.py @@ -1,3 +1,4 @@ +import pytest from fastapi import Depends, FastAPI from fastapi.routing import APIRouter from fastapi.testclient import TestClient @@ -26,6 +27,13 @@ def page() -> air.H1: assert response.text == "

Hello, World!

" +def test_air_app_factory_rejects_fastapi_params() -> None: + # https://github.com/feldroy/air/issues/1073 + + with pytest.raises(ValueError, match=r"Use `fastapi_app` to pass `docs_url`, `redoc_url` instead."): + air.Air(docs_url="", redoc_url="") + + def test_air_plus_fastapi() -> None: app = FastAPI() html = air.Air()