fastapi-cli 0.0.30__tar.gz → 0.0.31__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/PKG-INFO +1 -1
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/pyproject.toml +1 -1
- fastapi_cli-0.0.31/src/fastapi_cli/__init__.py +1 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/cli.py +63 -36
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_cli.py +90 -77
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_cli_pyproject.py +7 -7
- fastapi_cli-0.0.30/src/fastapi_cli/__init__.py +0 -1
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/LICENSE +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/README.md +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/scripts/add_latest_release_date.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/scripts/format.sh +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/scripts/lint.sh +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/scripts/prepare_release.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/scripts/test-cov-html.sh +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/scripts/test.sh +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/__main__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/config.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/discover.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/exceptions.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/logging.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/py.typed +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/utils/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/src/fastapi_cli/utils/cli.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/broken_package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/broken_package/mod/app.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/broken_package/utils.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_api/api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app/api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app/app.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_api/app/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_api/app/api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_app/app/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_app/app/api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_app/app/app.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_main/app/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_main/app/api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_main/app/app.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_main/app/main.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_non_default/app/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_non_default/app/nondefault.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_main/api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_main/app.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_main/main.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/non_default/nonstandard.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/core/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/core/utils.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/mod/api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/mod/app.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/mod/other.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/package/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/package/core/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/package/core/utils.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/package/mod/api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/package/mod/app.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/package/mod/other.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/pyproject_config/another_module.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/pyproject_config/my_module.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/pyproject_config/pyproject.toml +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/single_file_api.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/single_file_app.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/single_file_other.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/conftest.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_discover.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_prepare_release.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_requirements.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_utils_cli.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_utils_default_dir.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_utils_default_file.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_utils_package.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/test_utils_single_file.py +0 -0
- {fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/utils.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.31"
|
|
@@ -142,17 +142,19 @@ def _run(
|
|
|
142
142
|
proxy_headers: bool = False,
|
|
143
143
|
forwarded_allow_ips: str | None = None,
|
|
144
144
|
public_url: str | None = None,
|
|
145
|
+
verbose: bool = False,
|
|
145
146
|
) -> None:
|
|
146
147
|
with get_rich_toolkit() as toolkit:
|
|
147
148
|
server_type = "development" if command == "dev" else "production"
|
|
148
149
|
|
|
149
150
|
toolkit.print(f"Starting FastAPI in {server_type} mode", emoji="⚡️")
|
|
150
151
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
if verbose:
|
|
153
|
+
toolkit.print_line()
|
|
154
|
+
toolkit.print(
|
|
155
|
+
"Searching for package file structure from directories with [blue]__init__.py[/blue] files",
|
|
156
|
+
emoji="🔎",
|
|
157
|
+
)
|
|
156
158
|
|
|
157
159
|
if entrypoint and (path or app):
|
|
158
160
|
toolkit.print_line()
|
|
@@ -194,40 +196,54 @@ def _run(
|
|
|
194
196
|
|
|
195
197
|
module_data = import_data.module_data
|
|
196
198
|
import_string = import_data.import_string
|
|
199
|
+
is_auto_discovery = import_data.module_config_source == "auto-discovery"
|
|
197
200
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
+
if verbose:
|
|
202
|
+
toolkit.print_line()
|
|
203
|
+
toolkit.print(f"Importing from {module_data.extra_sys_path}", emoji="📂")
|
|
204
|
+
toolkit.print_line()
|
|
201
205
|
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
if module_data.module_paths:
|
|
207
|
+
root_tree = _get_module_tree(module_data.module_paths)
|
|
204
208
|
|
|
205
|
-
|
|
209
|
+
toolkit.print(root_tree)
|
|
206
210
|
|
|
207
|
-
|
|
211
|
+
toolkit.print_line()
|
|
212
|
+
|
|
213
|
+
toolkit.print(
|
|
214
|
+
"Importing the FastAPI app object from the module with the following code:",
|
|
215
|
+
)
|
|
216
|
+
toolkit.print_line()
|
|
217
|
+
toolkit.print(
|
|
218
|
+
f"[blue]from [bold]{module_data.module_import_str}[/bold] import [bold]{import_data.app_name}[/bold]",
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Outside --verbose, fold the resolution source into the import string
|
|
222
|
+
# line and point newcomers at --verbose for the full explanation
|
|
223
|
+
if is_auto_discovery and not verbose:
|
|
224
|
+
app_note = " [dim](auto-discovered, use --verbose to learn more)[/]"
|
|
225
|
+
else:
|
|
226
|
+
app_note = ""
|
|
208
227
|
|
|
209
|
-
toolkit.print(
|
|
210
|
-
"Importing the FastAPI app object from the module with the following code:",
|
|
211
|
-
)
|
|
212
228
|
toolkit.print_line()
|
|
213
229
|
toolkit.print(
|
|
214
|
-
f"[blue]
|
|
230
|
+
f"Using import string: [blue]{import_string}[/]{app_note}", emoji="🐍"
|
|
215
231
|
)
|
|
216
232
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
toolkit.print(f"• Module: {mod_source_desc}")
|
|
228
|
-
toolkit.print(f"• App name: {app_source_desc}")
|
|
233
|
+
if verbose:
|
|
234
|
+
toolkit.print_line()
|
|
235
|
+
mod_source_desc = SOURCE_DESCRIPTIONS[import_data.module_config_source]
|
|
236
|
+
app_source_desc = SOURCE_DESCRIPTIONS[import_data.app_name_config_source]
|
|
237
|
+
toolkit.print("Configuration sources:", emoji="📋")
|
|
238
|
+
if mod_source_desc == app_source_desc:
|
|
239
|
+
toolkit.print(f"• Import string: {mod_source_desc}")
|
|
240
|
+
else:
|
|
241
|
+
toolkit.print(f"• Module: {mod_source_desc}")
|
|
242
|
+
toolkit.print(f"• App name: {app_source_desc}")
|
|
229
243
|
|
|
230
|
-
|
|
244
|
+
# Nudge to pin the entrypoint whenever it was auto-discovered, so it's
|
|
245
|
+
# explicit next time — shown in the default output, not just --verbose
|
|
246
|
+
if is_auto_discovery:
|
|
231
247
|
toolkit.print_line()
|
|
232
248
|
toolkit.print(
|
|
233
249
|
"You can configure an entrypoint in [blue]pyproject.toml[/] for this app with:",
|
|
@@ -252,13 +268,6 @@ def _run(
|
|
|
252
268
|
toolkit.print(f"Server started at [link={url}]{url}[/]", emoji="🌐")
|
|
253
269
|
toolkit.print(f"Documentation at [link={url_docs}]{url_docs}[/]")
|
|
254
270
|
|
|
255
|
-
if command == "dev":
|
|
256
|
-
toolkit.print_line()
|
|
257
|
-
toolkit.print(
|
|
258
|
-
"Running in development mode, for production use: [bold]fastapi run[/]",
|
|
259
|
-
emoji="💡",
|
|
260
|
-
)
|
|
261
|
-
|
|
262
271
|
if not uvicorn:
|
|
263
272
|
raise FastAPICLIException(
|
|
264
273
|
"Could not import Uvicorn, try running 'pip install uvicorn'"
|
|
@@ -356,6 +365,14 @@ def dev(
|
|
|
356
365
|
help="Comma separated list of IP Addresses to trust with proxy headers. The literal '*' means trust everything."
|
|
357
366
|
),
|
|
358
367
|
] = None,
|
|
368
|
+
verbose: Annotated[
|
|
369
|
+
bool,
|
|
370
|
+
typer.Option(
|
|
371
|
+
"--verbose",
|
|
372
|
+
"-v",
|
|
373
|
+
help="Show detailed startup output and debug logs: how the [bold]FastAPI[/bold] app was discovered, imported, and configured.",
|
|
374
|
+
),
|
|
375
|
+
] = False,
|
|
359
376
|
) -> Any:
|
|
360
377
|
"""
|
|
361
378
|
Run a [bold]FastAPI[/bold] app in [yellow]development[/yellow] mode. 🧪
|
|
@@ -395,6 +412,7 @@ def dev(
|
|
|
395
412
|
proxy_headers=proxy_headers,
|
|
396
413
|
forwarded_allow_ips=forwarded_allow_ips,
|
|
397
414
|
public_url=os.getenv("FASTAPI_PUBLIC_URL"),
|
|
415
|
+
verbose=verbose,
|
|
398
416
|
)
|
|
399
417
|
|
|
400
418
|
|
|
@@ -464,6 +482,14 @@ def run(
|
|
|
464
482
|
help="Comma separated list of IP Addresses to trust with proxy headers. The literal '*' means trust everything."
|
|
465
483
|
),
|
|
466
484
|
] = None,
|
|
485
|
+
verbose: Annotated[
|
|
486
|
+
bool,
|
|
487
|
+
typer.Option(
|
|
488
|
+
"--verbose",
|
|
489
|
+
"-v",
|
|
490
|
+
help="Show detailed startup output and debug logs: how the [bold]FastAPI[/bold] app was discovered, imported, and configured.",
|
|
491
|
+
),
|
|
492
|
+
] = False,
|
|
467
493
|
) -> Any:
|
|
468
494
|
"""
|
|
469
495
|
Run a [bold]FastAPI[/bold] app in [green]production[/green] mode. 🚀
|
|
@@ -503,6 +529,7 @@ def run(
|
|
|
503
529
|
proxy_headers=proxy_headers,
|
|
504
530
|
forwarded_allow_ips=forwarded_allow_ips,
|
|
505
531
|
public_url=os.getenv("FASTAPI_PUBLIC_URL"),
|
|
532
|
+
verbose=verbose,
|
|
506
533
|
)
|
|
507
534
|
|
|
508
535
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import subprocess
|
|
2
3
|
import sys
|
|
3
4
|
from pathlib import Path
|
|
@@ -40,20 +41,16 @@ def test_dev() -> None:
|
|
|
40
41
|
"forwarded_allow_ips": None,
|
|
41
42
|
"log_config": get_uvicorn_log_config(),
|
|
42
43
|
}
|
|
43
|
-
assert "Using import string: single_file_app:app" in result.output
|
|
44
|
-
assert "Configuration sources:" in result.output
|
|
45
|
-
assert "Module: path CLI argument" in result.output
|
|
46
|
-
assert "App name: auto-discovery" in result.output
|
|
47
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
48
44
|
assert "Starting FastAPI in development mode" in result.output
|
|
45
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
49
46
|
assert "Server started at http://127.0.0.1:8000" in result.output
|
|
50
47
|
assert "Documentation at http://127.0.0.1:8000/docs" in result.output
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
assert "
|
|
48
|
+
# a passed path is explicit, so no source hint and no pyproject nudge
|
|
49
|
+
assert "(auto-discovered" not in result.output
|
|
50
|
+
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
51
|
+
# the step-by-step narration is --verbose only
|
|
52
|
+
assert "Searching for package file structure" not in result.output
|
|
53
|
+
assert "Configuration sources:" not in result.output
|
|
57
54
|
|
|
58
55
|
|
|
59
56
|
def test_run_uses_uvicorn_default_log_config_without_rich_logs(
|
|
@@ -83,12 +80,16 @@ def test_dev_no_args_auto_discovery() -> None:
|
|
|
83
80
|
assert mock_run.call_args.kwargs["host"] == "127.0.0.1"
|
|
84
81
|
assert mock_run.call_args.kwargs["port"] == 8000
|
|
85
82
|
assert mock_run.call_args.kwargs["reload"] is True
|
|
83
|
+
assert "Starting FastAPI in development mode" in result.output
|
|
86
84
|
assert "Using import string: main:app" in result.output
|
|
87
|
-
|
|
88
|
-
assert "
|
|
85
|
+
# Rich can wrap the rest of the hint based on terminal and emoji width
|
|
86
|
+
assert "(auto-discovered, use --verbose" in result.output
|
|
87
|
+
# auto-discovery nudges you to pin the entrypoint
|
|
89
88
|
assert "You can configure an entrypoint in pyproject.toml" in result.output
|
|
90
89
|
assert "[tool.fastapi]" in result.output
|
|
91
90
|
assert 'entrypoint = "main:app"' in result.output
|
|
91
|
+
# the full breakdown stays behind --verbose
|
|
92
|
+
assert "Configuration sources:" not in result.output
|
|
92
93
|
|
|
93
94
|
|
|
94
95
|
def test_dev_package() -> None:
|
|
@@ -110,22 +111,14 @@ def test_dev_package() -> None:
|
|
|
110
111
|
"forwarded_allow_ips": None,
|
|
111
112
|
"log_config": get_uvicorn_log_config(),
|
|
112
113
|
}
|
|
113
|
-
assert "Using import string: nested_package.package:app" in result.output
|
|
114
|
-
assert "Module: path CLI argument" in result.output
|
|
115
|
-
assert "App name: auto-discovery" in result.output
|
|
116
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
117
114
|
assert "Starting FastAPI in development mode" in result.output
|
|
115
|
+
assert "Using import string: nested_package.package:app" in result.output
|
|
118
116
|
assert "Server started at http://127.0.0.1:8000" in result.output
|
|
119
117
|
assert "Documentation at http://127.0.0.1:8000/docs" in result.output
|
|
120
|
-
assert (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
assert "📁 package" in result.output
|
|
126
|
-
assert "└── 🐍 __init__.py" in result.output
|
|
127
|
-
assert "└── 📁 package" in result.output
|
|
128
|
-
assert " └── 🐍 __init__.py" in result.output
|
|
118
|
+
assert "(auto-discovered" not in result.output
|
|
119
|
+
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
120
|
+
# the file tree is --verbose only
|
|
121
|
+
assert "📁 package" not in result.output
|
|
129
122
|
|
|
130
123
|
|
|
131
124
|
def test_dev_args() -> None:
|
|
@@ -163,17 +156,12 @@ def test_dev_args() -> None:
|
|
|
163
156
|
"forwarded_allow_ips": None,
|
|
164
157
|
"log_config": get_uvicorn_log_config(),
|
|
165
158
|
}
|
|
166
|
-
assert "Using import string: single_file_app:api" in result.output
|
|
167
|
-
assert "Module: path CLI argument" in result.output
|
|
168
|
-
assert "App name: --app CLI option" in result.output
|
|
169
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
170
159
|
assert "Starting FastAPI in development mode" in result.output
|
|
160
|
+
assert "Using import string: single_file_app:api" in result.output
|
|
171
161
|
assert "Server started at http://192.168.0.2:8080" in result.output
|
|
172
162
|
assert "Documentation at http://192.168.0.2:8080/docs" in result.output
|
|
173
|
-
assert (
|
|
174
|
-
|
|
175
|
-
in result.output
|
|
176
|
-
)
|
|
163
|
+
assert "(auto-discovered" not in result.output
|
|
164
|
+
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
177
165
|
|
|
178
166
|
|
|
179
167
|
def test_dev_env_vars() -> None:
|
|
@@ -197,17 +185,10 @@ def test_dev_env_vars() -> None:
|
|
|
197
185
|
"forwarded_allow_ips": None,
|
|
198
186
|
"log_config": get_uvicorn_log_config(),
|
|
199
187
|
}
|
|
200
|
-
assert "Using import string: single_file_app:app" in result.output
|
|
201
|
-
assert "Module: path CLI argument" in result.output
|
|
202
|
-
assert "App name: auto-discovery" in result.output
|
|
203
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
204
188
|
assert "Starting FastAPI in development mode" in result.output
|
|
189
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
205
190
|
assert "Server started at http://127.0.0.1:8111" in result.output
|
|
206
191
|
assert "Documentation at http://127.0.0.1:8111/docs" in result.output
|
|
207
|
-
assert (
|
|
208
|
-
"Running in development mode, for production use: fastapi run"
|
|
209
|
-
in result.output
|
|
210
|
-
)
|
|
211
192
|
|
|
212
193
|
|
|
213
194
|
def test_dev_env_vars_and_args() -> None:
|
|
@@ -238,17 +219,68 @@ def test_dev_env_vars_and_args() -> None:
|
|
|
238
219
|
"forwarded_allow_ips": None,
|
|
239
220
|
"log_config": get_uvicorn_log_config(),
|
|
240
221
|
}
|
|
241
|
-
assert "Using import string: single_file_app:app" in result.output
|
|
242
|
-
assert "Module: path CLI argument" in result.output
|
|
243
|
-
assert "App name: auto-discovery" in result.output
|
|
244
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
245
222
|
assert "Starting FastAPI in development mode" in result.output
|
|
223
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
246
224
|
assert "Server started at http://127.0.0.1:8080" in result.output
|
|
247
225
|
assert "Documentation at http://127.0.0.1:8080/docs" in result.output
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def test_dev_verbose() -> None:
|
|
229
|
+
"""--verbose restores the full narration and the module file tree."""
|
|
230
|
+
with changing_dir(assets_path):
|
|
231
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
232
|
+
result = runner.invoke(app, ["dev", "nested_package/package", "--verbose"])
|
|
233
|
+
assert result.exit_code == 0, result.output
|
|
234
|
+
assert mock_run.called
|
|
235
|
+
assert "Starting FastAPI in development mode" in result.output
|
|
236
|
+
assert "Searching for package file structure" in result.output
|
|
237
|
+
assert "Importing from" in result.output
|
|
238
|
+
assert "Importing the FastAPI app object" in result.output
|
|
239
|
+
assert "from nested_package.package import app" in result.output
|
|
240
|
+
assert "Using import string: nested_package.package:app" in result.output
|
|
241
|
+
# module and app come from different sources here
|
|
242
|
+
assert "Configuration sources:" in result.output
|
|
243
|
+
assert "Module: path CLI argument" in result.output
|
|
244
|
+
assert "App name: auto-discovery" in result.output
|
|
245
|
+
# the file tree
|
|
246
|
+
assert "📁 package" in result.output
|
|
247
|
+
assert "🐍 __init__.py" in result.output
|
|
248
|
+
# the source hint is folded away in verbose mode
|
|
249
|
+
assert "(auto-discovered, use --verbose to learn more)" not in result.output
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def test_dev_verbose_auto_discovery() -> None:
|
|
253
|
+
"""--verbose with auto-discovery shows the single 'import string' source."""
|
|
254
|
+
with changing_dir(assets_path / "default_files" / "default_main"):
|
|
255
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
256
|
+
result = runner.invoke(app, ["dev", "--verbose"])
|
|
257
|
+
assert result.exit_code == 0, result.output
|
|
258
|
+
assert mock_run.called
|
|
259
|
+
assert "Searching for package file structure" in result.output
|
|
260
|
+
assert "Importing the FastAPI app object" in result.output
|
|
261
|
+
assert "Using import string: main:app" in result.output
|
|
262
|
+
assert "Configuration sources:" in result.output
|
|
263
|
+
# module and app share the same source (auto-discovery)
|
|
264
|
+
assert "Import string: auto-discovery" in result.output
|
|
265
|
+
# auto-discovery still nudges to pin the entrypoint
|
|
266
|
+
assert "You can configure an entrypoint in pyproject.toml" in result.output
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def test_global_verbose_enables_debug_logging() -> None:
|
|
270
|
+
with changing_dir(assets_path):
|
|
271
|
+
with patch.object(uvicorn, "run"):
|
|
272
|
+
result = runner.invoke(app, ["--verbose", "dev", "single_file_app.py"])
|
|
273
|
+
assert result.exit_code == 0, result.output
|
|
274
|
+
|
|
275
|
+
assert logging.getLogger("fastapi_cli").level == logging.DEBUG
|
|
276
|
+
|
|
277
|
+
# a run without --verbose resets the level
|
|
278
|
+
with changing_dir(assets_path):
|
|
279
|
+
with patch.object(uvicorn, "run"):
|
|
280
|
+
result = runner.invoke(app, ["dev", "single_file_app.py"])
|
|
281
|
+
assert result.exit_code == 0, result.output
|
|
282
|
+
|
|
283
|
+
assert logging.getLogger("fastapi_cli").level == logging.INFO
|
|
252
284
|
|
|
253
285
|
|
|
254
286
|
def test_entrypoint_mutually_exclusive_with_path() -> None:
|
|
@@ -287,11 +319,8 @@ def test_run() -> None:
|
|
|
287
319
|
"forwarded_allow_ips": None,
|
|
288
320
|
"log_config": get_uvicorn_log_config(),
|
|
289
321
|
}
|
|
290
|
-
assert "Using import string: single_file_app:app" in result.output
|
|
291
|
-
assert "Module: path CLI argument" in result.output
|
|
292
|
-
assert "App name: auto-discovery" in result.output
|
|
293
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
294
322
|
assert "Starting FastAPI in production mode" in result.output
|
|
323
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
295
324
|
assert "Server started at http://0.0.0.0:8000" in result.output
|
|
296
325
|
assert "Documentation at http://0.0.0.0:8000/docs" in result.output
|
|
297
326
|
|
|
@@ -317,14 +346,10 @@ def test_run_trust_proxy() -> None:
|
|
|
317
346
|
"forwarded_allow_ips": "*",
|
|
318
347
|
"log_config": get_uvicorn_log_config(),
|
|
319
348
|
}
|
|
320
|
-
assert "Using import string: single_file_app:app" in result.output
|
|
321
349
|
assert "Starting FastAPI in production mode" in result.output
|
|
350
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
322
351
|
assert "Server started at http://0.0.0.0:8000" in result.output
|
|
323
352
|
assert "Documentation at http://0.0.0.0:8000/docs" in result.output
|
|
324
|
-
assert (
|
|
325
|
-
"Running in development mode, for production use: fastapi run"
|
|
326
|
-
not in result.output
|
|
327
|
-
)
|
|
328
353
|
|
|
329
354
|
|
|
330
355
|
def test_run_args() -> None:
|
|
@@ -365,17 +390,10 @@ def test_run_args() -> None:
|
|
|
365
390
|
"log_config": get_uvicorn_log_config(),
|
|
366
391
|
}
|
|
367
392
|
|
|
368
|
-
assert "Using import string: single_file_app:api" in result.output
|
|
369
|
-
assert "Module: path CLI argument" in result.output
|
|
370
|
-
assert "App name: --app CLI option" in result.output
|
|
371
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
372
393
|
assert "Starting FastAPI in production mode" in result.output
|
|
394
|
+
assert "Using import string: single_file_app:api" in result.output
|
|
373
395
|
assert "Server started at http://192.168.0.2:8080" in result.output
|
|
374
396
|
assert "Documentation at http://192.168.0.2:8080/docs" in result.output
|
|
375
|
-
assert (
|
|
376
|
-
"Running in development mode, for production use: fastapi run"
|
|
377
|
-
not in result.output
|
|
378
|
-
)
|
|
379
397
|
|
|
380
398
|
|
|
381
399
|
def test_run_env_vars() -> None:
|
|
@@ -399,11 +417,8 @@ def test_run_env_vars() -> None:
|
|
|
399
417
|
"forwarded_allow_ips": None,
|
|
400
418
|
"log_config": get_uvicorn_log_config(),
|
|
401
419
|
}
|
|
402
|
-
assert "Using import string: single_file_app:app" in result.output
|
|
403
|
-
assert "Module: path CLI argument" in result.output
|
|
404
|
-
assert "App name: auto-discovery" in result.output
|
|
405
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
406
420
|
assert "Starting FastAPI in production mode" in result.output
|
|
421
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
407
422
|
assert "Server started at http://0.0.0.0:8111" in result.output
|
|
408
423
|
assert "Documentation at http://0.0.0.0:8111/docs" in result.output
|
|
409
424
|
|
|
@@ -436,11 +451,8 @@ def test_run_env_vars_and_args() -> None:
|
|
|
436
451
|
"forwarded_allow_ips": None,
|
|
437
452
|
"log_config": get_uvicorn_log_config(),
|
|
438
453
|
}
|
|
439
|
-
assert "Using import string: single_file_app:app" in result.output
|
|
440
|
-
assert "Module: path CLI argument" in result.output
|
|
441
|
-
assert "App name: auto-discovery" in result.output
|
|
442
|
-
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
443
454
|
assert "Starting FastAPI in production mode" in result.output
|
|
455
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
444
456
|
assert "Server started at http://0.0.0.0:8080" in result.output
|
|
445
457
|
assert "Documentation at http://0.0.0.0:8080/docs" in result.output
|
|
446
458
|
|
|
@@ -601,7 +613,8 @@ def test_dev_with_import_string() -> None:
|
|
|
601
613
|
"log_config": get_uvicorn_log_config(),
|
|
602
614
|
}
|
|
603
615
|
assert "Using import string: single_file_app:api" in result.output
|
|
604
|
-
|
|
616
|
+
# an explicit entrypoint is not auto-discovery
|
|
617
|
+
assert "(auto-discovered" not in result.output
|
|
605
618
|
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
606
619
|
|
|
607
620
|
|
|
@@ -625,7 +638,7 @@ def test_run_with_import_string() -> None:
|
|
|
625
638
|
"log_config": get_uvicorn_log_config(),
|
|
626
639
|
}
|
|
627
640
|
assert "Using import string: single_file_app:app" in result.output
|
|
628
|
-
assert "
|
|
641
|
+
assert "(auto-discovered" not in result.output
|
|
629
642
|
assert "You can configure an entrypoint in pyproject.toml" not in result.output
|
|
630
643
|
|
|
631
644
|
|
|
@@ -26,8 +26,9 @@ def test_dev_with_pyproject_app_config_uses() -> None:
|
|
|
26
26
|
assert mock_run.call_args.kwargs["reload"] is True
|
|
27
27
|
|
|
28
28
|
assert "Using import string: my_module:app" in result.output
|
|
29
|
-
|
|
30
|
-
assert "
|
|
29
|
+
# a configured entrypoint is not auto-discovery
|
|
30
|
+
assert "(auto-discovered" not in result.output
|
|
31
|
+
assert "Configuration sources:" not in result.output
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
def test_run_with_pyproject_app_config() -> None:
|
|
@@ -44,8 +45,8 @@ def test_run_with_pyproject_app_config() -> None:
|
|
|
44
45
|
assert mock_run.call_args.kwargs["reload"] is False
|
|
45
46
|
|
|
46
47
|
assert "Using import string: my_module:app" in result.output
|
|
47
|
-
assert "
|
|
48
|
-
assert "
|
|
48
|
+
assert "(auto-discovered" not in result.output
|
|
49
|
+
assert "Configuration sources:" not in result.output
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
def test_cli_arg_overrides_pyproject_config() -> None:
|
|
@@ -58,9 +59,8 @@ def test_cli_arg_overrides_pyproject_config() -> None:
|
|
|
58
59
|
assert result.exit_code == 0, result.output
|
|
59
60
|
|
|
60
61
|
assert mock_run.call_args.kwargs["app"] == "another_module:app"
|
|
61
|
-
assert "
|
|
62
|
-
assert "
|
|
63
|
-
assert "App name: auto-discovery" in result.output
|
|
62
|
+
assert "Using import string: another_module:app" in result.output
|
|
63
|
+
assert "Configuration sources:" not in result.output
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
def test_pyproject_app_config_invalid_format() -> None:
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.30"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_api/app/api.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_app/app/api.py
RENAMED
|
File without changes
|
{fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_app/app/app.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_main/app/api.py
RENAMED
|
File without changes
|
{fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/default_app_dir_main/app/app.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/default_files/non_default/nonstandard.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.30 → fastapi_cli-0.0.31}/tests/assets/nested_package/package/mod/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|