diff --git a/src/fastapi_cli/discover.py b/src/fastapi_cli/discover.py index 3d49f72d..06f4e8bf 100644 --- a/src/fastapi_cli/discover.py +++ b/src/fastapi_cli/discover.py @@ -77,25 +77,24 @@ def get_app_name(*, mod_data: ModuleData, app_name: str | None = None) -> str: raise FastAPICLIException( "Could not import FastAPI, try running 'pip install fastapi'" ) from None - object_names = dir(mod) - object_names_set = set(object_names) if app_name: - if app_name not in object_names_set: + app = getattr(mod, app_name, None) + if app is None: raise FastAPICLIException( f"Could not find app name {app_name} in {mod_data.module_import_str}" ) - app = getattr(mod, app_name) if not isinstance(app, FastAPI): raise FastAPICLIException( f"The app name {app_name} in {mod_data.module_import_str} doesn't seem to be a FastAPI app" ) return app_name - for preferred_name in ["app", "api"]: - if preferred_name in object_names_set: - obj = getattr(mod, preferred_name) - if isinstance(obj, FastAPI): - return preferred_name - for name in object_names: + for preferred_name in ("app", "api"): + obj = getattr(mod, preferred_name, None) + if isinstance(obj, FastAPI): + return preferred_name + for name in dir(mod): + if name in ("app", "api"): + continue obj = getattr(mod, name) if isinstance(obj, FastAPI): return name diff --git a/tests/assets/single_file_non_app.py b/tests/assets/single_file_non_app.py new file mode 100644 index 00000000..e0acad08 --- /dev/null +++ b/tests/assets/single_file_non_app.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI + +app = "not a FastAPI instance" +api = 42 + +my_app = FastAPI() + + +@my_app.get("/") +def my_app_root(): + return {"message": "my_app"} diff --git a/tests/test_utils_single_file.py b/tests/test_utils_single_file.py index da8eba1c..2576a2d7 100644 --- a/tests/test_utils_single_file.py +++ b/tests/test_utils_single_file.py @@ -53,6 +53,17 @@ def test_single_file_explicit_object(capsys: CaptureFixture[str]) -> None: assert import_data.module_data.module_import_str == "single_file_app" +def test_single_file_non_fastapi_app_and_api(capsys: CaptureFixture[str]) -> None: + """Fallback walks past non-FastAPI `app`/`api` names to find the real app.""" + with changing_dir(assets_path): + import_data = get_import_data(path=Path("single_file_non_app.py")) + + assert import_data.import_string == "single_file_non_app:my_app" + + assert import_data.module_data.extra_sys_path == assets_path + assert import_data.module_data.module_import_str == "single_file_non_app" + + def test_single_non_existing_file() -> None: with changing_dir(assets_path): with pytest.raises(FastAPICLIException) as e: