fastapi-cli 0.0.5__tar.gz → 0.0.7__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.5 → fastapi_cli-0.0.7}/PKG-INFO +33 -44
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/README.md +27 -40
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/pyproject.toml +12 -3
- fastapi_cli-0.0.7/requirements-github-actions.txt +1 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/requirements-tests.txt +2 -2
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/requirements.txt +1 -1
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/scripts/format.sh +1 -1
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/scripts/test-cov-html.sh +1 -1
- fastapi_cli-0.0.7/src/fastapi_cli/__init__.py +1 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/src/fastapi_cli/cli.py +114 -43
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/src/fastapi_cli/discover.py +24 -59
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/src/fastapi_cli/logging.py +4 -2
- fastapi_cli-0.0.7/src/fastapi_cli/utils/cli.py +76 -0
- fastapi_cli-0.0.7/tests/assets/nested_package/__init__.py +0 -0
- fastapi_cli-0.0.7/tests/assets/nested_package/package/core/__init__.py +0 -0
- fastapi_cli-0.0.7/tests/assets/package/__init__.py +2 -0
- fastapi_cli-0.0.7/tests/assets/package/core/__init__.py +0 -0
- fastapi_cli-0.0.7/tests/assets/package/core/utils.py +2 -0
- fastapi_cli-0.0.7/tests/assets/package/mod/__init__.py +1 -0
- fastapi_cli-0.0.7/tests/assets/package/mod/api.py +24 -0
- fastapi_cli-0.0.7/tests/assets/package/mod/app.py +32 -0
- fastapi_cli-0.0.7/tests/assets/package/mod/other.py +16 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/conftest.py +2 -1
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/test_cli.py +65 -25
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/test_requirements.py +8 -5
- fastapi_cli-0.0.7/tests/test_utils_cli.py +56 -0
- fastapi_cli-0.0.7/tests/test_utils_default_dir.py +53 -0
- fastapi_cli-0.0.7/tests/test_utils_default_file.py +74 -0
- fastapi_cli-0.0.7/tests/test_utils_package.py +197 -0
- fastapi_cli-0.0.7/tests/test_utils_single_file.py +60 -0
- fastapi_cli-0.0.5/src/fastapi_cli/__init__.py +0 -1
- fastapi_cli-0.0.5/tests/test_utils_default_dir.py +0 -88
- fastapi_cli-0.0.5/tests/test_utils_default_file.py +0 -103
- fastapi_cli-0.0.5/tests/test_utils_package.py +0 -455
- fastapi_cli-0.0.5/tests/test_utils_single_file.py +0 -115
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/LICENSE +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/pdm_build.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/scripts/lint.sh +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/scripts/test.sh +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/src/fastapi_cli/__main__.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/src/fastapi_cli/exceptions.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/src/fastapi_cli/py.typed +0 -0
- {fastapi_cli-0.0.5/tests → fastapi_cli-0.0.7/src/fastapi_cli/utils}/__init__.py +0 -0
- {fastapi_cli-0.0.5/tests/assets/default_files/default_app_dir_api/app → fastapi_cli-0.0.7/tests}/__init__.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/broken_package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/broken_package/mod/app.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/broken_package/utils.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_api/api.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app/api.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app/app.py +0 -0
- {fastapi_cli-0.0.5/tests/assets/default_files/default_app_dir_app → fastapi_cli-0.0.7/tests/assets/default_files/default_app_dir_api}/app/__init__.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app_dir_api/app/api.py +0 -0
- {fastapi_cli-0.0.5/tests/assets/default_files/default_app_dir_main → fastapi_cli-0.0.7/tests/assets/default_files/default_app_dir_app}/app/__init__.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app_dir_app/app/api.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app_dir_app/app/app.py +0 -0
- {fastapi_cli-0.0.5/tests/assets/default_files/default_app_dir_non_default → fastapi_cli-0.0.7/tests/assets/default_files/default_app_dir_main}/app/__init__.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app_dir_main/app/api.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app_dir_main/app/app.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app_dir_main/app/main.py +0 -0
- {fastapi_cli-0.0.5/tests/assets/package/core → fastapi_cli-0.0.7/tests/assets/default_files/default_app_dir_non_default/app}/__init__.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_app_dir_non_default/app/nondefault.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_main/api.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_main/app.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/default_main/main.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/default_files/non_default/nonstandard.py +0 -0
- {fastapi_cli-0.0.5/tests/assets → fastapi_cli-0.0.7/tests/assets/nested_package}/package/__init__.py +0 -0
- {fastapi_cli-0.0.5/tests/assets → fastapi_cli-0.0.7/tests/assets/nested_package}/package/core/utils.py +0 -0
- {fastapi_cli-0.0.5/tests/assets → fastapi_cli-0.0.7/tests/assets/nested_package}/package/mod/__init__.py +0 -0
- {fastapi_cli-0.0.5/tests/assets → fastapi_cli-0.0.7/tests/assets/nested_package}/package/mod/api.py +0 -0
- {fastapi_cli-0.0.5/tests/assets → fastapi_cli-0.0.7/tests/assets/nested_package}/package/mod/app.py +0 -0
- {fastapi_cli-0.0.5/tests/assets → fastapi_cli-0.0.7/tests/assets/nested_package}/package/mod/other.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/single_file_api.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/single_file_app.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/assets/single_file_other.py +0 -0
- {fastapi_cli-0.0.5 → fastapi_cli-0.0.7}/tests/utils.py +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastapi-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀
|
|
5
|
-
Home-page: https://github.com/fastapi/fastapi-cli
|
|
6
5
|
Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com>
|
|
7
6
|
License: MIT
|
|
8
7
|
Classifier: Intended Audience :: Information Technology
|
|
@@ -26,14 +25,17 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
26
25
|
Classifier: Programming Language :: Python :: 3.11
|
|
27
26
|
Classifier: Programming Language :: Python :: 3.12
|
|
28
27
|
Classifier: License :: OSI Approved :: MIT License
|
|
29
|
-
Project-URL: Documentation, https://fastapi.tiangolo.com
|
|
30
28
|
Project-URL: Homepage, https://github.com/fastapi/fastapi-cli
|
|
29
|
+
Project-URL: Documentation, https://fastapi.tiangolo.com/fastapi-cli/
|
|
31
30
|
Project-URL: Repository, https://github.com/fastapi/fastapi-cli
|
|
31
|
+
Project-URL: Issues, https://github.com/fastapi/fastapi-cli/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/fastapi/fastapi-cli/blob/main/release-notes.md
|
|
32
33
|
Requires-Python: >=3.8
|
|
33
34
|
Requires-Dist: typer>=0.12.3
|
|
34
35
|
Requires-Dist: uvicorn[standard]>=0.15.0
|
|
35
|
-
Requires-Dist:
|
|
36
|
+
Requires-Dist: rich-toolkit>=0.11.1
|
|
36
37
|
Provides-Extra: standard
|
|
38
|
+
Requires-Dist: uvicorn[standard]>=0.15.0; extra == "standard"
|
|
37
39
|
Description-Content-Type: text/markdown
|
|
38
40
|
|
|
39
41
|
# FastAPI CLI
|
|
@@ -70,46 +72,33 @@ To run your FastAPI app for development, you can use the `fastapi dev` command:
|
|
|
70
72
|
|
|
71
73
|
```console
|
|
72
74
|
$ fastapi dev main.py
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
│ │
|
|
101
|
-
│ Running in development mode, for production use: │
|
|
102
|
-
│ │
|
|
103
|
-
│ fastapi run │
|
|
104
|
-
│ │
|
|
105
|
-
╰─────────────────────────────────────────────────────╯
|
|
106
|
-
|
|
107
|
-
INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
|
108
|
-
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
|
109
|
-
INFO: Started reloader process [56345] using WatchFiles
|
|
110
|
-
INFO: Started server process [56352]
|
|
111
|
-
INFO: Waiting for application startup.
|
|
112
|
-
INFO: Application startup complete.
|
|
75
|
+
|
|
76
|
+
FastAPI Starting development server 🚀
|
|
77
|
+
|
|
78
|
+
Searching for package file structure from directories with __init__.py files
|
|
79
|
+
Importing from /home/user/code/awesomeapp
|
|
80
|
+
|
|
81
|
+
module 🐍 main.py
|
|
82
|
+
|
|
83
|
+
code Importing the FastAPI app object from the module with the following code:
|
|
84
|
+
|
|
85
|
+
from main import app
|
|
86
|
+
|
|
87
|
+
app Using import string: main:app
|
|
88
|
+
|
|
89
|
+
server Server started at http://127.0.0.1:8000
|
|
90
|
+
server Documentation at http://127.0.0.1:8000/docs
|
|
91
|
+
|
|
92
|
+
tip Running in development mode, for production use: fastapi run
|
|
93
|
+
|
|
94
|
+
Logs:
|
|
95
|
+
|
|
96
|
+
INFO Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
|
97
|
+
INFO Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
|
98
|
+
INFO Started reloader process [4106097] using WatchFiles
|
|
99
|
+
INFO Started server process [4106120]
|
|
100
|
+
INFO Waiting for application startup.
|
|
101
|
+
INFO Application startup complete.
|
|
113
102
|
```
|
|
114
103
|
|
|
115
104
|
</div>
|
|
@@ -32,46 +32,33 @@ To run your FastAPI app for development, you can use the `fastapi dev` command:
|
|
|
32
32
|
|
|
33
33
|
```console
|
|
34
34
|
$ fastapi dev main.py
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
│ │
|
|
63
|
-
│ Running in development mode, for production use: │
|
|
64
|
-
│ │
|
|
65
|
-
│ fastapi run │
|
|
66
|
-
│ │
|
|
67
|
-
╰─────────────────────────────────────────────────────╯
|
|
68
|
-
|
|
69
|
-
INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
|
70
|
-
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
|
71
|
-
INFO: Started reloader process [56345] using WatchFiles
|
|
72
|
-
INFO: Started server process [56352]
|
|
73
|
-
INFO: Waiting for application startup.
|
|
74
|
-
INFO: Application startup complete.
|
|
35
|
+
|
|
36
|
+
FastAPI Starting development server 🚀
|
|
37
|
+
|
|
38
|
+
Searching for package file structure from directories with __init__.py files
|
|
39
|
+
Importing from /home/user/code/awesomeapp
|
|
40
|
+
|
|
41
|
+
module 🐍 main.py
|
|
42
|
+
|
|
43
|
+
code Importing the FastAPI app object from the module with the following code:
|
|
44
|
+
|
|
45
|
+
from main import app
|
|
46
|
+
|
|
47
|
+
app Using import string: main:app
|
|
48
|
+
|
|
49
|
+
server Server started at http://127.0.0.1:8000
|
|
50
|
+
server Documentation at http://127.0.0.1:8000/docs
|
|
51
|
+
|
|
52
|
+
tip Running in development mode, for production use: fastapi run
|
|
53
|
+
|
|
54
|
+
Logs:
|
|
55
|
+
|
|
56
|
+
INFO Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
|
57
|
+
INFO Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
|
58
|
+
INFO Started reloader process [4106097] using WatchFiles
|
|
59
|
+
INFO Started server process [4106120]
|
|
60
|
+
INFO Waiting for application startup.
|
|
61
|
+
INFO Application startup complete.
|
|
75
62
|
```
|
|
76
63
|
|
|
77
64
|
</div>
|
|
@@ -33,8 +33,9 @@ classifiers = [
|
|
|
33
33
|
dependencies = [
|
|
34
34
|
"typer >= 0.12.3",
|
|
35
35
|
"uvicorn[standard] >= 0.15.0",
|
|
36
|
+
"rich-toolkit >= 0.11.1",
|
|
36
37
|
]
|
|
37
|
-
version = "0.0.
|
|
38
|
+
version = "0.0.7"
|
|
38
39
|
|
|
39
40
|
[project.license]
|
|
40
41
|
text = "MIT"
|
|
@@ -45,9 +46,11 @@ standard = [
|
|
|
45
46
|
]
|
|
46
47
|
|
|
47
48
|
[project.urls]
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
Homepage = "https://github.com/fastapi/fastapi-cli"
|
|
50
|
+
Documentation = "https://fastapi.tiangolo.com/fastapi-cli/"
|
|
50
51
|
Repository = "https://github.com/fastapi/fastapi-cli"
|
|
52
|
+
Issues = "https://github.com/fastapi/fastapi-cli/issues"
|
|
53
|
+
Changelog = "https://github.com/fastapi/fastapi-cli/blob/main/release-notes.md"
|
|
51
54
|
|
|
52
55
|
[project.scripts]
|
|
53
56
|
fastapi = "fastapi_cli.cli:main"
|
|
@@ -91,11 +94,14 @@ source = [
|
|
|
91
94
|
"tests",
|
|
92
95
|
]
|
|
93
96
|
context = "${CONTEXT}"
|
|
97
|
+
dynamic_context = "test_function"
|
|
94
98
|
omit = [
|
|
95
99
|
"tests/assets/*",
|
|
96
100
|
]
|
|
97
101
|
|
|
98
102
|
[tool.coverage.report]
|
|
103
|
+
show_missing = true
|
|
104
|
+
sort = "-Cover"
|
|
99
105
|
exclude_lines = [
|
|
100
106
|
"pragma: no cover",
|
|
101
107
|
"@overload",
|
|
@@ -103,6 +109,9 @@ exclude_lines = [
|
|
|
103
109
|
"if TYPE_CHECKING:",
|
|
104
110
|
]
|
|
105
111
|
|
|
112
|
+
[tool.coverage.html]
|
|
113
|
+
show_contexts = true
|
|
114
|
+
|
|
106
115
|
[tool.mypy]
|
|
107
116
|
strict = true
|
|
108
117
|
exclude = [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
smokeshow
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.7"
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import logging
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Any, Union
|
|
3
|
+
from typing import Any, List, Union
|
|
4
4
|
|
|
5
5
|
import typer
|
|
6
6
|
from rich import print
|
|
7
|
-
from rich.
|
|
8
|
-
from rich.panel import Panel
|
|
7
|
+
from rich.tree import Tree
|
|
9
8
|
from typing_extensions import Annotated
|
|
10
9
|
|
|
11
|
-
from fastapi_cli.discover import
|
|
10
|
+
from fastapi_cli.discover import get_import_data
|
|
12
11
|
from fastapi_cli.exceptions import FastAPICLIException
|
|
13
12
|
|
|
14
13
|
from . import __version__
|
|
15
14
|
from .logging import setup_logging
|
|
15
|
+
from .utils.cli import get_rich_toolkit, get_uvicorn_log_config
|
|
16
16
|
|
|
17
17
|
app = typer.Typer(rich_markup_mode="rich")
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
21
|
|
|
22
22
|
try:
|
|
23
23
|
import uvicorn
|
|
@@ -39,15 +39,41 @@ def callback(
|
|
|
39
39
|
"--version", help="Show the version and exit.", callback=version_callback
|
|
40
40
|
),
|
|
41
41
|
] = None,
|
|
42
|
+
verbose: bool = typer.Option(False, help="Enable verbose output"),
|
|
42
43
|
) -> None:
|
|
43
44
|
"""
|
|
44
45
|
FastAPI CLI - The [bold]fastapi[/bold] command line app. 😎
|
|
45
46
|
|
|
46
47
|
Manage your [bold]FastAPI[/bold] projects, run your FastAPI apps, and more.
|
|
47
48
|
|
|
48
|
-
Read more in the docs: [link]https://fastapi.tiangolo.com/fastapi-cli/[/link].
|
|
49
|
+
Read more in the docs: [link=https://fastapi.tiangolo.com/fastapi-cli/]https://fastapi.tiangolo.com/fastapi-cli/[/link].
|
|
49
50
|
"""
|
|
50
51
|
|
|
52
|
+
log_level = logging.DEBUG if verbose else logging.INFO
|
|
53
|
+
|
|
54
|
+
setup_logging(level=log_level)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _get_module_tree(module_paths: List[Path]) -> Tree:
|
|
58
|
+
root = module_paths[0]
|
|
59
|
+
name = f"🐍 {root.name}" if root.is_file() else f"📁 {root.name}"
|
|
60
|
+
|
|
61
|
+
root_tree = Tree(name)
|
|
62
|
+
|
|
63
|
+
if root.is_dir():
|
|
64
|
+
root_tree.add("[dim]🐍 __init__.py[/dim]")
|
|
65
|
+
|
|
66
|
+
tree = root_tree
|
|
67
|
+
for sub_path in module_paths[1:]:
|
|
68
|
+
sub_name = (
|
|
69
|
+
f"🐍 {sub_path.name}" if sub_path.is_file() else f"📁 {sub_path.name}"
|
|
70
|
+
)
|
|
71
|
+
tree = tree.add(sub_name)
|
|
72
|
+
if sub_path.is_dir():
|
|
73
|
+
tree.add("[dim]🐍 __init__.py[/dim]")
|
|
74
|
+
|
|
75
|
+
return root_tree
|
|
76
|
+
|
|
51
77
|
|
|
52
78
|
def _run(
|
|
53
79
|
path: Union[Path, None] = None,
|
|
@@ -61,43 +87,88 @@ def _run(
|
|
|
61
87
|
app: Union[str, None] = None,
|
|
62
88
|
proxy_headers: bool = False,
|
|
63
89
|
) -> None:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
90
|
+
with get_rich_toolkit() as toolkit:
|
|
91
|
+
server_type = "development" if command == "dev" else "production"
|
|
92
|
+
|
|
93
|
+
toolkit.print_title(f"Starting {server_type} server 🚀", tag="FastAPI")
|
|
94
|
+
toolkit.print_line()
|
|
95
|
+
|
|
96
|
+
toolkit.print(
|
|
97
|
+
"Searching for package file structure from directories with [blue]__init__.py[/blue] files"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
import_data = get_import_data(path=path, app_name=app)
|
|
102
|
+
except FastAPICLIException as e:
|
|
103
|
+
toolkit.print_line()
|
|
104
|
+
toolkit.print(f"[error]{e}")
|
|
105
|
+
raise typer.Exit(code=1) from None
|
|
106
|
+
|
|
107
|
+
logger.debug(f"Importing from {import_data.module_data.extra_sys_path}")
|
|
108
|
+
logger.debug(f"Importing module {import_data.module_data.module_import_str}")
|
|
109
|
+
|
|
110
|
+
module_data = import_data.module_data
|
|
111
|
+
import_string = import_data.import_string
|
|
112
|
+
|
|
113
|
+
toolkit.print(f"Importing from {module_data.extra_sys_path}")
|
|
114
|
+
toolkit.print_line()
|
|
115
|
+
|
|
116
|
+
root_tree = _get_module_tree(module_data.module_paths)
|
|
117
|
+
|
|
118
|
+
toolkit.print(root_tree, tag="module")
|
|
119
|
+
toolkit.print_line()
|
|
120
|
+
|
|
121
|
+
toolkit.print(
|
|
122
|
+
"Importing the FastAPI app object from the module with the following code:",
|
|
123
|
+
tag="code",
|
|
78
124
|
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
f"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
125
|
+
toolkit.print_line()
|
|
126
|
+
toolkit.print(
|
|
127
|
+
f"[underline]from [bold]{module_data.module_import_str}[/bold] import [bold]{import_data.app_name}[/bold]"
|
|
128
|
+
)
|
|
129
|
+
toolkit.print_line()
|
|
130
|
+
|
|
131
|
+
toolkit.print(
|
|
132
|
+
f"Using import string: [blue]{import_string}[/]",
|
|
133
|
+
tag="app",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
url = f"http://{host}:{port}"
|
|
137
|
+
url_docs = f"{url}/docs"
|
|
138
|
+
|
|
139
|
+
toolkit.print_line()
|
|
140
|
+
toolkit.print(
|
|
141
|
+
f"Server started at [link={url}]{url}[/]",
|
|
142
|
+
f"Documentation at [link={url_docs}]{url_docs}[/]",
|
|
143
|
+
tag="server",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if command == "dev":
|
|
147
|
+
toolkit.print_line()
|
|
148
|
+
toolkit.print(
|
|
149
|
+
"Running in development mode, for production use: [bold]fastapi run[/]",
|
|
150
|
+
tag="tip",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if not uvicorn:
|
|
154
|
+
raise FastAPICLIException(
|
|
155
|
+
"Could not import Uvicorn, try running 'pip install uvicorn'"
|
|
156
|
+
) from None
|
|
157
|
+
|
|
158
|
+
toolkit.print_line()
|
|
159
|
+
toolkit.print("Logs:")
|
|
160
|
+
toolkit.print_line()
|
|
161
|
+
|
|
162
|
+
uvicorn.run(
|
|
163
|
+
app=import_string,
|
|
164
|
+
host=host,
|
|
165
|
+
port=port,
|
|
166
|
+
reload=reload,
|
|
167
|
+
workers=workers,
|
|
168
|
+
root_path=root_path,
|
|
169
|
+
proxy_headers=proxy_headers,
|
|
170
|
+
log_config=get_uvicorn_log_config(),
|
|
86
171
|
)
|
|
87
|
-
print(Padding(panel, 1))
|
|
88
|
-
if not uvicorn:
|
|
89
|
-
raise FastAPICLIException(
|
|
90
|
-
"Could not import Uvicorn, try running 'pip install uvicorn'"
|
|
91
|
-
) from None
|
|
92
|
-
uvicorn.run(
|
|
93
|
-
app=use_uvicorn_app,
|
|
94
|
-
host=host,
|
|
95
|
-
port=port,
|
|
96
|
-
reload=reload,
|
|
97
|
-
workers=workers,
|
|
98
|
-
root_path=root_path,
|
|
99
|
-
proxy_headers=proxy_headers,
|
|
100
|
-
)
|
|
101
172
|
|
|
102
173
|
|
|
103
174
|
@app.command()
|
|
@@ -3,13 +3,7 @@ import sys
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from logging import getLogger
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Union
|
|
7
|
-
|
|
8
|
-
from rich import print
|
|
9
|
-
from rich.padding import Padding
|
|
10
|
-
from rich.panel import Panel
|
|
11
|
-
from rich.syntax import Syntax
|
|
12
|
-
from rich.tree import Tree
|
|
6
|
+
from typing import List, Union
|
|
13
7
|
|
|
14
8
|
from fastapi_cli.exceptions import FastAPICLIException
|
|
15
9
|
|
|
@@ -45,12 +39,10 @@ def get_default_path() -> Path:
|
|
|
45
39
|
class ModuleData:
|
|
46
40
|
module_import_str: str
|
|
47
41
|
extra_sys_path: Path
|
|
42
|
+
module_paths: List[Path]
|
|
48
43
|
|
|
49
44
|
|
|
50
45
|
def get_module_data_from_path(path: Path) -> ModuleData:
|
|
51
|
-
logger.info(
|
|
52
|
-
"Searching for package file structure from directories with [blue]__init__.py[/blue] files"
|
|
53
|
-
)
|
|
54
46
|
use_path = path.resolve()
|
|
55
47
|
module_path = use_path
|
|
56
48
|
if use_path.is_file() and use_path.stem == "__init__":
|
|
@@ -64,37 +56,12 @@ def get_module_data_from_path(path: Path) -> ModuleData:
|
|
|
64
56
|
extra_sys_path = parent.parent
|
|
65
57
|
else:
|
|
66
58
|
break
|
|
67
|
-
|
|
68
|
-
root = module_paths[0]
|
|
69
|
-
name = f"🐍 {root.name}" if root.is_file() else f"📁 {root.name}"
|
|
70
|
-
root_tree = Tree(name)
|
|
71
|
-
if root.is_dir():
|
|
72
|
-
root_tree.add("[dim]🐍 __init__.py[/dim]")
|
|
73
|
-
tree = root_tree
|
|
74
|
-
for sub_path in module_paths[1:]:
|
|
75
|
-
sub_name = (
|
|
76
|
-
f"🐍 {sub_path.name}" if sub_path.is_file() else f"📁 {sub_path.name}"
|
|
77
|
-
)
|
|
78
|
-
tree = tree.add(sub_name)
|
|
79
|
-
if sub_path.is_dir():
|
|
80
|
-
tree.add("[dim]🐍 __init__.py[/dim]")
|
|
81
|
-
title = "[b green]Python module file[/b green]"
|
|
82
|
-
if len(module_paths) > 1 or module_path.is_dir():
|
|
83
|
-
title = "[b green]Python package file structure[/b green]"
|
|
84
|
-
panel = Padding(
|
|
85
|
-
Panel(
|
|
86
|
-
root_tree,
|
|
87
|
-
title=title,
|
|
88
|
-
expand=False,
|
|
89
|
-
padding=(1, 2),
|
|
90
|
-
),
|
|
91
|
-
1,
|
|
92
|
-
)
|
|
93
|
-
print(panel)
|
|
59
|
+
|
|
94
60
|
module_str = ".".join(p.stem for p in module_paths)
|
|
95
|
-
logger.info(f"Importing module [green]{module_str}[/green]")
|
|
96
61
|
return ModuleData(
|
|
97
|
-
module_import_str=module_str,
|
|
62
|
+
module_import_str=module_str,
|
|
63
|
+
extra_sys_path=extra_sys_path.resolve(),
|
|
64
|
+
module_paths=module_paths,
|
|
98
65
|
)
|
|
99
66
|
|
|
100
67
|
|
|
@@ -136,32 +103,30 @@ def get_app_name(*, mod_data: ModuleData, app_name: Union[str, None] = None) ->
|
|
|
136
103
|
raise FastAPICLIException("Could not find FastAPI app in module, try using --app")
|
|
137
104
|
|
|
138
105
|
|
|
139
|
-
|
|
106
|
+
@dataclass
|
|
107
|
+
class ImportData:
|
|
108
|
+
app_name: str
|
|
109
|
+
module_data: ModuleData
|
|
110
|
+
import_string: str
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_import_data(
|
|
140
114
|
*, path: Union[Path, None] = None, app_name: Union[str, None] = None
|
|
141
|
-
) ->
|
|
115
|
+
) -> ImportData:
|
|
142
116
|
if not path:
|
|
143
117
|
path = get_default_path()
|
|
144
|
-
|
|
145
|
-
logger.
|
|
118
|
+
|
|
119
|
+
logger.debug(f"Using path [blue]{path}[/blue]")
|
|
120
|
+
logger.debug(f"Resolved absolute path {path.resolve()}")
|
|
121
|
+
|
|
146
122
|
if not path.exists():
|
|
147
123
|
raise FastAPICLIException(f"Path does not exist {path}")
|
|
148
124
|
mod_data = get_module_data_from_path(path)
|
|
149
125
|
sys.path.insert(0, str(mod_data.extra_sys_path))
|
|
150
126
|
use_app_name = get_app_name(mod_data=mod_data, app_name=app_name)
|
|
151
|
-
|
|
152
|
-
f"from {mod_data.module_import_str} import {use_app_name}", "python"
|
|
153
|
-
)
|
|
154
|
-
import_panel = Padding(
|
|
155
|
-
Panel(
|
|
156
|
-
import_example,
|
|
157
|
-
title="[b green]Importable FastAPI app[/b green]",
|
|
158
|
-
expand=False,
|
|
159
|
-
padding=(1, 2),
|
|
160
|
-
),
|
|
161
|
-
1,
|
|
162
|
-
)
|
|
163
|
-
logger.info("Found importable FastAPI app")
|
|
164
|
-
print(import_panel)
|
|
127
|
+
|
|
165
128
|
import_string = f"{mod_data.module_import_str}:{use_app_name}"
|
|
166
|
-
|
|
167
|
-
return
|
|
129
|
+
|
|
130
|
+
return ImportData(
|
|
131
|
+
app_name=use_app_name, module_data=mod_data, import_string=import_string
|
|
132
|
+
)
|
|
@@ -5,7 +5,9 @@ from rich.console import Console
|
|
|
5
5
|
from rich.logging import RichHandler
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def setup_logging(
|
|
8
|
+
def setup_logging(
|
|
9
|
+
terminal_width: Union[int, None] = None, level: int = logging.INFO
|
|
10
|
+
) -> None:
|
|
9
11
|
logger = logging.getLogger("fastapi_cli")
|
|
10
12
|
console = Console(width=terminal_width) if terminal_width else None
|
|
11
13
|
rich_handler = RichHandler(
|
|
@@ -19,5 +21,5 @@ def setup_logging(terminal_width: Union[int, None] = None) -> None:
|
|
|
19
21
|
rich_handler.setFormatter(logging.Formatter("%(message)s"))
|
|
20
22
|
logger.addHandler(rich_handler)
|
|
21
23
|
|
|
22
|
-
logger.setLevel(
|
|
24
|
+
logger.setLevel(level)
|
|
23
25
|
logger.propagate = False
|