From 8295ac8c874b45bb50587a283375624b228fa6e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 19 May 2024 11:38:01 -0700 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9E=96=20Make=20FastAPI=20and=20Uvicorn?= =?UTF-8?q?=20optional=20dependencies,=20installed=20by=20FastAPI=20by=20d?= =?UTF-8?q?efault,=20to=20avoid=20circular=20dependencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5fb2684c..7d325e54 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,10 +70,12 @@ source-includes = [ name = "fastapi-cli-slim" [tool.tiangolo._internal-slim-build.packages.fastapi-cli] -include-optional-dependencies = ["standard"] +# No default dependencies included for now +include-optional-dependencies = [] [tool.tiangolo._internal-slim-build.packages.fastapi-cli.project] -optional-dependencies = {} +# No custom optional dependencies for now +# optional-dependencies = {} [tool.pytest.ini_options] addopts = [ From cc0d0198b6f7398df8bfbe3052213704c0795d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 19 May 2024 11:38:55 -0700 Subject: [PATCH 2/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Add=20checks=20to=20en?= =?UTF-8?q?sure=20FastAPI=20and=20Uvicorn=20are=20available=20before=20run?= =?UTF-8?q?ning=20them?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fastapi_cli/cli.py | 10 +++++++++- src/fastapi_cli/discover.py | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/fastapi_cli/cli.py b/src/fastapi_cli/cli.py index 2aea254c..41ee6cdf 100644 --- a/src/fastapi_cli/cli.py +++ b/src/fastapi_cli/cli.py @@ -3,7 +3,6 @@ from typing import Any, Union import typer -import uvicorn from rich import print from rich.padding import Padding from rich.panel import Panel @@ -20,6 +19,11 @@ setup_logging() logger = getLogger(__name__) +try: + import uvicorn +except ImportError: + uvicorn = None # type: ignore[assignment] + def version_callback(value: bool) -> None: if value: @@ -81,6 +85,10 @@ def _run( style="green", ) print(Padding(panel, 1)) + if not uvicorn: + raise FastAPICLIException( + "Could not import Uvicorn, try running 'pip install uvicorn'" + ) from None uvicorn.run( app=use_uvicorn_app, host=host, diff --git a/src/fastapi_cli/discover.py b/src/fastapi_cli/discover.py index befcdfd0..786fd5bc 100644 --- a/src/fastapi_cli/discover.py +++ b/src/fastapi_cli/discover.py @@ -5,7 +5,6 @@ from pathlib import Path from typing import Union -from fastapi import FastAPI from rich import print from rich.padding import Padding from rich.panel import Panel @@ -16,6 +15,11 @@ logger = getLogger(__name__) +try: + from fastapi import FastAPI +except ImportError: + FastAPI = None # type: ignore[misc, assignment] + def get_default_path() -> Path: path = Path("main.py") @@ -107,6 +111,10 @@ def get_app_name(*, mod_data: ModuleData, app_name: Union[str, None] = None) -> "Ensure all the package directories have an [blue]__init__.py[/blue] file" ) raise + if not FastAPI: # type: ignore[truthy-function] + 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: From 2309c79dd792b959ec91dc7e057035bd6ed38467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 19 May 2024 11:39:22 -0700 Subject: [PATCH 3/5] =?UTF-8?q?=E2=9C=85=20Add=20tests=20for=20import=20ch?= =?UTF-8?q?ecks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_requirements.py | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tests/test_requirements.py diff --git a/tests/test_requirements.py b/tests/test_requirements.py new file mode 100644 index 00000000..11707d05 --- /dev/null +++ b/tests/test_requirements.py @@ -0,0 +1,45 @@ +from pathlib import Path + +import pytest +from fastapi_cli.discover import get_import_string +from fastapi_cli.exceptions import FastAPICLIException +from typer.testing import CliRunner + +from .utils import changing_dir + +runner = CliRunner() + +assets_path = Path(__file__).parent / "assets" + + +def test_no_uvicorn() -> None: + import fastapi_cli.cli + import uvicorn + + fastapi_cli.cli.uvicorn = None # type: ignore[attr-defined] + + with changing_dir(assets_path): + result = runner.invoke(fastapi_cli.cli.app, ["dev", "single_file_app.py"]) + assert result.exit_code == 1 + assert result.exception is not None + assert ( + "Could not import Uvicorn, try running 'pip install uvicorn'" + in result.exception.args[0] + ) + + fastapi_cli.cli.uvicorn = uvicorn # type: ignore[attr-defined] + + +def test_no_fastapi() -> None: + import fastapi_cli.discover + from fastapi import FastAPI + + fastapi_cli.discover.FastAPI = None # type: ignore[attr-defined] + with changing_dir(assets_path): + with pytest.raises(FastAPICLIException) as exc_info: + get_import_string(path=Path("single_file_app.py")) + assert "Could not import FastAPI, try running 'pip install fastapi'" in str( + exc_info.value + ) + + fastapi_cli.discover.FastAPI = FastAPI # type: ignore[attr-defined] From abb56c101bbba9a33b84ccb8cd472d727d8f6e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 19 May 2024 11:42:30 -0700 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=8E=A8=20Add=20type=20ignores=20for?= =?UTF-8?q?=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_requirements.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_requirements.py b/tests/test_requirements.py index 11707d05..bcad1b91 100644 --- a/tests/test_requirements.py +++ b/tests/test_requirements.py @@ -16,7 +16,7 @@ def test_no_uvicorn() -> None: import fastapi_cli.cli import uvicorn - fastapi_cli.cli.uvicorn = None # type: ignore[attr-defined] + fastapi_cli.cli.uvicorn = None # type: ignore[attr-defined, assignment] with changing_dir(assets_path): result = runner.invoke(fastapi_cli.cli.app, ["dev", "single_file_app.py"]) @@ -34,7 +34,7 @@ def test_no_fastapi() -> None: import fastapi_cli.discover from fastapi import FastAPI - fastapi_cli.discover.FastAPI = None # type: ignore[attr-defined] + fastapi_cli.discover.FastAPI = None # type: ignore[attr-defined, assignment] with changing_dir(assets_path): with pytest.raises(FastAPICLIException) as exc_info: get_import_string(path=Path("single_file_app.py")) From 28eb4a84df048197c8fcb7ac3aab8004742e9179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 19 May 2024 11:49:21 -0700 Subject: [PATCH 5/5] =?UTF-8?q?=E2=9C=85=20Add=20coverage=20configs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fastapi_cli/cli.py | 2 +- src/fastapi_cli/discover.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fastapi_cli/cli.py b/src/fastapi_cli/cli.py index 41ee6cdf..d5bcb8e5 100644 --- a/src/fastapi_cli/cli.py +++ b/src/fastapi_cli/cli.py @@ -21,7 +21,7 @@ try: import uvicorn -except ImportError: +except ImportError: # pragma: no cover uvicorn = None # type: ignore[assignment] diff --git a/src/fastapi_cli/discover.py b/src/fastapi_cli/discover.py index 786fd5bc..17dd08dd 100644 --- a/src/fastapi_cli/discover.py +++ b/src/fastapi_cli/discover.py @@ -17,7 +17,7 @@ try: from fastapi import FastAPI -except ImportError: +except ImportError: # pragma: no cover FastAPI = None # type: ignore[misc, assignment]