Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
10 changes: 9 additions & 1 deletion src/fastapi_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -20,6 +19,11 @@
setup_logging()
logger = getLogger(__name__)

try:
import uvicorn
except ImportError: # pragma: no cover
uvicorn = None # type: ignore[assignment]


def version_callback(value: bool) -> None:
if value:
Expand Down Expand Up @@ -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,
Expand Down
10 changes: 9 additions & 1 deletion src/fastapi_cli/discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -16,6 +15,11 @@

logger = getLogger(__name__)

try:
from fastapi import FastAPI
except ImportError: # pragma: no cover
FastAPI = None # type: ignore[misc, assignment]


def get_default_path() -> Path:
path = Path("main.py")
Expand Down Expand Up @@ -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:
Expand Down
45 changes: 45 additions & 0 deletions tests/test_requirements.py
Original file line number Diff line number Diff line change
@@ -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, assignment]

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, assignment]
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]