33from dataclasses import dataclass
44from logging import getLogger
55from pathlib import Path
6- from typing import Union
6+ from typing import Any , Callable , Union , get_type_hints
77
88from rich import print
99from rich .padding import Padding
@@ -98,7 +98,9 @@ def get_module_data_from_path(path: Path) -> ModuleData:
9898 )
9999
100100
101- def get_app_name (* , mod_data : ModuleData , app_name : Union [str , None ] = None ) -> str :
101+ def get_app_name (
102+ * , mod_data : ModuleData , app_name : Union [str , None ] = None
103+ ) -> tuple [str , bool ]:
102104 try :
103105 mod = importlib .import_module (mod_data .module_import_str )
104106 except (ImportError , ValueError ) as e :
@@ -119,26 +121,40 @@ def get_app_name(*, mod_data: ModuleData, app_name: Union[str, None] = None) ->
119121 f"Could not find app name { app_name } in { mod_data .module_import_str } "
120122 )
121123 app = getattr (mod , app_name )
124+ is_factory = False
122125 if not isinstance (app , FastAPI ):
123- raise FastAPICLIException (
124- f"The app name { app_name } in { mod_data .module_import_str } doesn't seem to be a FastAPI app"
125- )
126- return app_name
127- for preferred_name in ["app" , "api" ]:
126+ is_factory = check_factory (app )
127+ if not is_factory :
128+ raise FastAPICLIException (
129+ f"The app name { app_name } in { mod_data .module_import_str } doesn't seem to be a FastAPI app"
130+ )
131+ return app_name , is_factory
132+ for preferred_name in ["app" , "api" , "create_app" , "create_api" ]:
128133 if preferred_name in object_names_set :
129134 obj = getattr (mod , preferred_name )
130135 if isinstance (obj , FastAPI ):
131- return preferred_name
136+ return preferred_name , False
137+ if check_factory (obj ):
138+ return preferred_name , True
132139 for name in object_names :
133140 obj = getattr (mod , name )
134141 if isinstance (obj , FastAPI ):
135- return name
142+ return name , False
136143 raise FastAPICLIException ("Could not find FastAPI app in module, try using --app" )
137144
138145
146+ def check_factory (fn : Callable [[], Any ]) -> bool :
147+ """Checks whether the return-type of a factory function is FastAPI"""
148+ # if not callable(fn):
149+ # return False
150+ type_hints = get_type_hints (fn )
151+ return_type = type_hints .get ("return" )
152+ return return_type is not None and issubclass (return_type , FastAPI )
153+
154+
139155def get_import_string (
140156 * , path : Union [Path , None ] = None , app_name : Union [str , None ] = None
141- ) -> str :
157+ ) -> tuple [ str , bool ] :
142158 if not path :
143159 path = get_default_path ()
144160 logger .info (f"Using path [blue]{ path } [/blue]" )
@@ -147,7 +163,7 @@ def get_import_string(
147163 raise FastAPICLIException (f"Path does not exist { path } " )
148164 mod_data = get_module_data_from_path (path )
149165 sys .path .insert (0 , str (mod_data .extra_sys_path ))
150- use_app_name = get_app_name (mod_data = mod_data , app_name = app_name )
166+ use_app_name , is_factory = get_app_name (mod_data = mod_data , app_name = app_name )
151167 import_example = Syntax (
152168 f"from { mod_data .module_import_str } import { use_app_name } " , "python"
153169 )
@@ -164,4 +180,4 @@ def get_import_string(
164180 print (import_panel )
165181 import_string = f"{ mod_data .module_import_str } :{ use_app_name } "
166182 logger .info (f"Using import string [b green]{ import_string } [/b green]" )
167- return import_string
183+ return import_string , is_factory
0 commit comments