fastapi-cli 0.0.10__tar.gz → 0.0.11__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.10 → fastapi_cli-0.0.11}/PKG-INFO +1 -1
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/pyproject.toml +1 -1
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/requirements-tests.txt +1 -1
- fastapi_cli-0.0.11/src/fastapi_cli/__init__.py +1 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/src/fastapi_cli/cli.py +28 -5
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/src/fastapi_cli/discover.py +23 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/test_cli.py +42 -0
- fastapi_cli-0.0.11/tests/test_discover.py +58 -0
- fastapi_cli-0.0.10/src/fastapi_cli/__init__.py +0 -1
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/LICENSE +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/README.md +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/pdm_build.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/requirements-github-actions.txt +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/requirements.txt +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/scripts/format.sh +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/scripts/lint.sh +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/scripts/test-cov-html.sh +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/scripts/test.sh +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/src/fastapi_cli/__main__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/src/fastapi_cli/exceptions.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/src/fastapi_cli/logging.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/src/fastapi_cli/py.typed +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/src/fastapi_cli/utils/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/src/fastapi_cli/utils/cli.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/broken_package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/broken_package/mod/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/broken_package/utils.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_api/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_api/app/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_api/app/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_app/app/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_app/app/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_app/app/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_main/app/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_main/app/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_main/app/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_main/app/main.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_non_default/app/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_non_default/app/nondefault.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_main/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_main/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_main/main.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/non_default/nonstandard.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/package/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/package/core/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/package/core/utils.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/package/mod/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/package/mod/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/package/mod/other.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/package/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/package/core/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/package/core/utils.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/package/mod/api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/package/mod/app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/package/mod/other.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/single_file_api.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/single_file_app.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/single_file_other.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/conftest.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/test_requirements.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/test_utils_cli.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/test_utils_default_dir.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/test_utils_default_file.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/test_utils_package.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/test_utils_single_file.py +0 -0
- {fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/utils.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.11"
|
|
@@ -7,7 +7,7 @@ from rich import print
|
|
|
7
7
|
from rich.tree import Tree
|
|
8
8
|
from typing_extensions import Annotated
|
|
9
9
|
|
|
10
|
-
from fastapi_cli.discover import get_import_data
|
|
10
|
+
from fastapi_cli.discover import get_import_data, get_import_data_from_import_string
|
|
11
11
|
from fastapi_cli.exceptions import FastAPICLIException
|
|
12
12
|
|
|
13
13
|
from . import __version__
|
|
@@ -95,6 +95,7 @@ def _run(
|
|
|
95
95
|
root_path: str = "",
|
|
96
96
|
command: str,
|
|
97
97
|
app: Union[str, None] = None,
|
|
98
|
+
entrypoint: Union[str, None] = None,
|
|
98
99
|
proxy_headers: bool = False,
|
|
99
100
|
forwarded_allow_ips: Union[str, None] = None,
|
|
100
101
|
) -> None:
|
|
@@ -109,7 +110,10 @@ def _run(
|
|
|
109
110
|
)
|
|
110
111
|
|
|
111
112
|
try:
|
|
112
|
-
|
|
113
|
+
if entrypoint:
|
|
114
|
+
import_data = get_import_data_from_import_string(entrypoint)
|
|
115
|
+
else:
|
|
116
|
+
import_data = get_import_data(path=path, app_name=app)
|
|
113
117
|
except FastAPICLIException as e:
|
|
114
118
|
toolkit.print_line()
|
|
115
119
|
toolkit.print(f"[error]{e}")
|
|
@@ -124,10 +128,11 @@ def _run(
|
|
|
124
128
|
toolkit.print(f"Importing from {module_data.extra_sys_path}")
|
|
125
129
|
toolkit.print_line()
|
|
126
130
|
|
|
127
|
-
|
|
131
|
+
if module_data.module_paths:
|
|
132
|
+
root_tree = _get_module_tree(module_data.module_paths)
|
|
128
133
|
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
toolkit.print(root_tree, tag="module")
|
|
135
|
+
toolkit.print_line()
|
|
131
136
|
|
|
132
137
|
toolkit.print(
|
|
133
138
|
"Importing the FastAPI app object from the module with the following code:",
|
|
@@ -222,6 +227,14 @@ def dev(
|
|
|
222
227
|
help="The name of the variable that contains the [bold]FastAPI[/bold] app in the imported module or package. If not provided, it is detected automatically."
|
|
223
228
|
),
|
|
224
229
|
] = None,
|
|
230
|
+
entrypoint: Annotated[
|
|
231
|
+
Union[str, None],
|
|
232
|
+
typer.Option(
|
|
233
|
+
"--entrypoint",
|
|
234
|
+
"-e",
|
|
235
|
+
help="The FastAPI app import string in the format 'some.importable_module:app_name'.",
|
|
236
|
+
),
|
|
237
|
+
] = None,
|
|
225
238
|
proxy_headers: Annotated[
|
|
226
239
|
bool,
|
|
227
240
|
typer.Option(
|
|
@@ -267,6 +280,7 @@ def dev(
|
|
|
267
280
|
reload=reload,
|
|
268
281
|
root_path=root_path,
|
|
269
282
|
app=app,
|
|
283
|
+
entrypoint=entrypoint,
|
|
270
284
|
command="dev",
|
|
271
285
|
proxy_headers=proxy_headers,
|
|
272
286
|
forwarded_allow_ips=forwarded_allow_ips,
|
|
@@ -318,6 +332,14 @@ def run(
|
|
|
318
332
|
help="The name of the variable that contains the [bold]FastAPI[/bold] app in the imported module or package. If not provided, it is detected automatically."
|
|
319
333
|
),
|
|
320
334
|
] = None,
|
|
335
|
+
entrypoint: Annotated[
|
|
336
|
+
Union[str, None],
|
|
337
|
+
typer.Option(
|
|
338
|
+
"--entrypoint",
|
|
339
|
+
"-e",
|
|
340
|
+
help="The FastAPI app import string in the format 'some.importable_module:app_name'.",
|
|
341
|
+
),
|
|
342
|
+
] = None,
|
|
321
343
|
proxy_headers: Annotated[
|
|
322
344
|
bool,
|
|
323
345
|
typer.Option(
|
|
@@ -364,6 +386,7 @@ def run(
|
|
|
364
386
|
workers=workers,
|
|
365
387
|
root_path=root_path,
|
|
366
388
|
app=app,
|
|
389
|
+
entrypoint=entrypoint,
|
|
367
390
|
command="run",
|
|
368
391
|
proxy_headers=proxy_headers,
|
|
369
392
|
forwarded_allow_ips=forwarded_allow_ips,
|
|
@@ -130,3 +130,26 @@ def get_import_data(
|
|
|
130
130
|
return ImportData(
|
|
131
131
|
app_name=use_app_name, module_data=mod_data, import_string=import_string
|
|
132
132
|
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_import_data_from_import_string(import_string: str) -> ImportData:
|
|
136
|
+
module_str, _, app_name = import_string.partition(":")
|
|
137
|
+
|
|
138
|
+
if not module_str or not app_name:
|
|
139
|
+
raise FastAPICLIException(
|
|
140
|
+
"Import string must be in the format module.submodule:app_name"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
here = Path(".").resolve()
|
|
144
|
+
|
|
145
|
+
sys.path.insert(0, str(here))
|
|
146
|
+
|
|
147
|
+
return ImportData(
|
|
148
|
+
app_name=app_name,
|
|
149
|
+
module_data=ModuleData(
|
|
150
|
+
module_import_str=module_str,
|
|
151
|
+
extra_sys_path=here,
|
|
152
|
+
module_paths=[],
|
|
153
|
+
),
|
|
154
|
+
import_string=import_string,
|
|
155
|
+
)
|
|
@@ -285,6 +285,48 @@ def test_version() -> None:
|
|
|
285
285
|
assert "FastAPI CLI version:" in result.output
|
|
286
286
|
|
|
287
287
|
|
|
288
|
+
def test_dev_with_import_string() -> None:
|
|
289
|
+
with changing_dir(assets_path):
|
|
290
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
291
|
+
result = runner.invoke(app, ["dev", "--entrypoint", "single_file_app:api"])
|
|
292
|
+
assert result.exit_code == 0, result.output
|
|
293
|
+
assert mock_run.called
|
|
294
|
+
assert mock_run.call_args
|
|
295
|
+
assert mock_run.call_args.kwargs == {
|
|
296
|
+
"app": "single_file_app:api",
|
|
297
|
+
"forwarded_allow_ips": None,
|
|
298
|
+
"host": "127.0.0.1",
|
|
299
|
+
"port": 8000,
|
|
300
|
+
"reload": True,
|
|
301
|
+
"workers": None,
|
|
302
|
+
"root_path": "",
|
|
303
|
+
"proxy_headers": True,
|
|
304
|
+
"log_config": get_uvicorn_log_config(),
|
|
305
|
+
}
|
|
306
|
+
assert "Using import string: single_file_app:api" in result.output
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def test_run_with_import_string() -> None:
|
|
310
|
+
with changing_dir(assets_path):
|
|
311
|
+
with patch.object(uvicorn, "run") as mock_run:
|
|
312
|
+
result = runner.invoke(app, ["run", "--entrypoint", "single_file_app:app"])
|
|
313
|
+
assert result.exit_code == 0, result.output
|
|
314
|
+
assert mock_run.called
|
|
315
|
+
assert mock_run.call_args
|
|
316
|
+
assert mock_run.call_args.kwargs == {
|
|
317
|
+
"app": "single_file_app:app",
|
|
318
|
+
"forwarded_allow_ips": None,
|
|
319
|
+
"host": "0.0.0.0",
|
|
320
|
+
"port": 8000,
|
|
321
|
+
"reload": False,
|
|
322
|
+
"workers": None,
|
|
323
|
+
"root_path": "",
|
|
324
|
+
"proxy_headers": True,
|
|
325
|
+
"log_config": get_uvicorn_log_config(),
|
|
326
|
+
}
|
|
327
|
+
assert "Using import string: single_file_app:app" in result.output
|
|
328
|
+
|
|
329
|
+
|
|
288
330
|
def test_script() -> None:
|
|
289
331
|
result = subprocess.run(
|
|
290
332
|
[sys.executable, "-m", "coverage", "run", "-m", "fastapi_cli", "--help"],
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from fastapi_cli.discover import (
|
|
6
|
+
ImportData,
|
|
7
|
+
get_import_data_from_import_string,
|
|
8
|
+
)
|
|
9
|
+
from fastapi_cli.exceptions import FastAPICLIException
|
|
10
|
+
|
|
11
|
+
assets_path = Path(__file__).parent / "assets"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_get_import_data_from_import_string_valid() -> None:
|
|
15
|
+
result = get_import_data_from_import_string("module.submodule:app")
|
|
16
|
+
|
|
17
|
+
assert isinstance(result, ImportData)
|
|
18
|
+
assert result.app_name == "app"
|
|
19
|
+
assert result.import_string == "module.submodule:app"
|
|
20
|
+
assert result.module_data.module_import_str == "module.submodule"
|
|
21
|
+
assert result.module_data.extra_sys_path == Path(".").resolve()
|
|
22
|
+
assert result.module_data.module_paths == []
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_get_import_data_from_import_string_missing_colon() -> None:
|
|
26
|
+
with pytest.raises(FastAPICLIException) as exc_info:
|
|
27
|
+
get_import_data_from_import_string("module.submodule")
|
|
28
|
+
|
|
29
|
+
assert "Import string must be in the format module.submodule:app_name" in str(
|
|
30
|
+
exc_info.value
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_import_data_from_import_string_missing_app() -> None:
|
|
35
|
+
with pytest.raises(FastAPICLIException) as exc_info:
|
|
36
|
+
get_import_data_from_import_string("module.submodule:")
|
|
37
|
+
|
|
38
|
+
assert "Import string must be in the format module.submodule:app_name" in str(
|
|
39
|
+
exc_info.value
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_get_import_data_from_import_string_missing_module() -> None:
|
|
44
|
+
with pytest.raises(FastAPICLIException) as exc_info:
|
|
45
|
+
get_import_data_from_import_string(":app")
|
|
46
|
+
|
|
47
|
+
assert "Import string must be in the format module.submodule:app_name" in str(
|
|
48
|
+
exc_info.value
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_get_import_data_from_import_string_empty() -> None:
|
|
53
|
+
with pytest.raises(FastAPICLIException) as exc_info:
|
|
54
|
+
get_import_data_from_import_string("")
|
|
55
|
+
|
|
56
|
+
assert "Import string must be in the format module.submodule:app_name" in str(
|
|
57
|
+
exc_info.value
|
|
58
|
+
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.10"
|
|
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.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_api/app/api.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_app/app/api.py
RENAMED
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_app/app/app.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/default_files/default_app_dir_main/app/api.py
RENAMED
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/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.10 → fastapi_cli-0.0.11}/tests/assets/default_files/non_default/nonstandard.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/tests/assets/nested_package/package/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_cli-0.0.10 → fastapi_cli-0.0.11}/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
|