@@ -260,7 +260,7 @@ async def _send_ws(ws, resp):
260260
261261def _ws_endp (recv , conn = None , disconn = None ):
262262 cls = type ('WS_Endp' , (WebSocketEndpoint ,), {"encoding" :"text" })
263-
263+
264264 async def _generic_handler (handler , ws , data = None ):
265265 wd = _wrap_ws (ws , loads (data ) if data else {}, _params (handler ))
266266 resp = await _handle (handler , wd )
@@ -299,7 +299,7 @@ def uri(_arg, **kwargs):
299299 return f"{ quote (_arg )} /{ urlencode (kwargs , doseq = True )} "
300300
301301# %% ../nbs/api/00_core.ipynb
302- def decode_uri (s ):
302+ def decode_uri (s ):
303303 arg ,_ ,kw = s .partition ('/' )
304304 return unquote (arg ), {k :v [0 ] for k ,v in parse_qs (kw ).items ()}
305305
@@ -329,7 +329,7 @@ def _url_for(req, t):
329329 if callable (t ): t = t .__routename__
330330 kw = {}
331331 if t .find ('/' )> - 1 and (t .find ('?' )< 0 or t .find ('/' )< t .find ('?' )): t ,kw = decode_uri (t )
332- t ,m ,q = t .partition ('?' )
332+ t ,m ,q = t .partition ('?' )
333333 return f"{ req .url_path_for (t , ** kw )} { m } { q } "
334334
335335def _find_targets (req , resp ):
@@ -397,28 +397,28 @@ def _xt_cts(req, resp):
397397 return _to_xml (req , resp , indent = fh_cfg .indent ), http_hdrs , ts
398398
399399# %% ../nbs/api/00_core.ipynb
400- def _xt_resp (req , resp ):
400+ def _xt_resp (req , resp , status_code ):
401401 cts ,http_hdrs ,tasks = _xt_cts (req , resp )
402- return HTMLResponse (cts , headers = http_hdrs , background = tasks )
402+ return HTMLResponse (cts , status_code = status_code , headers = http_hdrs , background = tasks )
403403
404404# %% ../nbs/api/00_core.ipynb
405405def _is_ft_resp (resp ): return isinstance (resp , _iter_typs + (HttpHeader ,FT )) or hasattr (resp , '__ft__' )
406406
407407# %% ../nbs/api/00_core.ipynb
408- def _resp (req , resp , cls = empty ):
408+ def _resp (req , resp , cls = empty , status_code = 200 ):
409409 if not resp : resp = ()
410410 if hasattr (resp , '__response__' ): resp = resp .__response__ (req )
411411 if cls in (Any ,FT ): cls = empty
412412 if isinstance (resp , FileResponse ) and not os .path .exists (resp .path ): raise HTTPException (404 , resp .path )
413- if cls is not empty : return cls (resp )
414- if isinstance (resp , Response ): return resp
415- if _is_ft_resp (resp ): return _xt_resp (req , resp )
413+ if cls is not empty : return cls (resp , status_code = status_code )
414+ if isinstance (resp , Response ): return resp # respect manually set status_code
415+ if _is_ft_resp (resp ): return _xt_resp (req , resp , status_code )
416416 if isinstance (resp , str ): cls = HTMLResponse
417417 elif isinstance (resp , Mapping ): cls = JSONResponse
418418 else :
419419 resp = str (resp )
420420 cls = HTMLResponse
421- return cls (resp )
421+ return cls (resp , status_code = status_code )
422422
423423# %% ../nbs/api/00_core.ipynb
424424class Redirect :
@@ -467,12 +467,12 @@ def get_key(key=None, fname='.sesskey'):
467467def _list (o ): return [] if not o else list (o ) if isinstance (o , (tuple ,list )) else [o ]
468468
469469# %% ../nbs/api/00_core.ipynb
470- def _wrap_ex (f , hdrs , ftrs , htmlkw , bodykw , body_wrap ):
470+ def _wrap_ex (f , status_code , hdrs , ftrs , htmlkw , bodykw , body_wrap ):
471471 async def _f (req , exc ):
472472 req .hdrs ,req .ftrs ,req .htmlkw ,req .bodykw = map (deepcopy , (hdrs , ftrs , htmlkw , bodykw ))
473473 req .body_wrap = body_wrap
474474 res = await _handle (f , (req , exc ))
475- return _resp (req , res )
475+ return _resp (req , res , status_code = status_code )
476476 return _f
477477
478478# %% ../nbs/api/00_core.ipynb
@@ -533,12 +533,12 @@ def __init__(self, debug=False, routes=None, middleware=None, title: str = "Fast
533533 https_only = sess_https_only , domain = sess_domain )
534534 middleware .append (sess )
535535 exception_handlers = ifnone (exception_handlers , {})
536- if 404 not in exception_handlers :
537- def _not_found (req , exc ): return Response ('404 Not Found' , status_code = 404 )
536+ if 404 not in exception_handlers :
537+ def _not_found (req , exc ): return Response ('404 Not Found' , status_code = 404 )
538538 exception_handlers [404 ] = _not_found
539- excs = {k :_wrap_ex (v , hdrs , ftrs , htmlkw , bodykw , body_wrap = body_wrap ) for k ,v in exception_handlers .items ()}
539+ excs = {k :_wrap_ex (v , k , hdrs , ftrs , htmlkw , bodykw , body_wrap = body_wrap ) for k ,v in exception_handlers .items ()}
540540 super ().__init__ (debug , routes , middleware = middleware , exception_handlers = excs , on_startup = on_startup , on_shutdown = on_shutdown , lifespan = lifespan )
541-
541+
542542 def add_route (self , route ):
543543 route .methods = [m .upper () for m in listify (route .methods )]
544544 self .router .routes = [r for r in self .router .routes if not
@@ -636,7 +636,7 @@ def serve(
636636 reload = True , # Default is to reload the app upon code changes
637637 reload_includes :list [str ]| str | None = None , # Additional files to watch for changes
638638 reload_excludes :list [str ]| str | None = None # Files to ignore for changes
639- ):
639+ ):
640640 "Run the app in an async server, with live reload set as the default."
641641 bk = inspect .currentframe ().f_back
642642 glb = bk .f_globals
@@ -665,7 +665,7 @@ async def _request(): return await self.cli.request(method, url, **kwargs)
665665class RouteFuncs :
666666 def __init__ (self ): super ().__setattr__ ('_funcs' , {})
667667 def __setattr__ (self , name , value ): self ._funcs [name ] = value
668- def __getattr__ (self , name ):
668+ def __getattr__ (self , name ):
669669 if name in all_meths : raise AttributeError ("Route functions with HTTP Names are not accessible here" )
670670 try : return self ._funcs [name ]
671671 except KeyError : raise AttributeError (f"No route named { name } found in route functions" )
@@ -674,7 +674,7 @@ def __dir__(self): return list(self._funcs.keys())
674674# %% ../nbs/api/00_core.ipynb
675675class APIRouter :
676676 "Add routes to an app"
677- def __init__ (self , prefix :str | None = None , body_wrap = noop_body ):
677+ def __init__ (self , prefix :str | None = None , body_wrap = noop_body ):
678678 self .routes ,self .wss = [],[]
679679 self .rt_funcs = RouteFuncs () # Store wrapped route function for discoverability
680680 self .prefix = prefix if prefix else ""
@@ -696,7 +696,7 @@ def f(func):
696696 self .routes .append ((func , p , methods , name , include_in_schema , body_wrap or self .body_wrap ))
697697 return wrapped
698698 return f (path ) if callable (path ) else f
699-
699+
700700 def __getattr__ (self , name ):
701701 try : return getattr (self .rt_funcs , name )
702702 except AttributeError : return super ().__getattr__ (self , name )
@@ -705,7 +705,7 @@ def to_app(self, app):
705705 "Add routes to `app`"
706706 for args in self .routes : app ._add_route (* args )
707707 for args in self .wss : app ._add_ws (* args )
708-
708+
709709 def ws (self , path :str , conn = None , disconn = None , name = None , middleware = None ):
710710 "Add a websocket route at `path`"
711711 def f (func = noop ): return self .wss .append ((func , f"{ self .prefix } { path } " , conn , disconn , name , middleware ))
@@ -769,7 +769,7 @@ class FtResponse:
769769 def __init__ (self , content , status_code :int = 200 , headers = None , cls = HTMLResponse , media_type :str | None = None ):
770770 self .content ,self .status_code ,self .headers = content ,status_code ,headers
771771 self .cls ,self .media_type = cls ,media_type
772-
772+
773773 def __response__ (self , req ):
774774 cts ,httphdrs ,tasks = _xt_cts (req , self .content )
775775 headers = {** (self .headers or {}), ** httphdrs }
0 commit comments