1010from contextvars import copy_context
1111import importlib .util
1212
13+
1314class FastAPIServerFactory (BaseServerFactory ):
1415 def __call__ (self , server , * args , ** kwargs ):
1516 # ASGI: (scope, receive, send)
16- if (
17- len (args ) == 3
18- and isinstance (args [0 ], dict )
19- and "type" in args [0 ]
20- ):
17+ if len (args ) == 3 and isinstance (args [0 ], dict ) and "type" in args [0 ]:
2118 return server (* args , ** kwargs )
2219 raise TypeError ("FastAPI app must be called with (scope, receive, send)" )
2320
24-
2521 def create_app (self , name = "__main__" , config = None ):
2622 app = FastAPI ()
2723 if config :
2824 for key , value in config .items ():
2925 setattr (app .state , key , value )
3026 return app
3127
32- def register_assets_blueprint (self , app , blueprint_name , assets_url_path , assets_folder ):
28+ def register_assets_blueprint (
29+ self , app , blueprint_name , assets_url_path , assets_folder
30+ ):
3331 from fastapi .staticfiles import StaticFiles
32+
3433 try :
35- app .mount (assets_url_path , StaticFiles (directory = assets_folder ), name = blueprint_name )
34+ app .mount (
35+ assets_url_path ,
36+ StaticFiles (directory = assets_folder ),
37+ name = blueprint_name ,
38+ )
3639 except RuntimeError :
3740 # directory doesnt exist
3841 pass
@@ -43,7 +46,9 @@ async def _handle_error(request: Request, exc: PreventUpdate):
4346 return Response (status_code = 204 )
4447
4548 @app .exception_handler (InvalidResourceError )
46- async def _invalid_resources_handler (request : Request , exc : InvalidResourceError ):
49+ async def _invalid_resources_handler (
50+ request : Request , exc : InvalidResourceError
51+ ):
4752 return Response (content = exc .args [0 ], status_code = 404 )
4853
4954 def _html_response_wrapper (self , view_func ):
@@ -60,6 +65,7 @@ async def index(request: Request):
6065 set_request_adapter (adapter )
6166 adapter .set_request (request )
6267 return Response (content = dash_app .render_index (), media_type = "text/html" )
68+
6369 self .add_url_rule (app , "/" , index , endpoint = "index" , methods = ["GET" ])
6470
6571 def setup_catchall (self , app , dash_app ):
@@ -73,17 +79,25 @@ async def catchall(path: str, request: Request):
7379 adapter .set_request (request )
7480 return Response (content = dash_app .render_index (), media_type = "text/html" )
7581
76- self .add_url_rule (app , "/{path:path}" , catchall , endpoint = "catchall" , methods = ["GET" ])
82+ self .add_url_rule (
83+ app , "/{path:path}" , catchall , endpoint = "catchall" , methods = ["GET" ]
84+ )
7785
78- pass # catchall needs to be last to not override other routes
86+ pass # catchall needs to be last to not override other routes
7987
8088 def add_url_rule (self , app , rule , view_func , endpoint = None , methods = None ):
8189 if rule == "" :
8290 rule = "/"
8391 if isinstance (view_func , str ):
8492 # Wrap string or sync function to async FastAPI handler
8593 view_func = self ._html_response_wrapper (view_func )
86- app .add_api_route (rule , view_func , methods = methods or ["GET" ], name = endpoint , include_in_schema = False )
94+ app .add_api_route (
95+ rule ,
96+ view_func ,
97+ methods = methods or ["GET" ],
98+ name = endpoint ,
99+ include_in_schema = False ,
100+ )
87101
88102 def before_request (self , app , func ):
89103 # FastAPI does not have before_request, but we can use middleware
@@ -102,7 +116,13 @@ def run(self, app, host, port, debug, **kwargs):
102116 # Dynamically determine the module name from the file path
103117 file_path = frame .filename
104118 module_name = importlib .util .spec_from_file_location ("app" , file_path ).name
105- uvicorn .run (f"{ module_name } :app.server" , host = host , port = port , reload = reload , ** kwargs )
119+ uvicorn .run (
120+ f"{ module_name } :app.server" ,
121+ host = host ,
122+ port = port ,
123+ reload = reload ,
124+ ** kwargs ,
125+ )
106126 else :
107127 uvicorn .run (app , host = host , port = port , reload = reload , ** kwargs )
108128
@@ -122,6 +142,7 @@ def get_request_adapter(self):
122142
123143 def _make_before_middleware (self , func ):
124144 pass
145+
125146 async def middleware (request , call_next ):
126147 if func is not None :
127148 if inspect .iscoroutinefunction (func ):
@@ -135,13 +156,17 @@ async def middleware(request, call_next):
135156
136157 def _make_after_middleware (self , func ):
137158 pass
159+
138160 async def middleware (request , call_next ):
139161 response = await call_next (request )
140162 await func ()
141163 return response
164+
142165 return middleware
143166
144- def serve_component_suites (self , dash_app , package_name , fingerprinted_path , request ):
167+ def serve_component_suites (
168+ self , dash_app , package_name , fingerprinted_path , request
169+ ):
145170 import sys
146171 import mimetypes
147172 import pkgutil
@@ -162,12 +187,14 @@ def serve_component_suites(self, dash_app, package_name, fingerprinted_path, req
162187 )
163188 data = pkgutil .get_data (package_name , path_in_pkg )
164189 from starlette .responses import Response as StarletteResponse
190+
165191 headers = {}
166192 if has_fingerprint :
167193 headers ["Cache-Control" ] = "public, max-age=31536000"
168194 return StarletteResponse (content = data , media_type = mimetype , headers = headers )
169195 else :
170196 import hashlib
197+
171198 etag = hashlib .md5 (data ).hexdigest () if data else ""
172199 headers ["ETag" ] = etag
173200 if request .headers .get ("if-none-match" ) == etag :
@@ -176,8 +203,11 @@ def serve_component_suites(self, dash_app, package_name, fingerprinted_path, req
176203
177204 def setup_component_suites (self , app , dash_app ):
178205 from fastapi import Request
206+
179207 async def serve (request : Request , package_name : str , fingerprinted_path : str ):
180- return self .serve_component_suites (dash_app , package_name , fingerprinted_path , request )
208+ return self .serve_component_suites (
209+ dash_app , package_name , fingerprinted_path , request
210+ )
181211
182212 self .add_url_rule (
183213 app ,
@@ -206,10 +236,10 @@ async def _dispatch(request: Request):
206236
207237 def _serve_default_favicon (self ):
208238 return Response (
209- content = pkgutil .get_data ("dash" , "favicon.ico" ),
210- media_type = "image/x-icon"
239+ content = pkgutil .get_data ("dash" , "favicon.ico" ), media_type = "image/x-icon"
211240 )
212241
242+
213243class FastAPIRequestAdapter :
214244 def __init__ (self ):
215245 self ._request = None
@@ -224,7 +254,9 @@ async def get_json(self):
224254 return await self ._request .json ()
225255
226256 def is_json (self ):
227- return self ._request .headers .get ("content-type" , "" ).startswith ("application/json" )
257+ return self ._request .headers .get ("content-type" , "" ).startswith (
258+ "application/json"
259+ )
228260
229261 def get_cookies (self , request = None ):
230262 return self ._request .cookies
0 commit comments