Skip to content

Commit 2b52204

Browse files
committed
Merge remote-tracking branch 'upstream/main' into config
2 parents d17538d + 65b4969 commit 2b52204

File tree

9 files changed

+112
-33
lines changed

9 files changed

+112
-33
lines changed

.github/workflows/smokeshow.yml

+6-4
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ jobs:
2424

2525
- run: pip install smokeshow
2626

27-
- uses: dawidd6/action-download-artifact@v3.1.4
27+
- uses: actions/download-artifact@v4
2828
with:
29-
workflow: test.yml
30-
commit: ${{ github.event.workflow_run.head_sha }}
29+
name: coverage-html
30+
path: htmlcov
31+
github-token: ${{ secrets.GITHUB_TOKEN }}
32+
run-id: ${{ github.event.workflow_run.id }}
3133

32-
- run: smokeshow upload coverage-html
34+
- run: smokeshow upload htmlcov
3335
env:
3436
SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}
3537
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 100

.github/workflows/test.yml

+7-5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
- "3.9"
3232
- "3.10"
3333
- "3.11"
34+
- "3.12"
3435
fail-fast: false
3536
steps:
3637
- name: Dump GitHub context
@@ -68,9 +69,9 @@ jobs:
6869
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
6970
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
7071
- name: Store coverage files
71-
uses: actions/upload-artifact@v3
72+
uses: actions/upload-artifact@v4
7273
with:
73-
name: coverage
74+
name: coverage-${{ matrix.python-version }}
7475
path: coverage
7576

7677
coverage-combine:
@@ -89,17 +90,18 @@ jobs:
8990
# cache: "pip"
9091
# cache-dependency-path: pyproject.toml
9192
- name: Get coverage files
92-
uses: actions/download-artifact@v3
93+
uses: actions/download-artifact@v4
9394
with:
94-
name: coverage
95+
pattern: coverage-*
9596
path: coverage
97+
merge-multiple: true
9698
- run: pip install coverage[toml]
9799
- run: ls -la coverage
98100
- run: coverage combine coverage
99101
- run: coverage report
100102
- run: coverage html --show-contexts --title "Coverage for ${{ github.sha }}"
101103
- name: Store coverage HTML
102-
uses: actions/upload-artifact@v3
104+
uses: actions/upload-artifact@v4
103105
with:
104106
name: coverage-html
105107
path: htmlcov

pyproject.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,12 @@ source-includes = [
7171
name = "fastapi-cli-slim"
7272

7373
[tool.tiangolo._internal-slim-build.packages.fastapi-cli]
74-
include-optional-dependencies = ["standard"]
74+
# No default dependencies included for now
75+
include-optional-dependencies = []
7576

7677
[tool.tiangolo._internal-slim-build.packages.fastapi-cli.project]
77-
optional-dependencies = {}
78+
# No custom optional dependencies for now
79+
# optional-dependencies = {}
7880

7981
[tool.pytest.ini_options]
8082
addopts = [

release-notes.md

+16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
## Latest Changes
44

5+
### Refactors
6+
7+
* ♻️ Simplify code in `src/fastapi_cli/discover.py`. PR [#22](https://github.com/tiangolo/fastapi-cli/pull/22) by [@pedroimpulcetto](https://github.com/pedroimpulcetto).
8+
9+
### Internal
10+
11+
* ⬆ Bump ruff from 0.4.3 to 0.4.4. PR [#23](https://github.com/tiangolo/fastapi-cli/pull/23) by [@dependabot[bot]](https://github.com/apps/dependabot).
12+
* 👷 Enable CI tests for Python 3.12. PR [#27](https://github.com/tiangolo/fastapi-cli/pull/27) by [@tiangolo](https://github.com/tiangolo).
13+
* 👷 Update Upload/Download artifacts GitHub Actions. PR [#26](https://github.com/tiangolo/fastapi-cli/pull/26) by [@tiangolo](https://github.com/tiangolo).
14+
15+
## 0.0.4
16+
17+
### Fixes
18+
19+
* 🔧 Make FastAPI and Uvicorn optional dependencies, to avoid circular dependencies. PR [#25](https://github.com/tiangolo/fastapi-cli/pull/25) by [@tiangolo](https://github.com/tiangolo).
20+
521
### Internal
622

723
* ⬆ Bump actions/cache from 3 to 4. PR [#5](https://github.com/tiangolo/fastapi-cli/pull/5) by [@dependabot[bot]](https://github.com/apps/dependabot).

requirements-tests.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pytest >=4.4.0,<9.0.0
44
coverage[toml] >=6.2,<8.0
55
mypy ==1.10.0
6-
ruff ==0.4.3
6+
ruff ==0.4.4
77
# Needed explicitly by fastapi-cli-slim
88
fastapi-slim
99
uvicorn

src/fastapi_cli/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.0.3"
1+
__version__ = "0.0.4"

src/fastapi_cli/cli.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from typing import Any, Union
44

55
import typer
6-
import uvicorn
76
from rich import print
87
from rich.padding import Padding
98
from rich.panel import Panel
@@ -21,6 +20,11 @@
2120
setup_logging()
2221
logger = getLogger(__name__)
2322

23+
try:
24+
import uvicorn
25+
except ImportError: # pragma: no cover
26+
uvicorn = None # type: ignore[assignment]
27+
2428

2529
def version_callback(value: bool) -> None:
2630
if value:
@@ -82,6 +86,10 @@ def _run(
8286
style="green",
8387
)
8488
print(Padding(panel, 1))
89+
if not uvicorn:
90+
raise FastAPICLIException(
91+
"Could not import Uvicorn, try running 'pip install uvicorn'"
92+
) from None
8593
uvicorn.run(
8694
app=use_uvicorn_app,
8795
host=host,

src/fastapi_cli/discover.py

+23-19
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from pathlib import Path
66
from typing import Union
77

8-
from fastapi import FastAPI
98
from rich import print
109
from rich.padding import Padding
1110
from rich.panel import Panel
@@ -16,26 +15,27 @@
1615

1716
logger = getLogger(__name__)
1817

18+
try:
19+
from fastapi import FastAPI
20+
except ImportError: # pragma: no cover
21+
FastAPI = None # type: ignore[misc, assignment]
22+
1923

2024
def get_default_path() -> Path:
21-
path = Path("main.py")
22-
if path.is_file():
23-
return path
24-
path = Path("app.py")
25-
if path.is_file():
26-
return path
27-
path = Path("api.py")
28-
if path.is_file():
29-
return path
30-
path = Path("app/main.py")
31-
if path.is_file():
32-
return path
33-
path = Path("app/app.py")
34-
if path.is_file():
35-
return path
36-
path = Path("app/api.py")
37-
if path.is_file():
38-
return path
25+
potential_paths = (
26+
"main.py",
27+
"app.py",
28+
"api.py",
29+
"app/main.py",
30+
"app/app.py",
31+
"app/api.py",
32+
)
33+
34+
for full_path in potential_paths:
35+
path = Path(full_path)
36+
if path.is_file():
37+
return path
38+
3939
raise FastAPICLIException(
4040
"Could not find a default file to run, please provide an explicit path"
4141
)
@@ -107,6 +107,10 @@ def get_app_name(*, mod_data: ModuleData, app_name: Union[str, None] = None) ->
107107
"Ensure all the package directories have an [blue]__init__.py[/blue] file"
108108
)
109109
raise
110+
if not FastAPI: # type: ignore[truthy-function]
111+
raise FastAPICLIException(
112+
"Could not import FastAPI, try running 'pip install fastapi'"
113+
) from None
110114
object_names = dir(mod)
111115
object_names_set = set(object_names)
112116
if app_name:

tests/test_requirements.py

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from pathlib import Path
2+
3+
import pytest
4+
from fastapi_cli.discover import get_import_string
5+
from fastapi_cli.exceptions import FastAPICLIException
6+
from typer.testing import CliRunner
7+
8+
from .utils import changing_dir
9+
10+
runner = CliRunner()
11+
12+
assets_path = Path(__file__).parent / "assets"
13+
14+
15+
def test_no_uvicorn() -> None:
16+
import fastapi_cli.cli
17+
import uvicorn
18+
19+
fastapi_cli.cli.uvicorn = None # type: ignore[attr-defined, assignment]
20+
21+
with changing_dir(assets_path):
22+
result = runner.invoke(fastapi_cli.cli.app, ["dev", "single_file_app.py"])
23+
assert result.exit_code == 1
24+
assert result.exception is not None
25+
assert (
26+
"Could not import Uvicorn, try running 'pip install uvicorn'"
27+
in result.exception.args[0]
28+
)
29+
30+
fastapi_cli.cli.uvicorn = uvicorn # type: ignore[attr-defined]
31+
32+
33+
def test_no_fastapi() -> None:
34+
import fastapi_cli.discover
35+
from fastapi import FastAPI
36+
37+
fastapi_cli.discover.FastAPI = None # type: ignore[attr-defined, assignment]
38+
with changing_dir(assets_path):
39+
with pytest.raises(FastAPICLIException) as exc_info:
40+
get_import_string(path=Path("single_file_app.py"))
41+
assert "Could not import FastAPI, try running 'pip install fastapi'" in str(
42+
exc_info.value
43+
)
44+
45+
fastapi_cli.discover.FastAPI = FastAPI # type: ignore[attr-defined]

0 commit comments

Comments
 (0)