Skip to content

Commit fe8ca93

Browse files
committed
rebasing onto main
1 parent 7d048df commit fe8ca93

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

src/fastapi_cli/cli.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def _run(
100100
entrypoint: Union[str, None] = None,
101101
proxy_headers: bool = False,
102102
forwarded_allow_ips: Union[str, None] = None,
103+
is_factory: bool = False,
103104
) -> None:
104105
with get_rich_toolkit() as toolkit:
105106
server_type = "development" if command == "dev" else "production"
@@ -187,6 +188,7 @@ def _run(
187188
proxy_headers=proxy_headers,
188189
forwarded_allow_ips=forwarded_allow_ips,
189190
log_config=get_uvicorn_log_config(),
191+
factory=is_factory,
190192
)
191193

192194

@@ -195,7 +197,7 @@ def dev(
195197
path: Annotated[
196198
Union[Path, None],
197199
typer.Argument(
198-
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."
200+
help="A path to a Python file or package directory (with [blue]__init__.py[/blue] files) containing a [bold]FastAPI[/bold] app or app factory. If not provided, a default set of paths will be tried."
199201
),
200202
] = None,
201203
*,
@@ -250,6 +252,12 @@ def dev(
250252
help="Comma separated list of IP Addresses to trust with proxy headers. The literal '*' means trust everything."
251253
),
252254
] = None,
255+
factory: Annotated[
256+
bool,
257+
typer.Option(
258+
help="Treat [bold]path[bold] as an application factory, i.e. a () -> <ASGI app> callable."
259+
),
260+
] = False,
253261
) -> Any:
254262
"""
255263
Run a [bold]FastAPI[/bold] app in [yellow]development[/yellow] mode. 🧪
@@ -287,6 +295,7 @@ def dev(
287295
command="dev",
288296
proxy_headers=proxy_headers,
289297
forwarded_allow_ips=forwarded_allow_ips,
298+
is_factory=factory,
290299
)
291300

292301

@@ -356,6 +365,12 @@ def run(
356365
help="Comma separated list of IP Addresses to trust with proxy headers. The literal '*' means trust everything."
357366
),
358367
] = None,
368+
factory: Annotated[
369+
bool,
370+
typer.Option(
371+
help="Treat [bold]path[bold] as an application factory, i.e. a () -> <ASGI app> callable."
372+
),
373+
] = False,
359374
) -> Any:
360375
"""
361376
Run a [bold]FastAPI[/bold] app in [green]production[/green] mode. 🚀
@@ -394,6 +409,7 @@ def run(
394409
command="run",
395410
proxy_headers=proxy_headers,
396411
forwarded_allow_ips=forwarded_allow_ips,
412+
is_factory=factory,
397413
)
398414

399415

src/fastapi_cli/discover.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ def get_module_data_from_path(path: Path) -> ModuleData:
6565
)
6666

6767

68-
def get_app_name(*, mod_data: ModuleData, app_name: Union[str, None] = None) -> str:
68+
def get_app_name(
69+
*, mod_data: ModuleData, app_name: Union[str, None] = None, is_factory: bool = False
70+
) -> str:
6971
try:
7072
mod = importlib.import_module(mod_data.module_import_str)
7173
except (ImportError, ValueError) as e:
@@ -86,21 +88,30 @@ def get_app_name(*, mod_data: ModuleData, app_name: Union[str, None] = None) ->
8688
f"Could not find app name {app_name} in {mod_data.module_import_str}"
8789
)
8890
app = getattr(mod, app_name)
89-
if not isinstance(app, FastAPI):
91+
if not isinstance(app, FastAPI) and not is_factory:
9092
raise FastAPICLIException(
9193
f"The app name {app_name} in {mod_data.module_import_str} doesn't seem to be a FastAPI app"
9294
)
95+
else:
96+
if not callable(app) and is_factory:
97+
raise FastAPICLIException(
98+
f"The app factory {app_name} in {mod_data.module_import_str} doesn't seem to be a function"
99+
)
93100
return app_name
94101
for preferred_name in ["app", "api"]:
95102
if preferred_name in object_names_set:
96103
obj = getattr(mod, preferred_name)
97-
if isinstance(obj, FastAPI):
104+
if isinstance(obj, FastAPI) and not is_factory:
98105
return preferred_name
99106
for name in object_names:
100107
obj = getattr(mod, name)
101-
if isinstance(obj, FastAPI):
108+
if isinstance(obj, FastAPI) and not is_factory:
109+
return name
110+
elif callable(name) and is_factory:
102111
return name
103-
raise FastAPICLIException("Could not find FastAPI app in module, try using --app")
112+
raise FastAPICLIException(
113+
"Could not find FastAPI app or app factory in module, try using --app"
114+
)
104115

105116

106117
@dataclass

0 commit comments

Comments
 (0)