fastapi-cli 0.0.1__py3-none-any.whl โ 0.0.2__py3-none-any.whl
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/__init__.py +1 -3
- fastapi_cli/__main__.py +3 -0
- fastapi_cli/cli.py +260 -0
- fastapi_cli/discover.py +163 -0
- fastapi_cli/exceptions.py +2 -0
- fastapi_cli/logging.py +23 -0
- fastapi_cli/py.typed +0 -0
- fastapi_cli-0.0.2.dist-info/METADATA +143 -0
- fastapi_cli-0.0.2.dist-info/RECORD +12 -0
- {fastapi_cli-0.0.1.dist-info โ fastapi_cli-0.0.2.dist-info}/WHEEL +1 -1
- fastapi_cli-0.0.2.dist-info/entry_points.txt +3 -0
- fastapi_cli-0.0.2.dist-info/licenses/LICENSE +21 -0
- fastapi_cli-0.0.1.dist-info/METADATA +0 -11
- fastapi_cli-0.0.1.dist-info/RECORD +0 -4
fastapi_cli/__init__.py
CHANGED
fastapi_cli/__main__.py
ADDED
fastapi_cli/cli.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
from logging import getLogger
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Union
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
import uvicorn
|
|
7
|
+
from rich import print
|
|
8
|
+
from rich.padding import Padding
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from typing_extensions import Annotated
|
|
11
|
+
|
|
12
|
+
from fastapi_cli.discover import get_import_string
|
|
13
|
+
from fastapi_cli.exceptions import FastAPICLIException
|
|
14
|
+
|
|
15
|
+
from . import __version__
|
|
16
|
+
from .logging import setup_logging
|
|
17
|
+
|
|
18
|
+
app = typer.Typer(rich_markup_mode="rich")
|
|
19
|
+
|
|
20
|
+
setup_logging()
|
|
21
|
+
logger = getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def version_callback(value: bool) -> None:
|
|
25
|
+
if value:
|
|
26
|
+
print(f"FastAPI CLI version: [green]{__version__}[/green]")
|
|
27
|
+
raise typer.Exit()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.callback()
|
|
31
|
+
def callback(
|
|
32
|
+
version: Annotated[
|
|
33
|
+
Union[bool, None],
|
|
34
|
+
typer.Option(
|
|
35
|
+
"--version", help="Show the version and exit.", callback=version_callback
|
|
36
|
+
),
|
|
37
|
+
] = None,
|
|
38
|
+
) -> None:
|
|
39
|
+
"""
|
|
40
|
+
FastAPI CLI - The [bold]fastapi[/bold] command line app. ๐
|
|
41
|
+
|
|
42
|
+
Manage your [bold]FastAPI[/bold] projects, run your FastAPI apps, and more.
|
|
43
|
+
|
|
44
|
+
Read more in the docs: [link]https://fastapi.tiangolo.com/fastapi-cli/[/link].
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _run(
|
|
49
|
+
path: Union[Path, None] = None,
|
|
50
|
+
*,
|
|
51
|
+
host: str = "127.0.0.1",
|
|
52
|
+
port: int = 8000,
|
|
53
|
+
reload: bool = True,
|
|
54
|
+
root_path: str = "",
|
|
55
|
+
command: str,
|
|
56
|
+
app: Union[str, None] = None,
|
|
57
|
+
proxy_headers: bool = False,
|
|
58
|
+
) -> None:
|
|
59
|
+
try:
|
|
60
|
+
use_uvicorn_app = get_import_string(path=path, app_name=app)
|
|
61
|
+
except FastAPICLIException as e:
|
|
62
|
+
logger.error(str(e))
|
|
63
|
+
raise typer.Exit(code=1) from None
|
|
64
|
+
serving_str = f"[dim]Serving at:[/dim] [link]http://{host}:{port}[/link]\n\n[dim]API docs:[/dim] [link]http://{host}:{port}/docs[/link]"
|
|
65
|
+
|
|
66
|
+
if command == "dev":
|
|
67
|
+
panel = Panel(
|
|
68
|
+
f"{serving_str}\n\n[dim]Running in development mode, for production use:[/dim] \n\n[b]fastapi run[/b]",
|
|
69
|
+
title="FastAPI CLI - Development mode",
|
|
70
|
+
expand=False,
|
|
71
|
+
padding=(1, 2),
|
|
72
|
+
style="black on yellow",
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
panel = Panel(
|
|
76
|
+
f"{serving_str}\n\n[dim]Running in production mode, for development use:[/dim] \n\n[b]fastapi dev[/b]",
|
|
77
|
+
title="FastAPI CLI - Production mode",
|
|
78
|
+
expand=False,
|
|
79
|
+
padding=(1, 2),
|
|
80
|
+
style="green",
|
|
81
|
+
)
|
|
82
|
+
print(Padding(panel, 1))
|
|
83
|
+
uvicorn.run(
|
|
84
|
+
app=use_uvicorn_app,
|
|
85
|
+
host=host,
|
|
86
|
+
port=port,
|
|
87
|
+
reload=reload,
|
|
88
|
+
root_path=root_path,
|
|
89
|
+
proxy_headers=proxy_headers,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@app.command()
|
|
94
|
+
def dev(
|
|
95
|
+
path: Annotated[
|
|
96
|
+
Union[Path, None],
|
|
97
|
+
typer.Argument(
|
|
98
|
+
help="A path to a Python file or package directory (with [blue]__init__.py[/blue] files) containing a [bold]FastAPI[/bold] app. If not provided, a default set of paths will be tried."
|
|
99
|
+
),
|
|
100
|
+
] = None,
|
|
101
|
+
*,
|
|
102
|
+
host: Annotated[
|
|
103
|
+
str,
|
|
104
|
+
typer.Option(
|
|
105
|
+
help="The host to serve on. For local development in localhost use [blue]127.0.0.1[/blue]. To enable public access, e.g. in a container, use all the IP addresses available with [blue]0.0.0.0[/blue]."
|
|
106
|
+
),
|
|
107
|
+
] = "127.0.0.1",
|
|
108
|
+
port: Annotated[
|
|
109
|
+
int,
|
|
110
|
+
typer.Option(
|
|
111
|
+
help="The port to serve on. You would normally have a termination proxy on top (another program) handling HTTPS on port [blue]443[/blue] and HTTP on port [blue]80[/blue], transferring the communication to your app."
|
|
112
|
+
),
|
|
113
|
+
] = 8000,
|
|
114
|
+
reload: Annotated[
|
|
115
|
+
bool,
|
|
116
|
+
typer.Option(
|
|
117
|
+
help="Enable auto-reload of the server when (code) files change. This is [bold]resource intensive[/bold], use it only during development."
|
|
118
|
+
),
|
|
119
|
+
] = True,
|
|
120
|
+
root_path: Annotated[
|
|
121
|
+
str,
|
|
122
|
+
typer.Option(
|
|
123
|
+
help="The root path is used to tell your app that it is being served to the outside world with some [bold]path prefix[/bold] set up in some termination proxy or similar."
|
|
124
|
+
),
|
|
125
|
+
] = "",
|
|
126
|
+
app: Annotated[
|
|
127
|
+
Union[str, None],
|
|
128
|
+
typer.Option(
|
|
129
|
+
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."
|
|
130
|
+
),
|
|
131
|
+
] = None,
|
|
132
|
+
proxy_headers: Annotated[
|
|
133
|
+
bool,
|
|
134
|
+
typer.Option(
|
|
135
|
+
help="Enable/Disable X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info."
|
|
136
|
+
),
|
|
137
|
+
] = True,
|
|
138
|
+
) -> Any:
|
|
139
|
+
"""
|
|
140
|
+
Run a [bold]FastAPI[/bold] app in [yellow]development[/yellow] mode. ๐งช
|
|
141
|
+
|
|
142
|
+
This is equivalent to [bold]fastapi run[/bold] but with [bold]reload[/bold] enabled and listening on the [blue]127.0.0.1[/blue] address.
|
|
143
|
+
|
|
144
|
+
It automatically detects the Python module or package that needs to be imported based on the file or directory path passed.
|
|
145
|
+
|
|
146
|
+
If no path is passed, it tries with:
|
|
147
|
+
|
|
148
|
+
- [blue]main.py[/blue]
|
|
149
|
+
- [blue]app.py[/blue]
|
|
150
|
+
- [blue]api.py[/blue]
|
|
151
|
+
- [blue]app/main.py[/blue]
|
|
152
|
+
- [blue]app/app.py[/blue]
|
|
153
|
+
- [blue]app/api.py[/blue]
|
|
154
|
+
|
|
155
|
+
It also detects the directory that needs to be added to the [bold]PYTHONPATH[/bold] to make the app importable and adds it.
|
|
156
|
+
|
|
157
|
+
It detects the [bold]FastAPI[/bold] app object to use. By default it looks in the module or package for an object named:
|
|
158
|
+
|
|
159
|
+
- [blue]app[/blue]
|
|
160
|
+
- [blue]api[/blue]
|
|
161
|
+
|
|
162
|
+
Otherwise, it uses the first [bold]FastAPI[/bold] app found in the imported module or package.
|
|
163
|
+
"""
|
|
164
|
+
_run(
|
|
165
|
+
path=path,
|
|
166
|
+
host=host,
|
|
167
|
+
port=port,
|
|
168
|
+
reload=reload,
|
|
169
|
+
root_path=root_path,
|
|
170
|
+
app=app,
|
|
171
|
+
command="dev",
|
|
172
|
+
proxy_headers=proxy_headers,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@app.command()
|
|
177
|
+
def run(
|
|
178
|
+
path: Annotated[
|
|
179
|
+
Union[Path, None],
|
|
180
|
+
typer.Argument(
|
|
181
|
+
help="A path to a Python file or package directory (with [blue]__init__.py[/blue] files) containing a [bold]FastAPI[/bold] app. If not provided, a default set of paths will be tried."
|
|
182
|
+
),
|
|
183
|
+
] = None,
|
|
184
|
+
*,
|
|
185
|
+
host: Annotated[
|
|
186
|
+
str,
|
|
187
|
+
typer.Option(
|
|
188
|
+
help="The host to serve on. For local development in localhost use [blue]127.0.0.1[/blue]. To enable public access, e.g. in a container, use all the IP addresses available with [blue]0.0.0.0[/blue]."
|
|
189
|
+
),
|
|
190
|
+
] = "0.0.0.0",
|
|
191
|
+
port: Annotated[
|
|
192
|
+
int,
|
|
193
|
+
typer.Option(
|
|
194
|
+
help="The port to serve on. You would normally have a termination proxy on top (another program) handling HTTPS on port [blue]443[/blue] and HTTP on port [blue]80[/blue], transferring the communication to your app."
|
|
195
|
+
),
|
|
196
|
+
] = 8000,
|
|
197
|
+
reload: Annotated[
|
|
198
|
+
bool,
|
|
199
|
+
typer.Option(
|
|
200
|
+
help="Enable auto-reload of the server when (code) files change. This is [bold]resource intensive[/bold], use it only during development."
|
|
201
|
+
),
|
|
202
|
+
] = False,
|
|
203
|
+
root_path: Annotated[
|
|
204
|
+
str,
|
|
205
|
+
typer.Option(
|
|
206
|
+
help="The root path is used to tell your app that it is being served to the outside world with some [bold]path prefix[/bold] set up in some termination proxy or similar."
|
|
207
|
+
),
|
|
208
|
+
] = "",
|
|
209
|
+
app: Annotated[
|
|
210
|
+
Union[str, None],
|
|
211
|
+
typer.Option(
|
|
212
|
+
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."
|
|
213
|
+
),
|
|
214
|
+
] = None,
|
|
215
|
+
proxy_headers: Annotated[
|
|
216
|
+
bool,
|
|
217
|
+
typer.Option(
|
|
218
|
+
help="Enable/Disable X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info."
|
|
219
|
+
),
|
|
220
|
+
] = True,
|
|
221
|
+
) -> Any:
|
|
222
|
+
"""
|
|
223
|
+
Run a [bold]FastAPI[/bold] app in [green]production[/green] mode. ๐
|
|
224
|
+
|
|
225
|
+
This is equivalent to [bold]fastapi dev[/bold] but with [bold]reload[/bold] disabled and listening on the [blue]0.0.0.0[/blue] address.
|
|
226
|
+
|
|
227
|
+
It automatically detects the Python module or package that needs to be imported based on the file or directory path passed.
|
|
228
|
+
|
|
229
|
+
If no path is passed, it tries with:
|
|
230
|
+
|
|
231
|
+
- [blue]main.py[/blue]
|
|
232
|
+
- [blue]app.py[/blue]
|
|
233
|
+
- [blue]api.py[/blue]
|
|
234
|
+
- [blue]app/main.py[/blue]
|
|
235
|
+
- [blue]app/app.py[/blue]
|
|
236
|
+
- [blue]app/api.py[/blue]
|
|
237
|
+
|
|
238
|
+
It also detects the directory that needs to be added to the [bold]PYTHONPATH[/bold] to make the app importable and adds it.
|
|
239
|
+
|
|
240
|
+
It detects the [bold]FastAPI[/bold] app object to use. By default it looks in the module or package for an object named:
|
|
241
|
+
|
|
242
|
+
- [blue]app[/blue]
|
|
243
|
+
- [blue]api[/blue]
|
|
244
|
+
|
|
245
|
+
Otherwise, it uses the first [bold]FastAPI[/bold] app found in the imported module or package.
|
|
246
|
+
"""
|
|
247
|
+
_run(
|
|
248
|
+
path=path,
|
|
249
|
+
host=host,
|
|
250
|
+
port=port,
|
|
251
|
+
reload=reload,
|
|
252
|
+
root_path=root_path,
|
|
253
|
+
app=app,
|
|
254
|
+
command="run",
|
|
255
|
+
proxy_headers=proxy_headers,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def main() -> None:
|
|
260
|
+
app()
|
fastapi_cli/discover.py
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import sys
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from logging import getLogger
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
from fastapi import FastAPI
|
|
9
|
+
from rich import print
|
|
10
|
+
from rich.padding import Padding
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
from rich.syntax import Syntax
|
|
13
|
+
from rich.tree import Tree
|
|
14
|
+
|
|
15
|
+
from fastapi_cli.exceptions import FastAPICLIException
|
|
16
|
+
|
|
17
|
+
logger = getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
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
|
|
39
|
+
raise FastAPICLIException(
|
|
40
|
+
"Could not find a default file to run, please provide an explicit path"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class ModuleData:
|
|
46
|
+
module_import_str: str
|
|
47
|
+
extra_sys_path: Path
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
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
|
+
use_path = path.resolve()
|
|
55
|
+
module_path = use_path
|
|
56
|
+
if use_path.is_file() and use_path.stem == "__init__":
|
|
57
|
+
module_path = use_path.parent
|
|
58
|
+
module_paths = [module_path]
|
|
59
|
+
extra_sys_path = module_path.parent
|
|
60
|
+
for parent in module_path.parents:
|
|
61
|
+
init_path = parent / "__init__.py"
|
|
62
|
+
if init_path.is_file():
|
|
63
|
+
module_paths.insert(0, parent)
|
|
64
|
+
extra_sys_path = parent.parent
|
|
65
|
+
else:
|
|
66
|
+
break
|
|
67
|
+
logger.info(f"Importing from {extra_sys_path.resolve()}")
|
|
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)
|
|
94
|
+
module_str = ".".join(p.stem for p in module_paths)
|
|
95
|
+
logger.info(f"Importing module [green]{module_str}[/green]")
|
|
96
|
+
return ModuleData(
|
|
97
|
+
module_import_str=module_str, extra_sys_path=extra_sys_path.resolve()
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_app_name(*, mod_data: ModuleData, app_name: Union[str, None] = None) -> str:
|
|
102
|
+
try:
|
|
103
|
+
mod = importlib.import_module(mod_data.module_import_str)
|
|
104
|
+
except (ImportError, ValueError) as e:
|
|
105
|
+
logger.error(f"Import error: {e}")
|
|
106
|
+
logger.warning(
|
|
107
|
+
"Ensure all the package directories have an [blue]__init__.py[/blue] file"
|
|
108
|
+
)
|
|
109
|
+
raise
|
|
110
|
+
object_names = dir(mod)
|
|
111
|
+
object_names_set = set(object_names)
|
|
112
|
+
if app_name:
|
|
113
|
+
if app_name not in object_names_set:
|
|
114
|
+
raise FastAPICLIException(
|
|
115
|
+
f"Could not find app name {app_name} in {mod_data.module_import_str}"
|
|
116
|
+
)
|
|
117
|
+
app = getattr(mod, app_name)
|
|
118
|
+
if not isinstance(app, FastAPI):
|
|
119
|
+
raise FastAPICLIException(
|
|
120
|
+
f"The app name {app_name} in {mod_data.module_import_str} doesn't seem to be a FastAPI app"
|
|
121
|
+
)
|
|
122
|
+
return app_name
|
|
123
|
+
for preferred_name in ["app", "api"]:
|
|
124
|
+
if preferred_name in object_names_set:
|
|
125
|
+
obj = getattr(mod, preferred_name)
|
|
126
|
+
if isinstance(obj, FastAPI):
|
|
127
|
+
return preferred_name
|
|
128
|
+
for name in object_names:
|
|
129
|
+
obj = getattr(mod, name)
|
|
130
|
+
if isinstance(obj, FastAPI):
|
|
131
|
+
return name
|
|
132
|
+
raise FastAPICLIException("Could not find FastAPI app in module, try using --app")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_import_string(
|
|
136
|
+
*, path: Union[Path, None] = None, app_name: Union[str, None] = None
|
|
137
|
+
) -> str:
|
|
138
|
+
if not path:
|
|
139
|
+
path = get_default_path()
|
|
140
|
+
logger.info(f"Using path [blue]{path}[/blue]")
|
|
141
|
+
logger.info(f"Resolved absolute path {path.resolve()}")
|
|
142
|
+
if not path.exists():
|
|
143
|
+
raise FastAPICLIException(f"Path does not exist {path}")
|
|
144
|
+
mod_data = get_module_data_from_path(path)
|
|
145
|
+
sys.path.insert(0, str(mod_data.extra_sys_path))
|
|
146
|
+
use_app_name = get_app_name(mod_data=mod_data, app_name=app_name)
|
|
147
|
+
import_example = Syntax(
|
|
148
|
+
f"from {mod_data.module_import_str} import {use_app_name}", "python"
|
|
149
|
+
)
|
|
150
|
+
import_panel = Padding(
|
|
151
|
+
Panel(
|
|
152
|
+
import_example,
|
|
153
|
+
title="[b green]Importable FastAPI app[/b green]",
|
|
154
|
+
expand=False,
|
|
155
|
+
padding=(1, 2),
|
|
156
|
+
),
|
|
157
|
+
1,
|
|
158
|
+
)
|
|
159
|
+
logger.info("Found importable FastAPI app")
|
|
160
|
+
print(import_panel)
|
|
161
|
+
import_string = f"{mod_data.module_import_str}:{use_app_name}"
|
|
162
|
+
logger.info(f"Using import string [b green]{import_string}[/b green]")
|
|
163
|
+
return import_string
|
fastapi_cli/logging.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.logging import RichHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def setup_logging(terminal_width: Union[int, None] = None) -> None:
|
|
9
|
+
logger = logging.getLogger("fastapi_cli")
|
|
10
|
+
console = Console(width=terminal_width) if terminal_width else None
|
|
11
|
+
rich_handler = RichHandler(
|
|
12
|
+
show_time=False,
|
|
13
|
+
rich_tracebacks=True,
|
|
14
|
+
tracebacks_show_locals=True,
|
|
15
|
+
markup=True,
|
|
16
|
+
show_path=False,
|
|
17
|
+
console=console,
|
|
18
|
+
)
|
|
19
|
+
rich_handler.setFormatter(logging.Formatter("%(message)s"))
|
|
20
|
+
logger.addHandler(rich_handler)
|
|
21
|
+
|
|
22
|
+
logger.setLevel(logging.INFO)
|
|
23
|
+
logger.propagate = False
|
fastapi_cli/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: fastapi-cli
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Run and manage FastAPI apps from the command line with FastAPI CLI. ๐
|
|
5
|
+
Home-page: https://github.com/tiangolo/fastapi-cli
|
|
6
|
+
Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Intended Audience :: Information Technology
|
|
9
|
+
Classifier: Intended Audience :: System Administrators
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Classifier: Topic :: Software Development
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Classifier: Development Status :: 4 - Beta
|
|
19
|
+
Classifier: Framework :: FastAPI
|
|
20
|
+
Classifier: Intended Audience :: Developers
|
|
21
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
22
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
29
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
30
|
+
Project-URL: Documentation, https://fastapi.tiangolo.com
|
|
31
|
+
Project-URL: Homepage, https://github.com/tiangolo/fastapi-cli
|
|
32
|
+
Project-URL: Repository, https://github.com/tiangolo/fastapi-cli
|
|
33
|
+
Requires-Python: >=3.8
|
|
34
|
+
Requires-Dist: typer>=0.12.3
|
|
35
|
+
Requires-Dist: fastapi
|
|
36
|
+
Requires-Dist: uvicorn[standard]>=0.29.0
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# FastAPI CLI
|
|
40
|
+
|
|
41
|
+
<a href="https://github.com/tiangolo/fastapi-cli/actions/workflows/test.yml" target="_blank">
|
|
42
|
+
<img src="https://github.com/tiangolo/fastapi-cli/actions/workflows/test.yml/badge.svg" alt="Test">
|
|
43
|
+
</a>
|
|
44
|
+
<a href="https://github.com/tiangolo/fastapi-cli/actions/workflows/publish.yml" target="_blank">
|
|
45
|
+
<img src="https://github.com/tiangolo/fastapi-cli/actions/workflows/publish.yml/badge.svg" alt="Publish">
|
|
46
|
+
</a>
|
|
47
|
+
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/tiangolo/fastapi-cli" target="_blank">
|
|
48
|
+
<img src="https://coverage-badge.samuelcolvin.workers.dev/tiangolo/fastapi-cli.svg" alt="Coverage">
|
|
49
|
+
<a href="https://pypi.org/project/fastapi-cli" target="_blank">
|
|
50
|
+
<img src="https://img.shields.io/pypi/v/fastapi-cli?color=%2334D058&label=pypi%20package" alt="Package version">
|
|
51
|
+
</a>
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
**Source Code**: <a href="https://github.com/tiangolo/fastapi-cli" target="_blank">https://github.com/tiangolo/fastapi-cli</a>
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
Run and manage FastAPI apps from the command line with FastAPI CLI. ๐
|
|
60
|
+
|
|
61
|
+
## Description
|
|
62
|
+
|
|
63
|
+
**FastAPI CLI** is a command line program `fastapi` that you can use to serve your FastAPI app, manage your FastAPI project, and more.
|
|
64
|
+
|
|
65
|
+
When you install FastAPI (e.g. with `pip install fastapi`), it includes a package called `fastapi-cli`, this package provides the `fastapi` command in the terminal.
|
|
66
|
+
|
|
67
|
+
To run your FastAPI app for development, you can use the `fastapi dev` command:
|
|
68
|
+
|
|
69
|
+
<div class="termy">
|
|
70
|
+
|
|
71
|
+
```console
|
|
72
|
+
$ fastapi dev main.py
|
|
73
|
+
INFO Using path main.py
|
|
74
|
+
INFO Resolved absolute path /home/user/code/awesomeapp/main.py
|
|
75
|
+
INFO Searching for package file structure from directories with __init__.py files
|
|
76
|
+
INFO Importing from /home/user/code/awesomeapp
|
|
77
|
+
|
|
78
|
+
โญโ Python module file โโฎ
|
|
79
|
+
โ โ
|
|
80
|
+
โ ๐ main.py โ
|
|
81
|
+
โ โ
|
|
82
|
+
โฐโโโโโโโโโโโโโโโโโโโโโโโฏ
|
|
83
|
+
|
|
84
|
+
INFO Importing module main
|
|
85
|
+
INFO Found importable FastAPI app
|
|
86
|
+
|
|
87
|
+
โญโ Importable FastAPI app โโฎ
|
|
88
|
+
โ โ
|
|
89
|
+
โ from main import app โ
|
|
90
|
+
โ โ
|
|
91
|
+
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
|
|
92
|
+
|
|
93
|
+
INFO Using import string main:app
|
|
94
|
+
|
|
95
|
+
โญโโโโโโโโโโ FastAPI CLI - Development mode โโโโโโโโโโโโฎ
|
|
96
|
+
โ โ
|
|
97
|
+
โ Serving at: http://127.0.0.1:8000 โ
|
|
98
|
+
โ โ
|
|
99
|
+
โ API docs: http://127.0.0.1:8000/docs โ
|
|
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.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
That command line program called `fastapi` is **FastAPI CLI**.
|
|
118
|
+
|
|
119
|
+
FastAPI CLI takes the path to your Python program and automatically detects the variable with the FastAPI (commonly named `app`) and how to import it, and then serves it.
|
|
120
|
+
|
|
121
|
+
For production you would use `fastapi run` instead. ๐
|
|
122
|
+
|
|
123
|
+
## `fastapi dev`
|
|
124
|
+
|
|
125
|
+
When you run `fastapi dev`, it will run on development mode.
|
|
126
|
+
|
|
127
|
+
By default, it will have **auto-reload** enabled, so it will automatically reload the server when you make changes to your code. This is resource intensive and could be less stable than without it, you should only use it for development.
|
|
128
|
+
|
|
129
|
+
By default it will listen on the IP address `127.0.0.1`, which is the IP for your machine to communicate with itself alone (`localhost`).
|
|
130
|
+
|
|
131
|
+
## `fastapi run`
|
|
132
|
+
|
|
133
|
+
When you run `fastapi run`, it will run on production mode by default.
|
|
134
|
+
|
|
135
|
+
It will have **auto-reload disabled** by default.
|
|
136
|
+
|
|
137
|
+
It will listen on the IP address `0.0.0.0`, which means all the available IP addresses, this way it will be publicly accessible to anyone that can communicate with the machine. This is how you would normally run it in production, for example, in a container.
|
|
138
|
+
|
|
139
|
+
In most cases you would (and should) have a "termination proxy" handling HTTPS for you on top, this will depend on how you deploy your application, your provider might do this for you, or you might need to set it up yourself. You can learn more about it in the <a href="https://fastapi.tiangolo.com/deployment/" class="external-link" target="_blank">FastAPI Deployment documentation</a>.
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
This project is licensed under the terms of the MIT license.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
fastapi_cli-0.0.2.dist-info/METADATA,sha256=DADt2yADHsKGZzCrzC4bcnF7ZKyHZnmaGPXSjmEzRVc,6780
|
|
2
|
+
fastapi_cli-0.0.2.dist-info/WHEEL,sha256=vnE8JVcI2Wz7GRKorsPArnBdnW2SWKWGow5gu5tHlRU,90
|
|
3
|
+
fastapi_cli-0.0.2.dist-info/entry_points.txt,sha256=RLUGtkrAf9gNKxCS3EeJNYN8AF1Er364vjW7bnEcCA8,50
|
|
4
|
+
fastapi_cli-0.0.2.dist-info/licenses/LICENSE,sha256=FqD5B4VbXJnefprQseE0U8llL6FxojC-i8muZy7YmSU,1086
|
|
5
|
+
fastapi_cli/__init__.py,sha256=QvlVh4JTl3JL7jQAja76yKtT-IvF4631ASjWY1wS6AQ,22
|
|
6
|
+
fastapi_cli/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
|
|
7
|
+
fastapi_cli/cli.py,sha256=OkiQenSf9HgBN7FxTTAoLfzqySsX1Z6FGxlRU7ILcGM,8754
|
|
8
|
+
fastapi_cli/discover.py,sha256=5QbjDHEbfNUQoYG7ZXRfYWvSJkj74ojkFtzUftPb2VE,5285
|
|
9
|
+
fastapi_cli/exceptions.py,sha256=AHRSqd43fbqN5IpX-Fq389k9MoEK_q28wVFL7oqPNcc,47
|
|
10
|
+
fastapi_cli/logging.py,sha256=lI7rIsioTJQsxDuWpG5YR_brWpIAUY4vDnhYm5p91ws,664
|
|
11
|
+
fastapi_cli/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
fastapi_cli-0.0.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Sebastiรกn Ramรญrez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: fastapi-cli
|
|
3
|
-
Version: 0.0.1
|
|
4
|
-
Summary:
|
|
5
|
-
Author: Sebastiรกn Ramรญrez
|
|
6
|
-
Author-email: tiangolo@gmail.com
|
|
7
|
-
Requires-Python: >=3.6,<4.0
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
11
|
-
Requires-Dist: importlib_metadata (>=1.5,<2.0)
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
fastapi_cli/__init__.py,sha256=5RpLGahop916SeM-IBybvWyDoKIuatfa3Aw-NIlBIgA,75
|
|
2
|
-
fastapi_cli-0.0.1.dist-info/WHEEL,sha256=f_L0I4hqSDuunYLcjib7afhVEQa4uCwremk0_wPx54s,85
|
|
3
|
-
fastapi_cli-0.0.1.dist-info/METADATA,sha256=w7fBwjwDWvtDXARBL_HqBIUjTa0r76nhlyhsXm2UEgw,349
|
|
4
|
-
fastapi_cli-0.0.1.dist-info/RECORD,,
|