@@ -692,12 +692,17 @@ def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner:
692
692
return cls (self , ** kwargs ) # type: ignore
693
693
694
694
def handle_http_exception (
695
- self , e : HTTPException
695
+ self ,
696
+ e : HTTPException ,
697
+ ctx : RequestContext ,
696
698
) -> HTTPException | ft .ResponseReturnValue :
697
699
"""Handles an HTTP exception. By default this will invoke the
698
700
registered error handlers and fall back to returning the
699
701
exception as response.
700
702
703
+ .. versionchanged:: 3.0
704
+ The request context, ctx, is now a required argument.
705
+
701
706
.. versionchanged:: 1.0.3
702
707
``RoutingException``, used internally for actions such as
703
708
slash redirects during routing, is not passed to error
@@ -721,13 +726,15 @@ def handle_http_exception(
721
726
if isinstance (e , RoutingException ):
722
727
return e
723
728
724
- handler = self ._find_error_handler (e , request .blueprints )
729
+ handler = self ._find_error_handler (e , ctx . request .blueprints )
725
730
if handler is None :
726
731
return e
727
732
return self .ensure_sync (handler )(e )
728
733
729
734
def handle_user_exception (
730
- self , e : Exception
735
+ self ,
736
+ e : Exception ,
737
+ ctx : RequestContext ,
731
738
) -> HTTPException | ft .ResponseReturnValue :
732
739
"""This method is called whenever an exception occurs that
733
740
should be handled. A special case is :class:`~werkzeug
@@ -736,6 +743,9 @@ def handle_user_exception(
736
743
return a response value or reraise the exception with the same
737
744
traceback.
738
745
746
+ .. versionchanged:: 3.0
747
+ The request context, ctx, is now a required argument.
748
+
739
749
.. versionchanged:: 1.0
740
750
Key errors raised from request data like ``form`` show the
741
751
bad key in debug mode rather than a generic bad request
@@ -749,16 +759,16 @@ def handle_user_exception(
749
759
e .show_exception = True
750
760
751
761
if isinstance (e , HTTPException ) and not self .trap_http_exception (e ):
752
- return self .handle_http_exception (e )
762
+ return self .handle_http_exception (e , ctx )
753
763
754
- handler = self ._find_error_handler (e , request .blueprints )
764
+ handler = self ._find_error_handler (e , ctx . request .blueprints )
755
765
756
766
if handler is None :
757
767
raise
758
768
759
769
return self .ensure_sync (handler )(e )
760
770
761
- def handle_exception (self , e : Exception ) -> Response :
771
+ def handle_exception (self , e : Exception , ctx : RequestContext ) -> Response :
762
772
"""Handle an exception that did not have an error handler
763
773
associated with it, or that was raised from an error handler.
764
774
This always causes a 500 ``InternalServerError``.
@@ -775,6 +785,9 @@ def handle_exception(self, e: Exception) -> Response:
775
785
always receive the ``InternalServerError``. The original
776
786
unhandled exception is available as ``e.original_exception``.
777
787
788
+ .. versionchanged:: 3.0
789
+ The request context, ctx, is now a required argument.
790
+
778
791
.. versionchanged:: 1.1.0
779
792
Always passes the ``InternalServerError`` instance to the
780
793
handler, setting ``original_exception`` to the unhandled
@@ -801,77 +814,87 @@ def handle_exception(self, e: Exception) -> Response:
801
814
802
815
raise e
803
816
804
- self .log_exception (exc_info )
817
+ self .log_exception (exc_info , ctx )
805
818
server_error : InternalServerError | ft .ResponseReturnValue
806
819
server_error = InternalServerError (original_exception = e )
807
- handler = self ._find_error_handler (server_error , request .blueprints )
820
+ handler = self ._find_error_handler (server_error , ctx . request .blueprints )
808
821
809
822
if handler is not None :
810
823
server_error = self .ensure_sync (handler )(server_error )
811
824
812
- return self .finalize_request (server_error , from_error_handler = True )
825
+ return self .finalize_request (server_error , ctx , from_error_handler = True )
813
826
814
827
def log_exception (
815
828
self ,
816
829
exc_info : (tuple [type , BaseException , TracebackType ] | tuple [None , None , None ]),
830
+ ctx : RequestContext ,
817
831
) -> None :
818
832
"""Logs an exception. This is called by :meth:`handle_exception`
819
833
if debugging is disabled and right before the handler is called.
820
834
The default implementation logs the exception as error on the
821
835
:attr:`logger`.
822
836
837
+ .. versionchanged:: 3.0
838
+ The request context, ctx, is now a required argument.
839
+
823
840
.. versionadded:: 0.8
824
841
"""
825
842
self .logger .error (
826
- f"Exception on { request .path } [{ request .method } ]" , exc_info = exc_info
843
+ f"Exception on { ctx . request .path } [{ ctx . request .method } ]" , exc_info = exc_info
827
844
)
828
845
829
- def dispatch_request (self ) -> ft .ResponseReturnValue :
846
+ def dispatch_request (self , ctx : RequestContext ) -> ft .ResponseReturnValue :
830
847
"""Does the request dispatching. Matches the URL and returns the
831
848
return value of the view or error handler. This does not have to
832
849
be a response object. In order to convert the return value to a
833
850
proper response object, call :func:`make_response`.
834
851
852
+ .. versionchanged:: 3.0
853
+ The request context, ctx, is now a required argument.
854
+
835
855
.. versionchanged:: 0.7
836
856
This no longer does the exception handling, this code was
837
857
moved to the new :meth:`full_dispatch_request`.
838
858
"""
839
- req = request_ctx .request
840
- if req .routing_exception is not None :
841
- self .raise_routing_exception (req )
842
- rule : Rule = req .url_rule # type: ignore[assignment]
859
+ if ctx .request .routing_exception is not None :
860
+ self .raise_routing_exception (ctx .request )
861
+ rule : Rule = ctx .request .url_rule # type: ignore[assignment]
843
862
# if we provide automatic options for this URL and the
844
863
# request came with the OPTIONS method, reply automatically
845
864
if (
846
865
getattr (rule , "provide_automatic_options" , False )
847
- and req .method == "OPTIONS"
866
+ and ctx . request .method == "OPTIONS"
848
867
):
849
868
return self .make_default_options_response ()
850
869
# otherwise dispatch to the handler for that endpoint
851
- view_args : dict [str , t .Any ] = req .view_args # type: ignore[assignment]
870
+ view_args : dict [str , t .Any ] = ctx . request .view_args # type: ignore[assignment]
852
871
return self .ensure_sync (self .view_functions [rule .endpoint ])(** view_args )
853
872
854
- def full_dispatch_request (self ) -> Response :
873
+ def full_dispatch_request (self , ctx : RequestContext ) -> Response :
855
874
"""Dispatches the request and on top of that performs request
856
875
pre and postprocessing as well as HTTP exception catching and
857
876
error handling.
858
877
878
+ .. versionchanged:: 3.0
879
+ The request context, ctx, is now a required argument.
880
+
859
881
.. versionadded:: 0.7
860
882
"""
861
883
self ._got_first_request = True
862
884
863
885
try :
864
886
request_started .send (self , _async_wrapper = self .ensure_sync )
865
- rv = self .preprocess_request ()
887
+ rv = self .preprocess_request (ctx )
866
888
if rv is None :
867
- rv = self .dispatch_request ()
889
+ rv = self .dispatch_request (ctx )
868
890
except Exception as e :
869
- rv = self .handle_user_exception (e )
870
- return self .finalize_request (rv )
891
+ rv = self .handle_user_exception (e , ctx )
892
+ return self .finalize_request (rv , ctx )
871
893
872
894
def finalize_request (
873
895
self ,
874
896
rv : ft .ResponseReturnValue | HTTPException ,
897
+ ctx : RequestContext ,
875
898
from_error_handler : bool = False ,
876
899
) -> Response :
877
900
"""Given the return value from a view function this finalizes
@@ -884,11 +907,14 @@ def finalize_request(
884
907
with the `from_error_handler` flag. If enabled, failures in
885
908
response processing will be logged and otherwise ignored.
886
909
910
+ .. versionchanged:: 3.0
911
+ The request context, ctx, is now a required argument.
912
+
887
913
:internal:
888
914
"""
889
915
response = self .make_response (rv )
890
916
try :
891
- response = self .process_response (response )
917
+ response = self .process_response (response , ctx )
892
918
request_finished .send (
893
919
self , _async_wrapper = self .ensure_sync , response = response
894
920
)
@@ -1215,7 +1241,7 @@ def make_response(self, rv: ft.ResponseReturnValue) -> Response:
1215
1241
1216
1242
return rv
1217
1243
1218
- def preprocess_request (self ) -> ft .ResponseReturnValue | None :
1244
+ def preprocess_request (self , ctx : RequestContext ) -> ft .ResponseReturnValue | None :
1219
1245
"""Called before the request is dispatched. Calls
1220
1246
:attr:`url_value_preprocessors` registered with the app and the
1221
1247
current blueprint (if any). Then calls :attr:`before_request_funcs`
@@ -1224,13 +1250,16 @@ def preprocess_request(self) -> ft.ResponseReturnValue | None:
1224
1250
If any :meth:`before_request` handler returns a non-None value, the
1225
1251
value is handled as if it was the return value from the view, and
1226
1252
further request handling is stopped.
1253
+
1254
+ .. versionchanged:: 3.0
1255
+ The request context, ctx, is now a required argument.
1227
1256
"""
1228
- names = (None , * reversed (request .blueprints ))
1257
+ names = (None , * reversed (ctx . request .blueprints ))
1229
1258
1230
1259
for name in names :
1231
1260
if name in self .url_value_preprocessors :
1232
1261
for url_func in self .url_value_preprocessors [name ]:
1233
- url_func (request .endpoint , request .view_args )
1262
+ url_func (ctx . request .endpoint , ctx . request .view_args )
1234
1263
1235
1264
for name in names :
1236
1265
if name in self .before_request_funcs :
@@ -1242,11 +1271,14 @@ def preprocess_request(self) -> ft.ResponseReturnValue | None:
1242
1271
1243
1272
return None
1244
1273
1245
- def process_response (self , response : Response ) -> Response :
1274
+ def process_response (self , response : Response , ctx : RequestContext ) -> Response :
1246
1275
"""Can be overridden in order to modify the response object
1247
1276
before it's sent to the WSGI server. By default this will
1248
1277
call all the :meth:`after_request` decorated functions.
1249
1278
1279
+ .. versionchanged:: 3.0
1280
+ The request context, ctx, is now a required argument.
1281
+
1250
1282
.. versionchanged:: 0.5
1251
1283
As of Flask 0.5 the functions registered for after request
1252
1284
execution are called in reverse order of registration.
@@ -1255,23 +1287,25 @@ def process_response(self, response: Response) -> Response:
1255
1287
:return: a new response object or the same, has to be an
1256
1288
instance of :attr:`response_class`.
1257
1289
"""
1258
- ctx = request_ctx ._get_current_object () # type: ignore[attr-defined]
1259
-
1260
1290
for func in ctx ._after_request_functions :
1261
1291
response = self .ensure_sync (func )(response )
1262
1292
1263
- for name in chain (request .blueprints , (None ,)):
1293
+ for name in chain (ctx . request .blueprints , (None ,)):
1264
1294
if name in self .after_request_funcs :
1265
1295
for func in reversed (self .after_request_funcs [name ]):
1266
1296
response = self .ensure_sync (func )(response )
1267
1297
1268
1298
if not self .session_interface .is_null_session (ctx .session ):
1269
- self .session_interface .save_session (self , ctx .session , response )
1299
+ self .session_interface .save_session (
1300
+ self , ctx .session , response # type: ignore[arg-type]
1301
+ )
1270
1302
1271
1303
return response
1272
1304
1273
1305
def do_teardown_request (
1274
- self , exc : BaseException | None = _sentinel # type: ignore
1306
+ self ,
1307
+ ctx : RequestContext ,
1308
+ exc : BaseException | None = _sentinel , # type: ignore
1275
1309
) -> None :
1276
1310
"""Called after the request is dispatched and the response is
1277
1311
returned, right before the request context is popped.
@@ -1290,13 +1324,16 @@ def do_teardown_request(
1290
1324
request. Detected from the current exception information if
1291
1325
not passed. Passed to each teardown function.
1292
1326
1327
+ .. versionchanged:: 3.0
1328
+ The request context, ctx, is now a required argument.
1329
+
1293
1330
.. versionchanged:: 0.9
1294
1331
Added the ``exc`` argument.
1295
1332
"""
1296
1333
if exc is _sentinel :
1297
1334
exc = sys .exc_info ()[1 ]
1298
1335
1299
- for name in chain (request .blueprints , (None ,)):
1336
+ for name in chain (ctx . request .blueprints , (None ,)):
1300
1337
if name in self .teardown_request_funcs :
1301
1338
for func in reversed (self .teardown_request_funcs [name ]):
1302
1339
self .ensure_sync (func )(exc )
@@ -1451,10 +1488,10 @@ def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
1451
1488
try :
1452
1489
try :
1453
1490
ctx .push ()
1454
- response = self .full_dispatch_request ()
1491
+ response = self .full_dispatch_request (ctx )
1455
1492
except Exception as e :
1456
1493
error = e
1457
- response = self .handle_exception (e )
1494
+ response = self .handle_exception (e , ctx )
1458
1495
except : # noqa: B001
1459
1496
error = sys .exc_info ()[1 ]
1460
1497
raise
0 commit comments