1- from logging import getLogger
1+ import logging
22from pathlib import Path
3- from typing import Any , Union
3+ from typing import Any , List , Union
44
55import typer
66from rich import print
7- from rich .padding import Padding
8- from rich .panel import Panel
7+ from rich .tree import Tree
98from typing_extensions import Annotated
109
11- from fastapi_cli .discover import get_import_string
10+ from fastapi_cli .discover import get_import_data
1211from fastapi_cli .exceptions import FastAPICLIException
1312
1413from . import __version__
1514from .logging import setup_logging
15+ from .utils .cli import get_rich_toolkit , get_uvicorn_log_config
1616
1717app = typer .Typer (rich_markup_mode = "rich" )
1818
19- setup_logging ( )
20- logger = getLogger ( __name__ )
19+ logger = logging . getLogger ( __name__ )
20+
2121
2222try :
2323 import uvicorn
@@ -39,6 +39,7 @@ def callback(
3939 "--version" , help = "Show the version and exit." , callback = version_callback
4040 ),
4141 ] = None ,
42+ verbose : bool = typer .Option (False , help = "Enable verbose output" ),
4243) -> None :
4344 """
4445 FastAPI CLI - The [bold]fastapi[/bold] command line app. 😎
@@ -48,6 +49,31 @@ def callback(
4849 Read more in the docs: [link=https://fastapi.tiangolo.com/fastapi-cli/]https://fastapi.tiangolo.com/fastapi-cli/[/link].
4950 """
5051
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+
5177
5278def _run (
5379 path : Union [Path , None ] = None ,
@@ -61,45 +87,88 @@ def _run(
6187 app : Union [str , None ] = None ,
6288 proxy_headers : bool = False ,
6389) -> None :
64- try :
65- use_uvicorn_app = get_import_string (path = path , app_name = app )
66- except FastAPICLIException as e :
67- logger .error (str (e ))
68- raise typer .Exit (code = 1 ) from None
69- url = f"http://{ host } :{ port } "
70- url_docs = f"{ url } /docs"
71- serving_str = f"[dim]Serving at:[/dim] [link={ url } ]{ url } [/link]\n \n [dim]API docs:[/dim] [link={ url_docs } ]{ url_docs } [/link]"
72-
73- if command == "dev" :
74- panel = Panel (
75- f"{ serving_str } \n \n [dim]Running in development mode, for production use:[/dim] \n \n [b]fastapi run[/b]" ,
76- title = "FastAPI CLI - Development mode" ,
77- expand = False ,
78- padding = (1 , 2 ),
79- style = "black on yellow" ,
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" ,
80124 )
81- else :
82- panel = Panel (
83- f"{ serving_str } \n \n [dim]Running in production mode, for development use:[/dim] \n \n [b]fastapi dev[/b]" ,
84- title = "FastAPI CLI - Production mode" ,
85- expand = False ,
86- padding = (1 , 2 ),
87- style = "green" ,
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 (),
88171 )
89- print (Padding (panel , 1 ))
90- if not uvicorn :
91- raise FastAPICLIException (
92- "Could not import Uvicorn, try running 'pip install uvicorn'"
93- ) from None
94- uvicorn .run (
95- app = use_uvicorn_app ,
96- host = host ,
97- port = port ,
98- reload = reload ,
99- workers = workers ,
100- root_path = root_path ,
101- proxy_headers = proxy_headers ,
102- )
103172
104173
105174@app .command ()
0 commit comments