@ -10,31 +10,30 @@
"""
"""
import os
import os
import sys
import sys
from threading import Lock
from datetime import timedelta
from datetime import timedelta
from itertools import chain
from functools import update_wrapper
from functools import update_wrapper
from collections import deque
from itertools import chain
from threading import Lock
from werkzeug . datastructures import ImmutableDict
from werkzeug . routing import Map , Rule , RequestRedirect , BuildError
from werkzeug . exceptions import HTTPException , InternalServerError , \
MethodNotAllowed , BadRequest , default_exceptions
from . helpers import _PackageBoundObject , url_for , get_flashed_messages , \
from werkzeug . datastructures import ImmutableDict , Headers
locked_cached_property , _endpoint_from_view_func , find_package , \
from werkzeug . exceptions import BadRequest , HTTPException , \
get_debug_flag
InternalServerError , MethodNotAllowed , default_exceptions
from . import json , cli
from werkzeug . routing import BuildError , Map , RequestRedirect , Rule
from . wrappers import Request , Response
from . config import ConfigAttribute , Config
from . import cli , json
from . ctx import RequestContext , AppContext , _AppCtxGlobals
from . _compat import integer_types , reraise , string_types , text_type
from . globals import _request_ctx_stack , request , session , g
from . config import Config , ConfigAttribute
from . ctx import AppContext , RequestContext , _AppCtxGlobals
from . globals import _request_ctx_stack , g , request , session
from . helpers import _PackageBoundObject , \
_endpoint_from_view_func , find_package , get_debug_flag , \
get_flashed_messages , locked_cached_property , url_for
from . sessions import SecureCookieSessionInterface
from . sessions import SecureCookieSessionInterface
from . signals import appcontext_tearing_down , got_request_exception , \
request_finished , request_started , request_tearing_down
from . templating import DispatchingJinjaLoader , Environment , \
from . templating import DispatchingJinjaLoader , Environment , \
_default_template_ctx_processor
_default_template_ctx_processor
from . signals import request_started , request_finished , got_request_exception , \
from . wrappers import Request , Response
request_tearing_down , appcontext_tearing_down
from . _compat import reraise , string_types , text_type , integer_types
# a lock used for logger initialization
# a lock used for logger initialization
_logger_lock = Lock ( )
_logger_lock = Lock ( )
@ -124,6 +123,9 @@ class Flask(_PackageBoundObject):
. . versionadded : : 0.11
. . versionadded : : 0.11
The ` root_path ` parameter was added .
The ` root_path ` parameter was added .
. . versionadded : : 0.13
The ` host_matching ` and ` static_host ` parameters were added .
: param import_name : the name of the application package
: param import_name : the name of the application package
: param static_url_path : can be used to specify a different path for the
: param static_url_path : can be used to specify a different path for the
static files on the web . Defaults to the name
static files on the web . Defaults to the name
@ -131,6 +133,13 @@ class Flask(_PackageBoundObject):
: param static_folder : the folder with static files that should be served
: param static_folder : the folder with static files that should be served
at ` static_url_path ` . Defaults to the ` ` ' static ' ` `
at ` static_url_path ` . Defaults to the ` ` ' static ' ` `
folder in the root path of the application .
folder in the root path of the application .
folder in the root path of the application . Defaults
to None .
: param host_matching : sets the app ' s ``url_map.host_matching`` to the given
given value . Defaults to False .
: param static_host : the host to use when adding the static route . Defaults
to None . Required when using ` ` host_matching = True ` `
with a ` ` static_folder ` ` configured .
: param template_folder : the folder that contains the templates that should
: param template_folder : the folder that contains the templates that should
be used by the application . Defaults to
be used by the application . Defaults to
` ` ' templates ' ` ` folder in the root path of the
` ` ' templates ' ` ` folder in the root path of the
@ -315,7 +324,7 @@ class Flask(_PackageBoundObject):
' PREFERRED_URL_SCHEME ' : ' http ' ,
' PREFERRED_URL_SCHEME ' : ' http ' ,
' JSON_AS_ASCII ' : True ,
' JSON_AS_ASCII ' : True ,
' JSON_SORT_KEYS ' : True ,
' JSON_SORT_KEYS ' : True ,
' JSONIFY_PRETTYPRINT_REGULAR ' : Tru e,
' JSONIFY_PRETTYPRINT_REGULAR ' : Fals e,
' JSONIFY_MIMETYPE ' : ' application/json ' ,
' JSONIFY_MIMETYPE ' : ' application/json ' ,
' TEMPLATES_AUTO_RELOAD ' : None ,
' TEMPLATES_AUTO_RELOAD ' : None ,
} )
} )
@ -338,7 +347,8 @@ class Flask(_PackageBoundObject):
session_interface = SecureCookieSessionInterface ( )
session_interface = SecureCookieSessionInterface ( )
def __init__ ( self , import_name , static_path = None , static_url_path = None ,
def __init__ ( self , import_name , static_path = None , static_url_path = None ,
static_folder = ' static ' , template_folder = ' templates ' ,
static_folder = ' static ' , static_host = None ,
host_matching = False , template_folder = ' templates ' ,
instance_path = None , instance_relative_config = False ,
instance_path = None , instance_relative_config = False ,
root_path = None ) :
root_path = None ) :
_PackageBoundObject . __init__ ( self , import_name ,
_PackageBoundObject . __init__ ( self , import_name ,
@ -392,7 +402,7 @@ class Flask(_PackageBoundObject):
#: is the class for the instance check and the second the error handler
#: is the class for the instance check and the second the error handler
#: function.
#: function.
#:
#:
#: To register a error handler, use the :meth:`errorhandler`
#: To register an error handler, use the :meth:`errorhandler`
#: decorator.
#: decorator.
self . error_handler_spec = { None : self . _error_handlers }
self . error_handler_spec = { None : self . _error_handlers }
@ -405,17 +415,16 @@ class Flask(_PackageBoundObject):
#: .. versionadded:: 0.9
#: .. versionadded:: 0.9
self . url_build_error_handlers = [ ]
self . url_build_error_handlers = [ ]
#: A dictionary with lists of functions that should be called at the
#: A dictionary with lists of functions that will be called at the
#: beginning of the request. The key of the dictionary is the name of
#: beginning of each request. The key of the dictionary is the name of
#: the blueprint this function is active for, ``None`` for all requests.
#: the blueprint this function is active for, or ``None`` for all
#: This can for example be used to open database connections or
#: requests. To register a function, use the :meth:`before_request`
#: getting hold of the currently logged in user. To register a
#: decorator.
#: function here, use the :meth:`before_request` decorator.
self . before_request_funcs = { }
self . before_request_funcs = { }
#: A lists of functions that should be called at the beginning of the
#: A list of functions that will be called at the beginning of the
#: first request to this instance. To register a function here , use
#: first request to this instance. To register a function, use th e
#: the :meth:`before_first_request` decorator.
#: :meth:`before_first_request` decorator.
#:
#:
#: .. versionadded:: 0.8
#: .. versionadded:: 0.8
self . before_first_request_funcs = [ ]
self . before_first_request_funcs = [ ]
@ -447,12 +456,11 @@ class Flask(_PackageBoundObject):
#: .. versionadded:: 0.9
#: .. versionadded:: 0.9
self . teardown_appcontext_funcs = [ ]
self . teardown_appcontext_funcs = [ ]
#: A dictionary with lists of functions that can be used as URL
#: A dictionary with lists of functions that are called before the
#: value processor functions. Whenever a URL is built these functions
#: :attr:`before_request_funcs` functions. The key of the dictionary is
#: are called to modify the dictionary of values in place. The key
#: the name of the blueprint this function is active for, or ``None``
#: ``None`` here is used for application wide
#: for all requests. To register a function, use
#: callbacks, otherwise the key is the name of the blueprint.
#: :meth:`url_value_preprocessor`.
#: Each of these functions has the chance to modify the dictionary
#:
#:
#: .. versionadded:: 0.7
#: .. versionadded:: 0.7
self . url_value_preprocessors = { }
self . url_value_preprocessors = { }
@ -519,26 +527,29 @@ class Flask(_PackageBoundObject):
#: def to_python(self, value):
#: def to_python(self, value):
#: return value.split(',')
#: return value.split(',')
#: def to_url(self, values):
#: def to_url(self, values):
#: return ','.join(Ba seConverter.to_url(value)
#: return ','.join(sup er(List Converter, self) .to_url(value)
#: for value in values)
#: for value in values)
#:
#:
#: app = Flask(__name__)
#: app = Flask(__name__)
#: app.url_map.converters['list'] = ListConverter
#: app.url_map.converters['list'] = ListConverter
self . url_map = Map ( )
self . url_map = Map ( )
self . url_map . host_matching = host_matching
# tracks internally if the application already handled at least one
# tracks internally if the application already handled at least one
# request.
# request.
self . _got_first_request = False
self . _got_first_request = False
self . _before_request_lock = Lock ( )
self . _before_request_lock = Lock ( )
# register the static folder for the application. Do that even
# Add a static route using the provided static_url_path, static_host,
# if the folder does not exist. First of all it might be created
# and static_folder if there is a configured static_folder.
# while the server is running (usually happens during development)
# Note we do this without checking if static_folder exists.
# but also because google appengine stores static files somewhere
# For one, it might be created while the server is running (e.g. during
# else when mapped with the .yml file.
# development). Also, Google App Engine stores static files somewhere
if self . has_static_folder :
if self . has_static_folder :
assert bool ( static_host ) == host_matching , ' Invalid static_host/host_matching combination '
self . add_url_rule ( self . static_url_path + ' /<path:filename> ' ,
self . add_url_rule ( self . static_url_path + ' /<path:filename> ' ,
endpoint = ' static ' ,
endpoint = ' static ' , host = static_host ,
view_func = self . send_static_file )
view_func = self . send_static_file )
#: The click command line context for this application. Commands
#: The click command line context for this application. Commands
@ -814,7 +825,8 @@ class Flask(_PackageBoundObject):
: param host : the hostname to listen on . Set this to ` ` ' 0.0.0.0 ' ` ` to
: param host : the hostname to listen on . Set this to ` ` ' 0.0.0.0 ' ` ` to
have the server available externally as well . Defaults to
have the server available externally as well . Defaults to
` ` ' 127.0.0.1 ' ` ` .
` ` ' 127.0.0.1 ' ` ` or the host in the ` ` SERVER_NAME ` ` config
variable if present .
: param port : the port of the webserver . Defaults to ` ` 5000 ` ` or the
: param port : the port of the webserver . Defaults to ` ` 5000 ` ` or the
port defined in the ` ` SERVER_NAME ` ` config variable if
port defined in the ` ` SERVER_NAME ` ` config variable if
present .
present .
@ -825,25 +837,31 @@ class Flask(_PackageBoundObject):
: func : ` werkzeug . serving . run_simple ` for more
: func : ` werkzeug . serving . run_simple ` for more
information .
information .
"""
"""
# Change this into a no-op if the server is invoked from the
# command line. Have a look at cli.py for more information.
if os . environ . get ( ' FLASK_RUN_FROM_CLI_SERVER ' ) == ' 1 ' :
from . debughelpers import explain_ignored_app_run
explain_ignored_app_run ( )
return
from werkzeug . serving import run_simple
from werkzeug . serving import run_simple
if host is None :
_host = ' 127.0.0.1 '
host = ' 127.0.0.1 '
_port = 5000
if port is None :
server_name = self . config . get ( " SERVER_NAME " )
server_name = self . config [ ' SERVER_NAME ' ]
sn_host , sn_port = None , None
if server_name and ' : ' in server_name :
if server_name :
port = int ( server_name . rsplit ( ' : ' , 1 ) [ 1 ] )
sn_host , _ , sn_port = server_name . partition ( ' : ' )
else :
host = host or sn_host or _host
port = 5000
port = int ( port or sn_port or _port )
if debug is not None :
if debug is not None :
self . debug = bool ( debug )
self . debug = bool ( debug )
options . setdefault ( ' use_reloader ' , self . debug )
options . setdefault ( ' use_reloader ' , self . debug )
options . setdefault ( ' use_debugger ' , self . debug )
options . setdefault ( ' use_debugger ' , self . debug )
options . setdefault ( ' passthrough_errors ' , True )
try :
try :
run_simple ( host , port , self , * * options )
run_simple ( host , port , self , * * options )
finally :
finally :
# reset the first request information if the development server
# reset the first request information if the development server
# resetted normally. This makes it possible to restart the server
# reset normally. This makes it possible to restart the server
# without reloader and that stuff from an interactive shell.
# without reloader and that stuff from an interactive shell.
self . _got_first_request = False
self . _got_first_request = False
@ -877,9 +895,9 @@ class Flask(_PackageBoundObject):
from flask . testing import FlaskClient
from flask . testing import FlaskClient
class CustomClient ( FlaskClient ) :
class CustomClient ( FlaskClient ) :
def __init__ ( self , authentication = None , * args , * * kwargs ) :
def __init__ ( self , * args , * * kwargs ) :
FlaskClient . __init__ ( * args , * * kwargs )
self . _authentication = kwargs . pop ( " authentication " )
self . _authentication = authentication
super ( CustomClient , self ) . __init__ ( * args , * * kwargs )
app . test_client_class = CustomClient
app . test_client_class = CustomClient
client = app . test_client ( authentication = ' Basic .... ' )
client = app . test_client ( authentication = ' Basic .... ' )
@ -935,22 +953,7 @@ class Flask(_PackageBoundObject):
@setupmethod
@setupmethod
def register_blueprint ( self , blueprint , * * options ) :
def register_blueprint ( self , blueprint , * * options ) :
""" Register a blueprint on the application. For information about
""" Registers a blueprint on the application.
blueprints head over to : ref : ` blueprints ` .
The blueprint name is passed in as the first argument .
Options are passed as additional keyword arguments and forwarded to
` blueprints ` in an " options " dictionary .
: param subdomain : set a subdomain for the blueprint
: param url_prefix : set the prefix for all URLs defined on the blueprint .
` ` ( url_prefix = ' /<lang code> ' ) ` `
: param url_defaults : a dictionary with URL defaults that is added to
each and every URL defined with this blueprint
: param static_folder : add a static folder to urls in this blueprint
: param static_url_path : add a static url path to urls in this blueprint
: param template_folder : set an alternate template folder
: param root_path : set an alternate root path for this blueprint
. . versionadded : : 0.7
. . versionadded : : 0.7
"""
"""
@ -975,7 +978,7 @@ class Flask(_PackageBoundObject):
return iter ( self . _blueprint_order )
return iter ( self . _blueprint_order )
@setupmethod
@setupmethod
def add_url_rule ( self , rule , endpoint = None , view_func = None , * * options ) :
def add_url_rule ( self , rule , endpoint = None , view_func = None , provide_automatic_options = None , * * options ) :
""" Connects a URL rule. Works exactly like the :meth:`route`
""" Connects a URL rule. Works exactly like the :meth:`route`
decorator . If a view_func is provided it will be registered with the
decorator . If a view_func is provided it will be registered with the
endpoint .
endpoint .
@ -1015,6 +1018,10 @@ class Flask(_PackageBoundObject):
endpoint
endpoint
: param view_func : the function to call when serving a request to the
: param view_func : the function to call when serving a request to the
provided endpoint
provided endpoint
: param provide_automatic_options : controls whether the ` ` OPTIONS ` `
method should be added automatically . This can also be controlled
by setting the ` ` view_func . provide_automatic_options = False ` `
before adding the rule .
: param options : the options to be forwarded to the underlying
: param options : the options to be forwarded to the underlying
: class : ` ~ werkzeug . routing . Rule ` object . A change
: class : ` ~ werkzeug . routing . Rule ` object . A change
to Werkzeug is handling of method options . methods
to Werkzeug is handling of method options . methods
@ -1044,8 +1051,9 @@ class Flask(_PackageBoundObject):
# starting with Flask 0.8 the view_func object can disable and
# starting with Flask 0.8 the view_func object can disable and
# force-enable the automatic options handling.
# force-enable the automatic options handling.
provide_automatic_options = getattr ( view_func ,
if provide_automatic_options is None :
' provide_automatic_options ' , None )
provide_automatic_options = getattr ( view_func ,
' provide_automatic_options ' , None )
if provide_automatic_options is None :
if provide_automatic_options is None :
if ' OPTIONS ' not in methods :
if ' OPTIONS ' not in methods :
@ -1131,7 +1139,7 @@ class Flask(_PackageBoundObject):
@setupmethod
@setupmethod
def errorhandler ( self , code_or_exception ) :
def errorhandler ( self , code_or_exception ) :
""" A decorator that is used to register a function give a give n
""" A decorator that is used to register a function given an
error code . Example : :
error code . Example : :
@app . errorhandler ( 404 )
@app . errorhandler ( 404 )
@ -1169,7 +1177,8 @@ class Flask(_PackageBoundObject):
that do not necessarily have to be a subclass of the
that do not necessarily have to be a subclass of the
: class : ` ~ werkzeug . exceptions . HTTPException ` class .
: class : ` ~ werkzeug . exceptions . HTTPException ` class .
: param code : the code as integer for the handler
: param code_or_exception : the code as integer for the handler , or
an arbitrary exception
"""
"""
def decorator ( f ) :
def decorator ( f ) :
self . _register_error_handler ( None , code_or_exception , f )
self . _register_error_handler ( None , code_or_exception , f )
@ -1303,11 +1312,13 @@ class Flask(_PackageBoundObject):
@setupmethod
@setupmethod
def before_request ( self , f ) :
def before_request ( self , f ) :
""" Registers a function to run before each request.
""" Registers a function to run before each request.
For example , this can be used to open a database connection , or to load
the logged in user from the session .
The function will be called without any arguments .
The function will be called without any arguments . If it returns a
If the function returns a non - None value , it ' s handled as
non - None value , the value is handled as if it was the return value from
if it was the return value from the view and further
the view , and further request handling is stopped .
request handling is stopped .
"""
"""
self . before_request_funcs . setdefault ( None , [ ] ) . append ( f )
self . before_request_funcs . setdefault ( None , [ ] ) . append ( f )
return f
return f
@ -1363,7 +1374,7 @@ class Flask(_PackageBoundObject):
will have to surround the execution of these code by try / except
will have to surround the execution of these code by try / except
statements and log occurring errors .
statements and log occurring errors .
When a teardown function was called because of a exception it will
When a teardown function was called because of an exception it will
be passed an error object .
be passed an error object .
The return values of teardown functions are ignored .
The return values of teardown functions are ignored .
@ -1426,9 +1437,17 @@ class Flask(_PackageBoundObject):
@setupmethod
@setupmethod
def url_value_preprocessor ( self , f ) :
def url_value_preprocessor ( self , f ) :
""" Registers a function as URL value preprocessor for all view
""" Register a URL value preprocessor function for all view
functions of the application . It ' s called before the view functions
functions in the application . These functions will be called before the
are called and can modify the url values provided .
: meth : ` before_request ` functions .
The function can modify the values captured from the matched url before
they are passed to the view . For example , this can be used to pop a
common language code value and place it in ` ` g ` ` rather than pass it to
every view .
The function is passed the endpoint name and values dict . The return
value is ignored .
"""
"""
self . url_value_preprocessors . setdefault ( None , [ ] ) . append ( f )
self . url_value_preprocessors . setdefault ( None , [ ] ) . append ( f )
return f
return f
@ -1452,24 +1471,13 @@ class Flask(_PackageBoundObject):
def find_handler ( handler_map ) :
def find_handler ( handler_map ) :
if not handler_map :
if not handler_map :
return
return
queue = deque ( exc_class . __mro__ )
for cls in exc_class . __mro__ :
# Protect from geniuses who might create circular references in
# __mro__
done = set ( )
while queue :
cls = queue . popleft ( )
if cls in done :
continue
done . add ( cls )
handler = handler_map . get ( cls )
handler = handler_map . get ( cls )
if handler is not None :
if handler is not None :
# cache for next time exc_class is raised
# cache for next time exc_class is raised
handler_map [ exc_class ] = handler
handler_map [ exc_class ] = handler
return handler
return handler
queue . extend ( cls . __mro__ )
# try blueprint handlers
# try blueprint handlers
handler = find_handler ( self . error_handler_spec
handler = find_handler ( self . error_handler_spec
. get ( request . blueprint , { } )
. get ( request . blueprint , { } )
@ -1571,7 +1579,7 @@ class Flask(_PackageBoundObject):
self . log_exception ( ( exc_type , exc_value , tb ) )
self . log_exception ( ( exc_type , exc_value , tb ) )
if handler is None :
if handler is None :
return InternalServerError ( )
return InternalServerError ( )
return handler ( e )
return self . finalize_request ( handler ( e ) , from_error_handler = Tru e)
def log_exception ( self , exc_info ) :
def log_exception ( self , exc_info ) :
""" Logs an exception. This is called by :meth:`handle_exception`
""" Logs an exception. This is called by :meth:`handle_exception`
@ -1639,9 +1647,30 @@ class Flask(_PackageBoundObject):
rv = self . dispatch_request ( )
rv = self . dispatch_request ( )
except Exception as e :
except Exception as e :
rv = self . handle_user_exception ( e )
rv = self . handle_user_exception ( e )
return self . finalize_request ( rv )
def finalize_request ( self , rv , from_error_handler = False ) :
""" Given the return value from a view function this finalizes
the request by converting it into a response and invoking the
postprocessing functions . This is invoked for both normal
request dispatching as well as error handlers .
Because this means that it might be called as a result of a
failure a special safe mode is available which can be enabled
with the ` from_error_handler ` flag . If enabled , failures in
response processing will be logged and otherwise ignored .
: internal :
"""
response = self . make_response ( rv )
response = self . make_response ( rv )
response = self . process_response ( response )
try :
request_finished . send ( self , response = response )
response = self . process_response ( response )
request_finished . send ( self , response = response )
except Exception :
if not from_error_handler :
raise
self . logger . exception ( ' Request finalizing failed with an '
' error while handling an error ' )
return response
return response
def try_trigger_before_first_request_functions ( self ) :
def try_trigger_before_first_request_functions ( self ) :
@ -1694,62 +1723,106 @@ class Flask(_PackageBoundObject):
return False
return False
def make_response ( self , rv ) :
def make_response ( self , rv ) :
""" Converts the return value from a view function to a real
""" Convert the return value from a view function to an instance of
response object that is an instance of : attr : ` response_class ` .
: attr : ` response_class ` .
The following types are allowed for ` rv ` :
: param rv : the return value from the view function . The view function
must return a response . Returning ` ` None ` ` , or the view ending
. . tabularcolumns : : | p { 3.5 cm } | p { 9.5 cm } |
without returning , is not allowed . The following types are allowed
for ` ` view_rv ` ` :
== == == == == == == == == == == = == == == == == == == == == == == == == == == == == == == == == =
: attr : ` response_class ` the object is returned unchanged
` ` str ` ` ( ` ` unicode ` ` in Python 2 )
: class : ` str ` a response object is created with the
A response object is created with the string encoded to UTF - 8
string as body
as the body .
: class : ` unicode ` a response object is created with the
string encoded to utf - 8 as body
` ` bytes ` ` ( ` ` str ` ` in Python 2 )
a WSGI function the function is called as WSGI application
A response object is created with the bytes as the body .
and buffered as response object
: class : ` tuple ` A tuple in the form ` ` ( response , status ,
` ` tuple ` `
headers ) ` ` or ` ` ( response , headers ) ` `
Either ` ` ( body , status , headers ) ` ` , ` ` ( body , status ) ` ` , or
where ` response ` is any of the
` ` ( body , headers ) ` ` , where ` ` body ` ` is any of the other types
types defined here , ` status ` is a string
allowed here , ` ` status ` ` is a string or an integer , and
or an integer and ` headers ` is a list or
` ` headers ` ` is a dictionary or a list of ` ` ( key , value ) ` `
a dictionary with header values .
tuples . If ` ` body ` ` is a : attr : ` response_class ` instance ,
== == == == == == == == == == == = == == == == == == == == == == == == == == == == == == == == == =
` ` status ` ` overwrites the exiting value and ` ` headers ` ` are
extended .
: param rv : the return value from the view function
: attr : ` response_class `
The object is returned unchanged .
other : class : ` ~ werkzeug . wrappers . Response ` class
The object is coerced to : attr : ` response_class ` .
: func : ` callable `
The function is called as a WSGI application . The result is
used to create a response object .
. . versionchanged : : 0.9
. . versionchanged : : 0.9
Previously a tuple was interpreted as the arguments for the
Previously a tuple was interpreted as the arguments for the
response object .
response object .
"""
"""
status_or_headers = headers = None
if isinstance ( rv , tuple ) :
rv , status_or_headers , headers = rv + ( None , ) * ( 3 - len ( rv ) )
if rv is None :
status = headers = None
raise ValueError ( ' View function did not return a response ' )
if isinstance ( status_or_headers , ( dict , list ) ) :
# unpack tuple returns
headers , status_or_headers = status_or_headers , None
if isinstance ( rv , ( tuple , list ) ) :
len_rv = len ( rv )
# a 3-tuple is unpacked directly
if len_rv == 3 :
rv , status , headers = rv
# decide if a 2-tuple has status or headers
elif len_rv == 2 :
if isinstance ( rv [ 1 ] , ( Headers , dict , tuple , list ) ) :
rv , headers = rv
else :
rv , status = rv
# other sized tuples are not allowed
else :
raise TypeError (
' The view function did not return a valid response tuple. '
' The tuple must have the form (body, status, headers), '
' (body, status), or (body, headers). '
)
# the body must not be None
if rv is None :
raise TypeError (
' The view function did not return a valid response. The '
' function either returned None or ended without a return '
' statement. '
)
# make sure the body is an instance of the response class
if not isinstance ( rv , self . response_class ) :
if not isinstance ( rv , self . response_class ) :
# When we create a response object directly, we let the constructor
# set the headers and status. We do this because there can be
# some extra logic involved when creating these objects with
# specific values (like default content type selection).
if isinstance ( rv , ( text_type , bytes , bytearray ) ) :
if isinstance ( rv , ( text_type , bytes , bytearray ) ) :
rv = self . response_class ( rv , headers = headers ,
# let the response class set the status and headers instead of
status = status_or_headers )
# waiting to do it manually, so that the class can handle any
headers = status_or_headers = None
# special logic
rv = self . response_class ( rv , status = status , headers = headers )
status = headers = None
else :
else :
rv = self . response_class . force_type ( rv , request . environ )
# evaluate a WSGI callable, or coerce a different response
# class to the correct type
if status_or_headers is not None :
try :
if isinstance ( status_or_headers , string_types ) :
rv = self . response_class . force_type ( rv , request . environ )
rv . status = status_or_headers
except TypeError as e :
new_error = TypeError (
' {e} \n The view function did not return a valid '
' response. The return type must be a string, tuple, '
' Response instance, or WSGI callable, but it was a '
' {rv.__class__.__name__} . ' . format ( e = e , rv = rv )
)
reraise ( TypeError , new_error , sys . exc_info ( ) [ 2 ] )
# prefer the status if it was provided
if status is not None :
if isinstance ( status , ( text_type , bytes , bytearray ) ) :
rv . status = status
else :
else :
rv . status_code = status_or_headers
rv . status_code = status
# extend existing headers with provided headers
if headers :
if headers :
rv . headers . extend ( headers )
rv . headers . extend ( headers )
@ -1812,16 +1885,16 @@ class Flask(_PackageBoundObject):
raise error
raise error
def preprocess_request ( self ) :
def preprocess_request ( self ) :
""" Called before the actual request dispatching and will
""" Called before the request is dispatched. Calls
call each : meth : ` before_request ` decorated function , passing no
: attr : ` url_value_preprocessors ` registered with the app and the
arguments .
current blueprint ( if any ) . Then calls : attr : ` before_request_funcs `
If any of these functions returns a value , it ' s handled as
registered with the app and the blueprint .
if it was the return value from the view and further
request handling is stopped .
If any : meth : ` before_request ` handler returns a non - None value , the
value is handled as if it was the return value from the view , and
This also triggers the : meth : ` url_value_processor ` functions before
further request handling is stopped .
the actual : meth : ` before_request ` functions are called .
"""
"""
bp = _request_ctx_stack . top . request . blueprint
bp = _request_ctx_stack . top . request . blueprint
funcs = self . url_value_preprocessors . get ( None , ( ) )
funcs = self . url_value_preprocessors . get ( None , ( ) )
@ -1981,14 +2054,17 @@ class Flask(_PackageBoundObject):
exception context to start the response
exception context to start the response
"""
"""
ctx = self . request_context ( environ )
ctx = self . request_context ( environ )
ctx . push ( )
error = None
error = None
try :
try :
try :
try :
ctx . push ( )
response = self . full_dispatch_request ( )
response = self . full_dispatch_request ( )
except Exception as e :
except Exception as e :
error = e
error = e
response = self . make_response ( self . handle_exception ( e ) )
response = self . handle_exception ( e )
except :
error = sys . exc_info ( ) [ 1 ]
raise
return response ( environ , start_response )
return response ( environ , start_response )
finally :
finally :
if self . should_ignore_error ( error ) :
if self . should_ignore_error ( error ) :