2004 lines
81 KiB
Python
2004 lines
81 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
flask.app
|
||
~~~~~~~~~
|
||
|
||
This module implements the central WSGI application object.
|
||
|
||
:copyright: (c) 2015 by Armin Ronacher.
|
||
:license: BSD, see LICENSE for more details.
|
||
"""
|
||
import os
|
||
import sys
|
||
from threading import Lock
|
||
from datetime import timedelta
|
||
from itertools import chain
|
||
from functools import update_wrapper
|
||
|
||
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, \
|
||
locked_cached_property, _endpoint_from_view_func, find_package, \
|
||
get_debug_flag
|
||
from . import json, cli
|
||
from .wrappers import Request, Response
|
||
from .config import ConfigAttribute, Config
|
||
from .ctx import RequestContext, AppContext, _AppCtxGlobals
|
||
from .globals import _request_ctx_stack, request, session, g
|
||
from .sessions import SecureCookieSessionInterface
|
||
from .templating import DispatchingJinjaLoader, Environment, \
|
||
_default_template_ctx_processor
|
||
from .signals import request_started, request_finished, got_request_exception, \
|
||
request_tearing_down, appcontext_tearing_down
|
||
from ._compat import reraise, string_types, text_type, integer_types
|
||
|
||
# a lock used for logger initialization
|
||
_logger_lock = Lock()
|
||
|
||
# a singleton sentinel value for parameter defaults
|
||
_sentinel = object()
|
||
|
||
|
||
def _make_timedelta(value):
|
||
if not isinstance(value, timedelta):
|
||
return timedelta(seconds=value)
|
||
return value
|
||
|
||
|
||
def setupmethod(f):
|
||
"""Wraps a method so that it performs a check in debug mode if the
|
||
first request was already handled.
|
||
"""
|
||
def wrapper_func(self, *args, **kwargs):
|
||
if self.debug and self._got_first_request:
|
||
raise AssertionError('A setup function was called after the '
|
||
'first request was handled. This usually indicates a bug '
|
||
'in the application where a module was not imported '
|
||
'and decorators or other functionality was called too late.\n'
|
||
'To fix this make sure to import all your view modules, '
|
||
'database models and everything related at a central place '
|
||
'before the application starts serving requests.')
|
||
return f(self, *args, **kwargs)
|
||
return update_wrapper(wrapper_func, f)
|
||
|
||
|
||
class Flask(_PackageBoundObject):
|
||
"""The flask object implements a WSGI application and acts as the central
|
||
object. It is passed the name of the module or package of the
|
||
application. Once it is created it will act as a central registry for
|
||
the view functions, the URL rules, template configuration and much more.
|
||
|
||
The name of the package is used to resolve resources from inside the
|
||
package or the folder the module is contained in depending on if the
|
||
package parameter resolves to an actual python package (a folder with
|
||
an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).
|
||
|
||
For more information about resource loading, see :func:`open_resource`.
|
||
|
||
Usually you create a :class:`Flask` instance in your main module or
|
||
in the :file:`__init__.py` file of your package like this::
|
||
|
||
from flask import Flask
|
||
app = Flask(__name__)
|
||
|
||
.. admonition:: About the First Parameter
|
||
|
||
The idea of the first parameter is to give Flask an idea of what
|
||
belongs to your application. This name is used to find resources
|
||
on the filesystem, can be used by extensions to improve debugging
|
||
information and a lot more.
|
||
|
||
So it's important what you provide there. If you are using a single
|
||
module, `__name__` is always the correct value. If you however are
|
||
using a package, it's usually recommended to hardcode the name of
|
||
your package there.
|
||
|
||
For example if your application is defined in :file:`yourapplication/app.py`
|
||
you should create it with one of the two versions below::
|
||
|
||
app = Flask('yourapplication')
|
||
app = Flask(__name__.split('.')[0])
|
||
|
||
Why is that? The application will work even with `__name__`, thanks
|
||
to how resources are looked up. However it will make debugging more
|
||
painful. Certain extensions can make assumptions based on the
|
||
import name of your application. For example the Flask-SQLAlchemy
|
||
extension will look for the code in your application that triggered
|
||
an SQL query in debug mode. If the import name is not properly set
|
||
up, that debugging information is lost. (For example it would only
|
||
pick up SQL queries in `yourapplication.app` and not
|
||
`yourapplication.views.frontend`)
|
||
|
||
.. versionadded:: 0.7
|
||
The `static_url_path`, `static_folder`, and `template_folder`
|
||
parameters were added.
|
||
|
||
.. versionadded:: 0.8
|
||
The `instance_path` and `instance_relative_config` parameters were
|
||
added.
|
||
|
||
.. versionadded:: 0.11
|
||
The `root_path` parameter was added.
|
||
|
||
:param import_name: the name of the application package
|
||
:param static_url_path: can be used to specify a different path for the
|
||
static files on the web. Defaults to the name
|
||
of the `static_folder` folder.
|
||
:param static_folder: the folder with static files that should be served
|
||
at `static_url_path`. Defaults to the ``'static'``
|
||
folder in the root path of the application.
|
||
:param template_folder: the folder that contains the templates that should
|
||
be used by the application. Defaults to
|
||
``'templates'`` folder in the root path of the
|
||
application.
|
||
:param instance_path: An alternative instance path for the application.
|
||
By default the folder ``'instance'`` next to the
|
||
package or module is assumed to be the instance
|
||
path.
|
||
:param instance_relative_config: if set to ``True`` relative filenames
|
||
for loading the config are assumed to
|
||
be relative to the instance path instead
|
||
of the application root.
|
||
:param root_path: Flask by default will automatically calculate the path
|
||
to the root of the application. In certain situations
|
||
this cannot be achieved (for instance if the package
|
||
is a Python 3 namespace package) and needs to be
|
||
manually defined.
|
||
"""
|
||
|
||
#: The class that is used for request objects. See :class:`~flask.Request`
|
||
#: for more information.
|
||
request_class = Request
|
||
|
||
#: The class that is used for response objects. See
|
||
#: :class:`~flask.Response` for more information.
|
||
response_class = Response
|
||
|
||
#: The class that is used for the Jinja environment.
|
||
#:
|
||
#: .. versionadded:: 0.11
|
||
jinja_environment = Environment
|
||
|
||
#: The class that is used for the :data:`~flask.g` instance.
|
||
#:
|
||
#: Example use cases for a custom class:
|
||
#:
|
||
#: 1. Store arbitrary attributes on flask.g.
|
||
#: 2. Add a property for lazy per-request database connectors.
|
||
#: 3. Return None instead of AttributeError on unexpected attributes.
|
||
#: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
|
||
#:
|
||
#: In Flask 0.9 this property was called `request_globals_class` but it
|
||
#: was changed in 0.10 to :attr:`app_ctx_globals_class` because the
|
||
#: flask.g object is now application context scoped.
|
||
#:
|
||
#: .. versionadded:: 0.10
|
||
app_ctx_globals_class = _AppCtxGlobals
|
||
|
||
# Backwards compatibility support
|
||
def _get_request_globals_class(self):
|
||
return self.app_ctx_globals_class
|
||
def _set_request_globals_class(self, value):
|
||
from warnings import warn
|
||
warn(DeprecationWarning('request_globals_class attribute is now '
|
||
'called app_ctx_globals_class'))
|
||
self.app_ctx_globals_class = value
|
||
request_globals_class = property(_get_request_globals_class,
|
||
_set_request_globals_class)
|
||
del _get_request_globals_class, _set_request_globals_class
|
||
|
||
#: The class that is used for the ``config`` attribute of this app.
|
||
#: Defaults to :class:`~flask.Config`.
|
||
#:
|
||
#: Example use cases for a custom class:
|
||
#:
|
||
#: 1. Default values for certain config options.
|
||
#: 2. Access to config values through attributes in addition to keys.
|
||
#:
|
||
#: .. versionadded:: 0.11
|
||
config_class = Config
|
||
|
||
#: The debug flag. Set this to ``True`` to enable debugging of the
|
||
#: application. In debug mode the debugger will kick in when an unhandled
|
||
#: exception occurs and the integrated server will automatically reload
|
||
#: the application if changes in the code are detected.
|
||
#:
|
||
#: This attribute can also be configured from the config with the ``DEBUG``
|
||
#: configuration key. Defaults to ``False``.
|
||
debug = ConfigAttribute('DEBUG')
|
||
|
||
#: The testing flag. Set this to ``True`` to enable the test mode of
|
||
#: Flask extensions (and in the future probably also Flask itself).
|
||
#: For example this might activate unittest helpers that have an
|
||
#: additional runtime cost which should not be enabled by default.
|
||
#:
|
||
#: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the
|
||
#: default it's implicitly enabled.
|
||
#:
|
||
#: This attribute can also be configured from the config with the
|
||
#: ``TESTING`` configuration key. Defaults to ``False``.
|
||
testing = ConfigAttribute('TESTING')
|
||
|
||
#: If a secret key is set, cryptographic components can use this to
|
||
#: sign cookies and other things. Set this to a complex random value
|
||
#: when you want to use the secure cookie for instance.
|
||
#:
|
||
#: This attribute can also be configured from the config with the
|
||
#: ``SECRET_KEY`` configuration key. Defaults to ``None``.
|
||
secret_key = ConfigAttribute('SECRET_KEY')
|
||
|
||
#: The secure cookie uses this for the name of the session cookie.
|
||
#:
|
||
#: This attribute can also be configured from the config with the
|
||
#: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
|
||
session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME')
|
||
|
||
#: A :class:`~datetime.timedelta` which is used to set the expiration
|
||
#: date of a permanent session. The default is 31 days which makes a
|
||
#: permanent session survive for roughly one month.
|
||
#:
|
||
#: This attribute can also be configured from the config with the
|
||
#: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to
|
||
#: ``timedelta(days=31)``
|
||
permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME',
|
||
get_converter=_make_timedelta)
|
||
|
||
#: A :class:`~datetime.timedelta` which is used as default cache_timeout
|
||
#: for the :func:`send_file` functions. The default is 12 hours.
|
||
#:
|
||
#: This attribute can also be configured from the config with the
|
||
#: ``SEND_FILE_MAX_AGE_DEFAULT`` configuration key. This configuration
|
||
#: variable can also be set with an integer value used as seconds.
|
||
#: Defaults to ``timedelta(hours=12)``
|
||
send_file_max_age_default = ConfigAttribute('SEND_FILE_MAX_AGE_DEFAULT',
|
||
get_converter=_make_timedelta)
|
||
|
||
#: Enable this if you want to use the X-Sendfile feature. Keep in
|
||
#: mind that the server has to support this. This only affects files
|
||
#: sent with the :func:`send_file` method.
|
||
#:
|
||
#: .. versionadded:: 0.2
|
||
#:
|
||
#: This attribute can also be configured from the config with the
|
||
#: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``.
|
||
use_x_sendfile = ConfigAttribute('USE_X_SENDFILE')
|
||
|
||
#: The name of the logger to use. By default the logger name is the
|
||
#: package name passed to the constructor.
|
||
#:
|
||
#: .. versionadded:: 0.4
|
||
logger_name = ConfigAttribute('LOGGER_NAME')
|
||
|
||
#: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`.
|
||
#:
|
||
#: .. versionadded:: 0.10
|
||
json_encoder = json.JSONEncoder
|
||
|
||
#: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`.
|
||
#:
|
||
#: .. versionadded:: 0.10
|
||
json_decoder = json.JSONDecoder
|
||
|
||
#: Options that are passed directly to the Jinja2 environment.
|
||
jinja_options = ImmutableDict(
|
||
extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
|
||
)
|
||
|
||
#: Default configuration parameters.
|
||
default_config = ImmutableDict({
|
||
'DEBUG': get_debug_flag(default=False),
|
||
'TESTING': False,
|
||
'PROPAGATE_EXCEPTIONS': None,
|
||
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
|
||
'SECRET_KEY': None,
|
||
'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
|
||
'USE_X_SENDFILE': False,
|
||
'LOGGER_NAME': None,
|
||
'LOGGER_HANDLER_POLICY': 'always',
|
||
'SERVER_NAME': None,
|
||
'APPLICATION_ROOT': None,
|
||
'SESSION_COOKIE_NAME': 'session',
|
||
'SESSION_COOKIE_DOMAIN': None,
|
||
'SESSION_COOKIE_PATH': None,
|
||
'SESSION_COOKIE_HTTPONLY': True,
|
||
'SESSION_COOKIE_SECURE': False,
|
||
'SESSION_REFRESH_EACH_REQUEST': True,
|
||
'MAX_CONTENT_LENGTH': None,
|
||
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
|
||
'TRAP_BAD_REQUEST_ERRORS': False,
|
||
'TRAP_HTTP_EXCEPTIONS': False,
|
||
'EXPLAIN_TEMPLATE_LOADING': False,
|
||
'PREFERRED_URL_SCHEME': 'http',
|
||
'JSON_AS_ASCII': True,
|
||
'JSON_SORT_KEYS': True,
|
||
'JSONIFY_PRETTYPRINT_REGULAR': True,
|
||
'JSONIFY_MIMETYPE': 'application/json',
|
||
'TEMPLATES_AUTO_RELOAD': None,
|
||
})
|
||
|
||
#: The rule object to use for URL rules created. This is used by
|
||
#: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`.
|
||
#:
|
||
#: .. versionadded:: 0.7
|
||
url_rule_class = Rule
|
||
|
||
#: the test client that is used with when `test_client` is used.
|
||
#:
|
||
#: .. versionadded:: 0.7
|
||
test_client_class = None
|
||
|
||
#: the session interface to use. By default an instance of
|
||
#: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.
|
||
#:
|
||
#: .. versionadded:: 0.8
|
||
session_interface = SecureCookieSessionInterface()
|
||
|
||
def __init__(self, import_name, static_path=None, static_url_path=None,
|
||
static_folder='static', template_folder='templates',
|
||
instance_path=None, instance_relative_config=False,
|
||
root_path=None):
|
||
_PackageBoundObject.__init__(self, import_name,
|
||
template_folder=template_folder,
|
||
root_path=root_path)
|
||
if static_path is not None:
|
||
from warnings import warn
|
||
warn(DeprecationWarning('static_path is now called '
|
||
'static_url_path'), stacklevel=2)
|
||
static_url_path = static_path
|
||
|
||
if static_url_path is not None:
|
||
self.static_url_path = static_url_path
|
||
if static_folder is not None:
|
||
self.static_folder = static_folder
|
||
if instance_path is None:
|
||
instance_path = self.auto_find_instance_path()
|
||
elif not os.path.isabs(instance_path):
|
||
raise ValueError('If an instance path is provided it must be '
|
||
'absolute. A relative path was given instead.')
|
||
|
||
#: Holds the path to the instance folder.
|
||
#:
|
||
#: .. versionadded:: 0.8
|
||
self.instance_path = instance_path
|
||
|
||
#: The configuration dictionary as :class:`Config`. This behaves
|
||
#: exactly like a regular dictionary but supports additional methods
|
||
#: to load a config from files.
|
||
self.config = self.make_config(instance_relative_config)
|
||
|
||
# Prepare the deferred setup of the logger.
|
||
self._logger = None
|
||
self.logger_name = self.import_name
|
||
|
||
#: A dictionary of all view functions registered. The keys will
|
||
#: be function names which are also used to generate URLs and
|
||
#: the values are the function objects themselves.
|
||
#: To register a view function, use the :meth:`route` decorator.
|
||
self.view_functions = {}
|
||
|
||
# support for the now deprecated `error_handlers` attribute. The
|
||
# :attr:`error_handler_spec` shall be used now.
|
||
self._error_handlers = {}
|
||
|
||
#: A dictionary of all registered error handlers. The key is ``None``
|
||
#: for error handlers active on the application, otherwise the key is
|
||
#: the name of the blueprint. Each key points to another dictionary
|
||
#: where the key is the status code of the http exception. The
|
||
#: special key ``None`` points to a list of tuples where the first item
|
||
#: is the class for the instance check and the second the error handler
|
||
#: function.
|
||
#:
|
||
#: To register a error handler, use the :meth:`errorhandler`
|
||
#: decorator.
|
||
self.error_handler_spec = {None: self._error_handlers}
|
||
|
||
#: A list of functions that are called when :meth:`url_for` raises a
|
||
#: :exc:`~werkzeug.routing.BuildError`. Each function registered here
|
||
#: is called with `error`, `endpoint` and `values`. If a function
|
||
#: returns ``None`` or raises a :exc:`BuildError` the next function is
|
||
#: tried.
|
||
#:
|
||
#: .. versionadded:: 0.9
|
||
self.url_build_error_handlers = []
|
||
|
||
#: A dictionary with lists of functions that should be called at the
|
||
#: beginning of the request. The key of the dictionary is the name of
|
||
#: the blueprint this function is active for, ``None`` for all requests.
|
||
#: This can for example be used to open database connections or
|
||
#: getting hold of the currently logged in user. To register a
|
||
#: function here, use the :meth:`before_request` decorator.
|
||
self.before_request_funcs = {}
|
||
|
||
#: A lists of functions that should be called at the beginning of the
|
||
#: first request to this instance. To register a function here, use
|
||
#: the :meth:`before_first_request` decorator.
|
||
#:
|
||
#: .. versionadded:: 0.8
|
||
self.before_first_request_funcs = []
|
||
|
||
#: A dictionary with lists of functions that should be called after
|
||
#: each request. The key of the dictionary is the name of the blueprint
|
||
#: this function is active for, ``None`` for all requests. This can for
|
||
#: example be used to close database connections. To register a function
|
||
#: here, use the :meth:`after_request` decorator.
|
||
self.after_request_funcs = {}
|
||
|
||
#: A dictionary with lists of functions that are called after
|
||
#: each request, even if an exception has occurred. The key of the
|
||
#: dictionary is the name of the blueprint this function is active for,
|
||
#: ``None`` for all requests. These functions are not allowed to modify
|
||
#: the request, and their return values are ignored. If an exception
|
||
#: occurred while processing the request, it gets passed to each
|
||
#: teardown_request function. To register a function here, use the
|
||
#: :meth:`teardown_request` decorator.
|
||
#:
|
||
#: .. versionadded:: 0.7
|
||
self.teardown_request_funcs = {}
|
||
|
||
#: A list of functions that are called when the application context
|
||
#: is destroyed. Since the application context is also torn down
|
||
#: if the request ends this is the place to store code that disconnects
|
||
#: from databases.
|
||
#:
|
||
#: .. versionadded:: 0.9
|
||
self.teardown_appcontext_funcs = []
|
||
|
||
#: A dictionary with lists of functions that can be used as URL
|
||
#: value processor functions. Whenever a URL is built these functions
|
||
#: are called to modify the dictionary of values in place. The key
|
||
#: ``None`` here is used for application wide
|
||
#: callbacks, otherwise the key is the name of the blueprint.
|
||
#: Each of these functions has the chance to modify the dictionary
|
||
#:
|
||
#: .. versionadded:: 0.7
|
||
self.url_value_preprocessors = {}
|
||
|
||
#: A dictionary with lists of functions that can be used as URL value
|
||
#: preprocessors. The key ``None`` here is used for application wide
|
||
#: callbacks, otherwise the key is the name of the blueprint.
|
||
#: Each of these functions has the chance to modify the dictionary
|
||
#: of URL values before they are used as the keyword arguments of the
|
||
#: view function. For each function registered this one should also
|
||
#: provide a :meth:`url_defaults` function that adds the parameters
|
||
#: automatically again that were removed that way.
|
||
#:
|
||
#: .. versionadded:: 0.7
|
||
self.url_default_functions = {}
|
||
|
||
#: A dictionary with list of functions that are called without argument
|
||
#: to populate the template context. The key of the dictionary is the
|
||
#: name of the blueprint this function is active for, ``None`` for all
|
||
#: requests. Each returns a dictionary that the template context is
|
||
#: updated with. To register a function here, use the
|
||
#: :meth:`context_processor` decorator.
|
||
self.template_context_processors = {
|
||
None: [_default_template_ctx_processor]
|
||
}
|
||
|
||
#: A list of shell context processor functions that should be run
|
||
#: when a shell context is created.
|
||
#:
|
||
#: .. versionadded:: 0.11
|
||
self.shell_context_processors = []
|
||
|
||
#: all the attached blueprints in a dictionary by name. Blueprints
|
||
#: can be attached multiple times so this dictionary does not tell
|
||
#: you how often they got attached.
|
||
#:
|
||
#: .. versionadded:: 0.7
|
||
self.blueprints = {}
|
||
self._blueprint_order = []
|
||
|
||
#: a place where extensions can store application specific state. For
|
||
#: example this is where an extension could store database engines and
|
||
#: similar things. For backwards compatibility extensions should register
|
||
#: themselves like this::
|
||
#:
|
||
#: if not hasattr(app, 'extensions'):
|
||
#: app.extensions = {}
|
||
#: app.extensions['extensionname'] = SomeObject()
|
||
#:
|
||
#: The key must match the name of the extension module. For example in
|
||
#: case of a "Flask-Foo" extension in `flask_foo`, the key would be
|
||
#: ``'foo'``.
|
||
#:
|
||
#: .. versionadded:: 0.7
|
||
self.extensions = {}
|
||
|
||
#: The :class:`~werkzeug.routing.Map` for this instance. You can use
|
||
#: this to change the routing converters after the class was created
|
||
#: but before any routes are connected. Example::
|
||
#:
|
||
#: from werkzeug.routing import BaseConverter
|
||
#:
|
||
#: class ListConverter(BaseConverter):
|
||
#: def to_python(self, value):
|
||
#: return value.split(',')
|
||
#: def to_url(self, values):
|
||
#: return ','.join(super(ListConverter, self).to_url(value)
|
||
#: for value in values)
|
||
#:
|
||
#: app = Flask(__name__)
|
||
#: app.url_map.converters['list'] = ListConverter
|
||
self.url_map = Map()
|
||
|
||
# tracks internally if the application already handled at least one
|
||
# request.
|
||
self._got_first_request = False
|
||
self._before_request_lock = Lock()
|
||
|
||
# register the static folder for the application. Do that even
|
||
# if the folder does not exist. First of all it might be created
|
||
# while the server is running (usually happens during development)
|
||
# but also because google appengine stores static files somewhere
|
||
# else when mapped with the .yml file.
|
||
if self.has_static_folder:
|
||
self.add_url_rule(self.static_url_path + '/<path:filename>',
|
||
endpoint='static',
|
||
view_func=self.send_static_file)
|
||
|
||
#: The click command line context for this application. Commands
|
||
#: registered here show up in the :command:`flask` command once the
|
||
#: application has been discovered. The default commands are
|
||
#: provided by Flask itself and can be overridden.
|
||
#:
|
||
#: This is an instance of a :class:`click.Group` object.
|
||
self.cli = cli.AppGroup(self.name)
|
||
|
||
def _get_error_handlers(self):
|
||
from warnings import warn
|
||
warn(DeprecationWarning('error_handlers is deprecated, use the '
|
||
'new error_handler_spec attribute instead.'), stacklevel=1)
|
||
return self._error_handlers
|
||
def _set_error_handlers(self, value):
|
||
self._error_handlers = value
|
||
self.error_handler_spec[None] = value
|
||
error_handlers = property(_get_error_handlers, _set_error_handlers)
|
||
del _get_error_handlers, _set_error_handlers
|
||
|
||
@locked_cached_property
|
||
def name(self):
|
||
"""The name of the application. This is usually the import name
|
||
with the difference that it's guessed from the run file if the
|
||
import name is main. This name is used as a display name when
|
||
Flask needs the name of the application. It can be set and overridden
|
||
to change the value.
|
||
|
||
.. versionadded:: 0.8
|
||
"""
|
||
if self.import_name == '__main__':
|
||
fn = getattr(sys.modules['__main__'], '__file__', None)
|
||
if fn is None:
|
||
return '__main__'
|
||
return os.path.splitext(os.path.basename(fn))[0]
|
||
return self.import_name
|
||
|
||
@property
|
||
def propagate_exceptions(self):
|
||
"""Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
|
||
value in case it's set, otherwise a sensible default is returned.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
rv = self.config['PROPAGATE_EXCEPTIONS']
|
||
if rv is not None:
|
||
return rv
|
||
return self.testing or self.debug
|
||
|
||
@property
|
||
def preserve_context_on_exception(self):
|
||
"""Returns the value of the ``PRESERVE_CONTEXT_ON_EXCEPTION``
|
||
configuration value in case it's set, otherwise a sensible default
|
||
is returned.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION']
|
||
if rv is not None:
|
||
return rv
|
||
return self.debug
|
||
|
||
@property
|
||
def logger(self):
|
||
"""A :class:`logging.Logger` object for this application. The
|
||
default configuration is to log to stderr if the application is
|
||
in debug mode. This logger can be used to (surprise) log messages.
|
||
Here some examples::
|
||
|
||
app.logger.debug('A value for debugging')
|
||
app.logger.warning('A warning occurred (%d apples)', 42)
|
||
app.logger.error('An error occurred')
|
||
|
||
.. versionadded:: 0.3
|
||
"""
|
||
if self._logger and self._logger.name == self.logger_name:
|
||
return self._logger
|
||
with _logger_lock:
|
||
if self._logger and self._logger.name == self.logger_name:
|
||
return self._logger
|
||
from flask.logging import create_logger
|
||
self._logger = rv = create_logger(self)
|
||
return rv
|
||
|
||
@locked_cached_property
|
||
def jinja_env(self):
|
||
"""The Jinja2 environment used to load templates."""
|
||
return self.create_jinja_environment()
|
||
|
||
@property
|
||
def got_first_request(self):
|
||
"""This attribute is set to ``True`` if the application started
|
||
handling the first request.
|
||
|
||
.. versionadded:: 0.8
|
||
"""
|
||
return self._got_first_request
|
||
|
||
def make_config(self, instance_relative=False):
|
||
"""Used to create the config attribute by the Flask constructor.
|
||
The `instance_relative` parameter is passed in from the constructor
|
||
of Flask (there named `instance_relative_config`) and indicates if
|
||
the config should be relative to the instance path or the root path
|
||
of the application.
|
||
|
||
.. versionadded:: 0.8
|
||
"""
|
||
root_path = self.root_path
|
||
if instance_relative:
|
||
root_path = self.instance_path
|
||
return self.config_class(root_path, self.default_config)
|
||
|
||
def auto_find_instance_path(self):
|
||
"""Tries to locate the instance path if it was not provided to the
|
||
constructor of the application class. It will basically calculate
|
||
the path to a folder named ``instance`` next to your main file or
|
||
the package.
|
||
|
||
.. versionadded:: 0.8
|
||
"""
|
||
prefix, package_path = find_package(self.import_name)
|
||
if prefix is None:
|
||
return os.path.join(package_path, 'instance')
|
||
return os.path.join(prefix, 'var', self.name + '-instance')
|
||
|
||
def open_instance_resource(self, resource, mode='rb'):
|
||
"""Opens a resource from the application's instance folder
|
||
(:attr:`instance_path`). Otherwise works like
|
||
:meth:`open_resource`. Instance resources can also be opened for
|
||
writing.
|
||
|
||
:param resource: the name of the resource. To access resources within
|
||
subfolders use forward slashes as separator.
|
||
:param mode: resource file opening mode, default is 'rb'.
|
||
"""
|
||
return open(os.path.join(self.instance_path, resource), mode)
|
||
|
||
def create_jinja_environment(self):
|
||
"""Creates the Jinja2 environment based on :attr:`jinja_options`
|
||
and :meth:`select_jinja_autoescape`. Since 0.7 this also adds
|
||
the Jinja2 globals and filters after initialization. Override
|
||
this function to customize the behavior.
|
||
|
||
.. versionadded:: 0.5
|
||
.. versionchanged:: 0.11
|
||
``Environment.auto_reload`` set in accordance with
|
||
``TEMPLATES_AUTO_RELOAD`` configuration option.
|
||
"""
|
||
options = dict(self.jinja_options)
|
||
if 'autoescape' not in options:
|
||
options['autoescape'] = self.select_jinja_autoescape
|
||
if 'auto_reload' not in options:
|
||
if self.config['TEMPLATES_AUTO_RELOAD'] is not None:
|
||
options['auto_reload'] = self.config['TEMPLATES_AUTO_RELOAD']
|
||
else:
|
||
options['auto_reload'] = self.debug
|
||
rv = self.jinja_environment(self, **options)
|
||
rv.globals.update(
|
||
url_for=url_for,
|
||
get_flashed_messages=get_flashed_messages,
|
||
config=self.config,
|
||
# request, session and g are normally added with the
|
||
# context processor for efficiency reasons but for imported
|
||
# templates we also want the proxies in there.
|
||
request=request,
|
||
session=session,
|
||
g=g
|
||
)
|
||
rv.filters['tojson'] = json.tojson_filter
|
||
return rv
|
||
|
||
def create_global_jinja_loader(self):
|
||
"""Creates the loader for the Jinja2 environment. Can be used to
|
||
override just the loader and keeping the rest unchanged. It's
|
||
discouraged to override this function. Instead one should override
|
||
the :meth:`jinja_loader` function instead.
|
||
|
||
The global loader dispatches between the loaders of the application
|
||
and the individual blueprints.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
return DispatchingJinjaLoader(self)
|
||
|
||
def init_jinja_globals(self):
|
||
"""Deprecated. Used to initialize the Jinja2 globals.
|
||
|
||
.. versionadded:: 0.5
|
||
.. versionchanged:: 0.7
|
||
This method is deprecated with 0.7. Override
|
||
:meth:`create_jinja_environment` instead.
|
||
"""
|
||
|
||
def select_jinja_autoescape(self, filename):
|
||
"""Returns ``True`` if autoescaping should be active for the given
|
||
template name. If no template name is given, returns `True`.
|
||
|
||
.. versionadded:: 0.5
|
||
"""
|
||
if filename is None:
|
||
return True
|
||
return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))
|
||
|
||
def update_template_context(self, context):
|
||
"""Update the template context with some commonly used variables.
|
||
This injects request, session, config and g into the template
|
||
context as well as everything template context processors want
|
||
to inject. Note that the as of Flask 0.6, the original values
|
||
in the context will not be overridden if a context processor
|
||
decides to return a value with the same key.
|
||
|
||
:param context: the context as a dictionary that is updated in place
|
||
to add extra variables.
|
||
"""
|
||
funcs = self.template_context_processors[None]
|
||
reqctx = _request_ctx_stack.top
|
||
if reqctx is not None:
|
||
bp = reqctx.request.blueprint
|
||
if bp is not None and bp in self.template_context_processors:
|
||
funcs = chain(funcs, self.template_context_processors[bp])
|
||
orig_ctx = context.copy()
|
||
for func in funcs:
|
||
context.update(func())
|
||
# make sure the original values win. This makes it possible to
|
||
# easier add new variables in context processors without breaking
|
||
# existing views.
|
||
context.update(orig_ctx)
|
||
|
||
def make_shell_context(self):
|
||
"""Returns the shell context for an interactive shell for this
|
||
application. This runs all the registered shell context
|
||
processors.
|
||
|
||
.. versionadded:: 0.11
|
||
"""
|
||
rv = {'app': self, 'g': g}
|
||
for processor in self.shell_context_processors:
|
||
rv.update(processor())
|
||
return rv
|
||
|
||
def run(self, host=None, port=None, debug=None, **options):
|
||
"""Runs the application on a local development server.
|
||
|
||
Do not use ``run()`` in a production setting. It is not intended to
|
||
meet security and performance requirements for a production server.
|
||
Instead, see :ref:`deployment` for WSGI server recommendations.
|
||
|
||
If the :attr:`debug` flag is set the server will automatically reload
|
||
for code changes and show a debugger in case an exception happened.
|
||
|
||
If you want to run the application in debug mode, but disable the
|
||
code execution on the interactive debugger, you can pass
|
||
``use_evalex=False`` as parameter. This will keep the debugger's
|
||
traceback screen active, but disable code execution.
|
||
|
||
It is not recommended to use this function for development with
|
||
automatic reloading as this is badly supported. Instead you should
|
||
be using the :command:`flask` command line script's ``run`` support.
|
||
|
||
.. admonition:: Keep in Mind
|
||
|
||
Flask will suppress any server error with a generic error page
|
||
unless it is in debug mode. As such to enable just the
|
||
interactive debugger without the code reloading, you have to
|
||
invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``.
|
||
Setting ``use_debugger`` to ``True`` without being in debug mode
|
||
won't catch any exceptions because there won't be any to
|
||
catch.
|
||
|
||
.. versionchanged:: 0.10
|
||
The default port is now picked from the ``SERVER_NAME`` variable.
|
||
|
||
:param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to
|
||
have the server available externally as well. Defaults to
|
||
``'127.0.0.1'``.
|
||
:param port: the port of the webserver. Defaults to ``5000`` or the
|
||
port defined in the ``SERVER_NAME`` config variable if
|
||
present.
|
||
:param debug: if given, enable or disable debug mode.
|
||
See :attr:`debug`.
|
||
:param options: the options to be forwarded to the underlying
|
||
Werkzeug server. See
|
||
:func:`werkzeug.serving.run_simple` for more
|
||
information.
|
||
"""
|
||
from werkzeug.serving import run_simple
|
||
if host is None:
|
||
host = '127.0.0.1'
|
||
if port is None:
|
||
server_name = self.config['SERVER_NAME']
|
||
if server_name and ':' in server_name:
|
||
port = int(server_name.rsplit(':', 1)[1])
|
||
else:
|
||
port = 5000
|
||
if debug is not None:
|
||
self.debug = bool(debug)
|
||
options.setdefault('use_reloader', self.debug)
|
||
options.setdefault('use_debugger', self.debug)
|
||
try:
|
||
run_simple(host, port, self, **options)
|
||
finally:
|
||
# reset the first request information if the development server
|
||
# reset normally. This makes it possible to restart the server
|
||
# without reloader and that stuff from an interactive shell.
|
||
self._got_first_request = False
|
||
|
||
def test_client(self, use_cookies=True, **kwargs):
|
||
"""Creates a test client for this application. For information
|
||
about unit testing head over to :ref:`testing`.
|
||
|
||
Note that if you are testing for assertions or exceptions in your
|
||
application code, you must set ``app.testing = True`` in order for the
|
||
exceptions to propagate to the test client. Otherwise, the exception
|
||
will be handled by the application (not visible to the test client) and
|
||
the only indication of an AssertionError or other exception will be a
|
||
500 status code response to the test client. See the :attr:`testing`
|
||
attribute. For example::
|
||
|
||
app.testing = True
|
||
client = app.test_client()
|
||
|
||
The test client can be used in a ``with`` block to defer the closing down
|
||
of the context until the end of the ``with`` block. This is useful if
|
||
you want to access the context locals for testing::
|
||
|
||
with app.test_client() as c:
|
||
rv = c.get('/?vodka=42')
|
||
assert request.args['vodka'] == '42'
|
||
|
||
Additionally, you may pass optional keyword arguments that will then
|
||
be passed to the application's :attr:`test_client_class` constructor.
|
||
For example::
|
||
|
||
from flask.testing import FlaskClient
|
||
|
||
class CustomClient(FlaskClient):
|
||
def __init__(self, *args, **kwargs):
|
||
self._authentication = kwargs.pop("authentication")
|
||
super(CustomClient,self).__init__( *args, **kwargs)
|
||
|
||
app.test_client_class = CustomClient
|
||
client = app.test_client(authentication='Basic ....')
|
||
|
||
See :class:`~flask.testing.FlaskClient` for more information.
|
||
|
||
.. versionchanged:: 0.4
|
||
added support for ``with`` block usage for the client.
|
||
|
||
.. versionadded:: 0.7
|
||
The `use_cookies` parameter was added as well as the ability
|
||
to override the client to be used by setting the
|
||
:attr:`test_client_class` attribute.
|
||
|
||
.. versionchanged:: 0.11
|
||
Added `**kwargs` to support passing additional keyword arguments to
|
||
the constructor of :attr:`test_client_class`.
|
||
"""
|
||
cls = self.test_client_class
|
||
if cls is None:
|
||
from flask.testing import FlaskClient as cls
|
||
return cls(self, self.response_class, use_cookies=use_cookies, **kwargs)
|
||
|
||
def open_session(self, request):
|
||
"""Creates or opens a new session. Default implementation stores all
|
||
session data in a signed cookie. This requires that the
|
||
:attr:`secret_key` is set. Instead of overriding this method
|
||
we recommend replacing the :class:`session_interface`.
|
||
|
||
:param request: an instance of :attr:`request_class`.
|
||
"""
|
||
return self.session_interface.open_session(self, request)
|
||
|
||
def save_session(self, session, response):
|
||
"""Saves the session if it needs updates. For the default
|
||
implementation, check :meth:`open_session`. Instead of overriding this
|
||
method we recommend replacing the :class:`session_interface`.
|
||
|
||
:param session: the session to be saved (a
|
||
:class:`~werkzeug.contrib.securecookie.SecureCookie`
|
||
object)
|
||
:param response: an instance of :attr:`response_class`
|
||
"""
|
||
return self.session_interface.save_session(self, session, response)
|
||
|
||
def make_null_session(self):
|
||
"""Creates a new instance of a missing session. Instead of overriding
|
||
this method we recommend replacing the :class:`session_interface`.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
return self.session_interface.make_null_session(self)
|
||
|
||
@setupmethod
|
||
def register_blueprint(self, blueprint, **options):
|
||
"""Registers a blueprint on the application.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
first_registration = False
|
||
if blueprint.name in self.blueprints:
|
||
assert self.blueprints[blueprint.name] is blueprint, \
|
||
'A blueprint\'s name collision occurred between %r and ' \
|
||
'%r. Both share the same name "%s". Blueprints that ' \
|
||
'are created on the fly need unique names.' % \
|
||
(blueprint, self.blueprints[blueprint.name], blueprint.name)
|
||
else:
|
||
self.blueprints[blueprint.name] = blueprint
|
||
self._blueprint_order.append(blueprint)
|
||
first_registration = True
|
||
blueprint.register(self, options, first_registration)
|
||
|
||
def iter_blueprints(self):
|
||
"""Iterates over all blueprints by the order they were registered.
|
||
|
||
.. versionadded:: 0.11
|
||
"""
|
||
return iter(self._blueprint_order)
|
||
|
||
@setupmethod
|
||
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
|
||
"""Connects a URL rule. Works exactly like the :meth:`route`
|
||
decorator. If a view_func is provided it will be registered with the
|
||
endpoint.
|
||
|
||
Basically this example::
|
||
|
||
@app.route('/')
|
||
def index():
|
||
pass
|
||
|
||
Is equivalent to the following::
|
||
|
||
def index():
|
||
pass
|
||
app.add_url_rule('/', 'index', index)
|
||
|
||
If the view_func is not provided you will need to connect the endpoint
|
||
to a view function like so::
|
||
|
||
app.view_functions['index'] = index
|
||
|
||
Internally :meth:`route` invokes :meth:`add_url_rule` so if you want
|
||
to customize the behavior via subclassing you only need to change
|
||
this method.
|
||
|
||
For more information refer to :ref:`url-route-registrations`.
|
||
|
||
.. versionchanged:: 0.2
|
||
`view_func` parameter added.
|
||
|
||
.. versionchanged:: 0.6
|
||
``OPTIONS`` is added automatically as method.
|
||
|
||
:param rule: the URL rule as string
|
||
:param endpoint: the endpoint for the registered URL rule. Flask
|
||
itself assumes the name of the view function as
|
||
endpoint
|
||
:param view_func: the function to call when serving a request to the
|
||
provided endpoint
|
||
:param options: the options to be forwarded to the underlying
|
||
:class:`~werkzeug.routing.Rule` object. A change
|
||
to Werkzeug is handling of method options. methods
|
||
is a list of methods this rule should be limited
|
||
to (``GET``, ``POST`` etc.). By default a rule
|
||
just listens for ``GET`` (and implicitly ``HEAD``).
|
||
Starting with Flask 0.6, ``OPTIONS`` is implicitly
|
||
added and handled by the standard request handling.
|
||
"""
|
||
if endpoint is None:
|
||
endpoint = _endpoint_from_view_func(view_func)
|
||
options['endpoint'] = endpoint
|
||
methods = options.pop('methods', None)
|
||
|
||
# if the methods are not given and the view_func object knows its
|
||
# methods we can use that instead. If neither exists, we go with
|
||
# a tuple of only ``GET`` as default.
|
||
if methods is None:
|
||
methods = getattr(view_func, 'methods', None) or ('GET',)
|
||
if isinstance(methods, string_types):
|
||
raise TypeError('Allowed methods have to be iterables of strings, '
|
||
'for example: @app.route(..., methods=["POST"])')
|
||
methods = set(item.upper() for item in methods)
|
||
|
||
# Methods that should always be added
|
||
required_methods = set(getattr(view_func, 'required_methods', ()))
|
||
|
||
# starting with Flask 0.8 the view_func object can disable and
|
||
# force-enable the automatic options handling.
|
||
provide_automatic_options = getattr(view_func,
|
||
'provide_automatic_options', None)
|
||
|
||
if provide_automatic_options is None:
|
||
if 'OPTIONS' not in methods:
|
||
provide_automatic_options = True
|
||
required_methods.add('OPTIONS')
|
||
else:
|
||
provide_automatic_options = False
|
||
|
||
# Add the required methods now.
|
||
methods |= required_methods
|
||
|
||
rule = self.url_rule_class(rule, methods=methods, **options)
|
||
rule.provide_automatic_options = provide_automatic_options
|
||
|
||
self.url_map.add(rule)
|
||
if view_func is not None:
|
||
old_func = self.view_functions.get(endpoint)
|
||
if old_func is not None and old_func != view_func:
|
||
raise AssertionError('View function mapping is overwriting an '
|
||
'existing endpoint function: %s' % endpoint)
|
||
self.view_functions[endpoint] = view_func
|
||
|
||
def route(self, rule, **options):
|
||
"""A decorator that is used to register a view function for a
|
||
given URL rule. This does the same thing as :meth:`add_url_rule`
|
||
but is intended for decorator usage::
|
||
|
||
@app.route('/')
|
||
def index():
|
||
return 'Hello World'
|
||
|
||
For more information refer to :ref:`url-route-registrations`.
|
||
|
||
:param rule: the URL rule as string
|
||
:param endpoint: the endpoint for the registered URL rule. Flask
|
||
itself assumes the name of the view function as
|
||
endpoint
|
||
:param options: the options to be forwarded to the underlying
|
||
:class:`~werkzeug.routing.Rule` object. A change
|
||
to Werkzeug is handling of method options. methods
|
||
is a list of methods this rule should be limited
|
||
to (``GET``, ``POST`` etc.). By default a rule
|
||
just listens for ``GET`` (and implicitly ``HEAD``).
|
||
Starting with Flask 0.6, ``OPTIONS`` is implicitly
|
||
added and handled by the standard request handling.
|
||
"""
|
||
def decorator(f):
|
||
endpoint = options.pop('endpoint', None)
|
||
self.add_url_rule(rule, endpoint, f, **options)
|
||
return f
|
||
return decorator
|
||
|
||
@setupmethod
|
||
def endpoint(self, endpoint):
|
||
"""A decorator to register a function as an endpoint.
|
||
Example::
|
||
|
||
@app.endpoint('example.endpoint')
|
||
def example():
|
||
return "example"
|
||
|
||
:param endpoint: the name of the endpoint
|
||
"""
|
||
def decorator(f):
|
||
self.view_functions[endpoint] = f
|
||
return f
|
||
return decorator
|
||
|
||
@staticmethod
|
||
def _get_exc_class_and_code(exc_class_or_code):
|
||
"""Ensure that we register only exceptions as handler keys"""
|
||
if isinstance(exc_class_or_code, integer_types):
|
||
exc_class = default_exceptions[exc_class_or_code]
|
||
else:
|
||
exc_class = exc_class_or_code
|
||
|
||
assert issubclass(exc_class, Exception)
|
||
|
||
if issubclass(exc_class, HTTPException):
|
||
return exc_class, exc_class.code
|
||
else:
|
||
return exc_class, None
|
||
|
||
@setupmethod
|
||
def errorhandler(self, code_or_exception):
|
||
"""A decorator that is used to register a function given an
|
||
error code. Example::
|
||
|
||
@app.errorhandler(404)
|
||
def page_not_found(error):
|
||
return 'This page does not exist', 404
|
||
|
||
You can also register handlers for arbitrary exceptions::
|
||
|
||
@app.errorhandler(DatabaseError)
|
||
def special_exception_handler(error):
|
||
return 'Database connection failed', 500
|
||
|
||
You can also register a function as error handler without using
|
||
the :meth:`errorhandler` decorator. The following example is
|
||
equivalent to the one above::
|
||
|
||
def page_not_found(error):
|
||
return 'This page does not exist', 404
|
||
app.error_handler_spec[None][404] = page_not_found
|
||
|
||
Setting error handlers via assignments to :attr:`error_handler_spec`
|
||
however is discouraged as it requires fiddling with nested dictionaries
|
||
and the special case for arbitrary exception types.
|
||
|
||
The first ``None`` refers to the active blueprint. If the error
|
||
handler should be application wide ``None`` shall be used.
|
||
|
||
.. versionadded:: 0.7
|
||
Use :meth:`register_error_handler` instead of modifying
|
||
:attr:`error_handler_spec` directly, for application wide error
|
||
handlers.
|
||
|
||
.. versionadded:: 0.7
|
||
One can now additionally also register custom exception types
|
||
that do not necessarily have to be a subclass of the
|
||
:class:`~werkzeug.exceptions.HTTPException` class.
|
||
|
||
:param code_or_exception: the code as integer for the handler, or
|
||
an arbitrary exception
|
||
"""
|
||
def decorator(f):
|
||
self._register_error_handler(None, code_or_exception, f)
|
||
return f
|
||
return decorator
|
||
|
||
def register_error_handler(self, code_or_exception, f):
|
||
"""Alternative error attach function to the :meth:`errorhandler`
|
||
decorator that is more straightforward to use for non decorator
|
||
usage.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
self._register_error_handler(None, code_or_exception, f)
|
||
|
||
@setupmethod
|
||
def _register_error_handler(self, key, code_or_exception, f):
|
||
"""
|
||
:type key: None|str
|
||
:type code_or_exception: int|T<=Exception
|
||
:type f: callable
|
||
"""
|
||
if isinstance(code_or_exception, HTTPException): # old broken behavior
|
||
raise ValueError(
|
||
'Tried to register a handler for an exception instance {0!r}. '
|
||
'Handlers can only be registered for exception classes or HTTP error codes.'
|
||
.format(code_or_exception))
|
||
|
||
exc_class, code = self._get_exc_class_and_code(code_or_exception)
|
||
|
||
handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {})
|
||
handlers[exc_class] = f
|
||
|
||
@setupmethod
|
||
def template_filter(self, name=None):
|
||
"""A decorator that is used to register custom template filter.
|
||
You can specify a name for the filter, otherwise the function
|
||
name will be used. Example::
|
||
|
||
@app.template_filter()
|
||
def reverse(s):
|
||
return s[::-1]
|
||
|
||
:param name: the optional name of the filter, otherwise the
|
||
function name will be used.
|
||
"""
|
||
def decorator(f):
|
||
self.add_template_filter(f, name=name)
|
||
return f
|
||
return decorator
|
||
|
||
@setupmethod
|
||
def add_template_filter(self, f, name=None):
|
||
"""Register a custom template filter. Works exactly like the
|
||
:meth:`template_filter` decorator.
|
||
|
||
:param name: the optional name of the filter, otherwise the
|
||
function name will be used.
|
||
"""
|
||
self.jinja_env.filters[name or f.__name__] = f
|
||
|
||
@setupmethod
|
||
def template_test(self, name=None):
|
||
"""A decorator that is used to register custom template test.
|
||
You can specify a name for the test, otherwise the function
|
||
name will be used. Example::
|
||
|
||
@app.template_test()
|
||
def is_prime(n):
|
||
if n == 2:
|
||
return True
|
||
for i in range(2, int(math.ceil(math.sqrt(n))) + 1):
|
||
if n % i == 0:
|
||
return False
|
||
return True
|
||
|
||
.. versionadded:: 0.10
|
||
|
||
:param name: the optional name of the test, otherwise the
|
||
function name will be used.
|
||
"""
|
||
def decorator(f):
|
||
self.add_template_test(f, name=name)
|
||
return f
|
||
return decorator
|
||
|
||
@setupmethod
|
||
def add_template_test(self, f, name=None):
|
||
"""Register a custom template test. Works exactly like the
|
||
:meth:`template_test` decorator.
|
||
|
||
.. versionadded:: 0.10
|
||
|
||
:param name: the optional name of the test, otherwise the
|
||
function name will be used.
|
||
"""
|
||
self.jinja_env.tests[name or f.__name__] = f
|
||
|
||
@setupmethod
|
||
def template_global(self, name=None):
|
||
"""A decorator that is used to register a custom template global function.
|
||
You can specify a name for the global function, otherwise the function
|
||
name will be used. Example::
|
||
|
||
@app.template_global()
|
||
def double(n):
|
||
return 2 * n
|
||
|
||
.. versionadded:: 0.10
|
||
|
||
:param name: the optional name of the global function, otherwise the
|
||
function name will be used.
|
||
"""
|
||
def decorator(f):
|
||
self.add_template_global(f, name=name)
|
||
return f
|
||
return decorator
|
||
|
||
@setupmethod
|
||
def add_template_global(self, f, name=None):
|
||
"""Register a custom template global function. Works exactly like the
|
||
:meth:`template_global` decorator.
|
||
|
||
.. versionadded:: 0.10
|
||
|
||
:param name: the optional name of the global function, otherwise the
|
||
function name will be used.
|
||
"""
|
||
self.jinja_env.globals[name or f.__name__] = f
|
||
|
||
@setupmethod
|
||
def before_request(self, f):
|
||
"""Registers a function to run before each request.
|
||
|
||
The function will be called without any arguments.
|
||
If the function returns a non-None value, it's handled as
|
||
if it was the return value from the view and further
|
||
request handling is stopped.
|
||
"""
|
||
self.before_request_funcs.setdefault(None, []).append(f)
|
||
return f
|
||
|
||
@setupmethod
|
||
def before_first_request(self, f):
|
||
"""Registers a function to be run before the first request to this
|
||
instance of the application.
|
||
|
||
The function will be called without any arguments and its return
|
||
value is ignored.
|
||
|
||
.. versionadded:: 0.8
|
||
"""
|
||
self.before_first_request_funcs.append(f)
|
||
return f
|
||
|
||
@setupmethod
|
||
def after_request(self, f):
|
||
"""Register a function to be run after each request.
|
||
|
||
Your function must take one parameter, an instance of
|
||
:attr:`response_class` and return a new response object or the
|
||
same (see :meth:`process_response`).
|
||
|
||
As of Flask 0.7 this function might not be executed at the end of the
|
||
request in case an unhandled exception occurred.
|
||
"""
|
||
self.after_request_funcs.setdefault(None, []).append(f)
|
||
return f
|
||
|
||
@setupmethod
|
||
def teardown_request(self, f):
|
||
"""Register a function to be run at the end of each request,
|
||
regardless of whether there was an exception or not. These functions
|
||
are executed when the request context is popped, even if not an
|
||
actual request was performed.
|
||
|
||
Example::
|
||
|
||
ctx = app.test_request_context()
|
||
ctx.push()
|
||
...
|
||
ctx.pop()
|
||
|
||
When ``ctx.pop()`` is executed in the above example, the teardown
|
||
functions are called just before the request context moves from the
|
||
stack of active contexts. This becomes relevant if you are using
|
||
such constructs in tests.
|
||
|
||
Generally teardown functions must take every necessary step to avoid
|
||
that they will fail. If they do execute code that might fail they
|
||
will have to surround the execution of these code by try/except
|
||
statements and log occurring errors.
|
||
|
||
When a teardown function was called because of a exception it will
|
||
be passed an error object.
|
||
|
||
The return values of teardown functions are ignored.
|
||
|
||
.. admonition:: Debug Note
|
||
|
||
In debug mode Flask will not tear down a request on an exception
|
||
immediately. Instead it will keep it alive so that the interactive
|
||
debugger can still access it. This behavior can be controlled
|
||
by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable.
|
||
"""
|
||
self.teardown_request_funcs.setdefault(None, []).append(f)
|
||
return f
|
||
|
||
@setupmethod
|
||
def teardown_appcontext(self, f):
|
||
"""Registers a function to be called when the application context
|
||
ends. These functions are typically also called when the request
|
||
context is popped.
|
||
|
||
Example::
|
||
|
||
ctx = app.app_context()
|
||
ctx.push()
|
||
...
|
||
ctx.pop()
|
||
|
||
When ``ctx.pop()`` is executed in the above example, the teardown
|
||
functions are called just before the app context moves from the
|
||
stack of active contexts. This becomes relevant if you are using
|
||
such constructs in tests.
|
||
|
||
Since a request context typically also manages an application
|
||
context it would also be called when you pop a request context.
|
||
|
||
When a teardown function was called because of an exception it will
|
||
be passed an error object.
|
||
|
||
The return values of teardown functions are ignored.
|
||
|
||
.. versionadded:: 0.9
|
||
"""
|
||
self.teardown_appcontext_funcs.append(f)
|
||
return f
|
||
|
||
@setupmethod
|
||
def context_processor(self, f):
|
||
"""Registers a template context processor function."""
|
||
self.template_context_processors[None].append(f)
|
||
return f
|
||
|
||
@setupmethod
|
||
def shell_context_processor(self, f):
|
||
"""Registers a shell context processor function.
|
||
|
||
.. versionadded:: 0.11
|
||
"""
|
||
self.shell_context_processors.append(f)
|
||
return f
|
||
|
||
@setupmethod
|
||
def url_value_preprocessor(self, f):
|
||
"""Registers a function as URL value preprocessor for all view
|
||
functions of the application. It's called before the view functions
|
||
are called and can modify the url values provided.
|
||
"""
|
||
self.url_value_preprocessors.setdefault(None, []).append(f)
|
||
return f
|
||
|
||
@setupmethod
|
||
def url_defaults(self, f):
|
||
"""Callback function for URL defaults for all view functions of the
|
||
application. It's called with the endpoint and values and should
|
||
update the values passed in place.
|
||
"""
|
||
self.url_default_functions.setdefault(None, []).append(f)
|
||
return f
|
||
|
||
def _find_error_handler(self, e):
|
||
"""Finds a registered error handler for the request’s blueprint.
|
||
Otherwise falls back to the app, returns None if not a suitable
|
||
handler is found.
|
||
"""
|
||
exc_class, code = self._get_exc_class_and_code(type(e))
|
||
|
||
def find_handler(handler_map):
|
||
if not handler_map:
|
||
return
|
||
for cls in exc_class.__mro__:
|
||
handler = handler_map.get(cls)
|
||
if handler is not None:
|
||
# cache for next time exc_class is raised
|
||
handler_map[exc_class] = handler
|
||
return handler
|
||
|
||
# try blueprint handlers
|
||
handler = find_handler(self.error_handler_spec
|
||
.get(request.blueprint, {})
|
||
.get(code))
|
||
if handler is not None:
|
||
return handler
|
||
|
||
# fall back to app handlers
|
||
return find_handler(self.error_handler_spec[None].get(code))
|
||
|
||
def handle_http_exception(self, e):
|
||
"""Handles an HTTP exception. By default this will invoke the
|
||
registered error handlers and fall back to returning the
|
||
exception as response.
|
||
|
||
.. versionadded:: 0.3
|
||
"""
|
||
# Proxy exceptions don't have error codes. We want to always return
|
||
# those unchanged as errors
|
||
if e.code is None:
|
||
return e
|
||
|
||
handler = self._find_error_handler(e)
|
||
if handler is None:
|
||
return e
|
||
return handler(e)
|
||
|
||
def trap_http_exception(self, e):
|
||
"""Checks if an HTTP exception should be trapped or not. By default
|
||
this will return ``False`` for all exceptions except for a bad request
|
||
key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It
|
||
also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``.
|
||
|
||
This is called for all HTTP exceptions raised by a view function.
|
||
If it returns ``True`` for any exception the error handler for this
|
||
exception is not called and it shows up as regular exception in the
|
||
traceback. This is helpful for debugging implicitly raised HTTP
|
||
exceptions.
|
||
|
||
.. versionadded:: 0.8
|
||
"""
|
||
if self.config['TRAP_HTTP_EXCEPTIONS']:
|
||
return True
|
||
if self.config['TRAP_BAD_REQUEST_ERRORS']:
|
||
return isinstance(e, BadRequest)
|
||
return False
|
||
|
||
def handle_user_exception(self, e):
|
||
"""This method is called whenever an exception occurs that should be
|
||
handled. A special case are
|
||
:class:`~werkzeug.exception.HTTPException`\s which are forwarded by
|
||
this function to the :meth:`handle_http_exception` method. This
|
||
function will either return a response value or reraise the
|
||
exception with the same traceback.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
exc_type, exc_value, tb = sys.exc_info()
|
||
assert exc_value is e
|
||
|
||
# ensure not to trash sys.exc_info() at that point in case someone
|
||
# wants the traceback preserved in handle_http_exception. Of course
|
||
# we cannot prevent users from trashing it themselves in a custom
|
||
# trap_http_exception method so that's their fault then.
|
||
|
||
if isinstance(e, HTTPException) and not self.trap_http_exception(e):
|
||
return self.handle_http_exception(e)
|
||
|
||
handler = self._find_error_handler(e)
|
||
|
||
if handler is None:
|
||
reraise(exc_type, exc_value, tb)
|
||
return handler(e)
|
||
|
||
def handle_exception(self, e):
|
||
"""Default exception handling that kicks in when an exception
|
||
occurs that is not caught. In debug mode the exception will
|
||
be re-raised immediately, otherwise it is logged and the handler
|
||
for a 500 internal server error is used. If no such handler
|
||
exists, a default 500 internal server error message is displayed.
|
||
|
||
.. versionadded:: 0.3
|
||
"""
|
||
exc_type, exc_value, tb = sys.exc_info()
|
||
|
||
got_request_exception.send(self, exception=e)
|
||
handler = self._find_error_handler(InternalServerError())
|
||
|
||
if self.propagate_exceptions:
|
||
# if we want to repropagate the exception, we can attempt to
|
||
# raise it with the whole traceback in case we can do that
|
||
# (the function was actually called from the except part)
|
||
# otherwise, we just raise the error again
|
||
if exc_value is e:
|
||
reraise(exc_type, exc_value, tb)
|
||
else:
|
||
raise e
|
||
|
||
self.log_exception((exc_type, exc_value, tb))
|
||
if handler is None:
|
||
return InternalServerError()
|
||
return self.finalize_request(handler(e), from_error_handler=True)
|
||
|
||
def log_exception(self, exc_info):
|
||
"""Logs an exception. This is called by :meth:`handle_exception`
|
||
if debugging is disabled and right before the handler is called.
|
||
The default implementation logs the exception as error on the
|
||
:attr:`logger`.
|
||
|
||
.. versionadded:: 0.8
|
||
"""
|
||
self.logger.error('Exception on %s [%s]' % (
|
||
request.path,
|
||
request.method
|
||
), exc_info=exc_info)
|
||
|
||
def raise_routing_exception(self, request):
|
||
"""Exceptions that are recording during routing are reraised with
|
||
this method. During debug we are not reraising redirect requests
|
||
for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising
|
||
a different error instead to help debug situations.
|
||
|
||
:internal:
|
||
"""
|
||
if not self.debug \
|
||
or not isinstance(request.routing_exception, RequestRedirect) \
|
||
or request.method in ('GET', 'HEAD', 'OPTIONS'):
|
||
raise request.routing_exception
|
||
|
||
from .debughelpers import FormDataRoutingRedirect
|
||
raise FormDataRoutingRedirect(request)
|
||
|
||
def dispatch_request(self):
|
||
"""Does the request dispatching. Matches the URL and returns the
|
||
return value of the view or error handler. This does not have to
|
||
be a response object. In order to convert the return value to a
|
||
proper response object, call :func:`make_response`.
|
||
|
||
.. versionchanged:: 0.7
|
||
This no longer does the exception handling, this code was
|
||
moved to the new :meth:`full_dispatch_request`.
|
||
"""
|
||
req = _request_ctx_stack.top.request
|
||
if req.routing_exception is not None:
|
||
self.raise_routing_exception(req)
|
||
rule = req.url_rule
|
||
# if we provide automatic options for this URL and the
|
||
# request came with the OPTIONS method, reply automatically
|
||
if getattr(rule, 'provide_automatic_options', False) \
|
||
and req.method == 'OPTIONS':
|
||
return self.make_default_options_response()
|
||
# otherwise dispatch to the handler for that endpoint
|
||
return self.view_functions[rule.endpoint](**req.view_args)
|
||
|
||
def full_dispatch_request(self):
|
||
"""Dispatches the request and on top of that performs request
|
||
pre and postprocessing as well as HTTP exception catching and
|
||
error handling.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
self.try_trigger_before_first_request_functions()
|
||
try:
|
||
request_started.send(self)
|
||
rv = self.preprocess_request()
|
||
if rv is None:
|
||
rv = self.dispatch_request()
|
||
except Exception as 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)
|
||
try:
|
||
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
|
||
|
||
def try_trigger_before_first_request_functions(self):
|
||
"""Called before each request and will ensure that it triggers
|
||
the :attr:`before_first_request_funcs` and only exactly once per
|
||
application instance (which means process usually).
|
||
|
||
:internal:
|
||
"""
|
||
if self._got_first_request:
|
||
return
|
||
with self._before_request_lock:
|
||
if self._got_first_request:
|
||
return
|
||
for func in self.before_first_request_funcs:
|
||
func()
|
||
self._got_first_request = True
|
||
|
||
def make_default_options_response(self):
|
||
"""This method is called to create the default ``OPTIONS`` response.
|
||
This can be changed through subclassing to change the default
|
||
behavior of ``OPTIONS`` responses.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
adapter = _request_ctx_stack.top.url_adapter
|
||
if hasattr(adapter, 'allowed_methods'):
|
||
methods = adapter.allowed_methods()
|
||
else:
|
||
# fallback for Werkzeug < 0.7
|
||
methods = []
|
||
try:
|
||
adapter.match(method='--')
|
||
except MethodNotAllowed as e:
|
||
methods = e.valid_methods
|
||
except HTTPException as e:
|
||
pass
|
||
rv = self.response_class()
|
||
rv.allow.update(methods)
|
||
return rv
|
||
|
||
def should_ignore_error(self, error):
|
||
"""This is called to figure out if an error should be ignored
|
||
or not as far as the teardown system is concerned. If this
|
||
function returns ``True`` then the teardown handlers will not be
|
||
passed the error.
|
||
|
||
.. versionadded:: 0.10
|
||
"""
|
||
return False
|
||
|
||
def make_response(self, rv):
|
||
"""Converts the return value from a view function to a real
|
||
response object that is an instance of :attr:`response_class`.
|
||
|
||
The following types are allowed for `rv`:
|
||
|
||
.. tabularcolumns:: |p{3.5cm}|p{9.5cm}|
|
||
|
||
======================= ===========================================
|
||
:attr:`response_class` the object is returned unchanged
|
||
:class:`str` a response object is created with the
|
||
string as body
|
||
:class:`unicode` a response object is created with the
|
||
string encoded to utf-8 as body
|
||
a WSGI function the function is called as WSGI application
|
||
and buffered as response object
|
||
:class:`tuple` A tuple in the form ``(response, status,
|
||
headers)`` or ``(response, headers)``
|
||
where `response` is any of the
|
||
types defined here, `status` is a string
|
||
or an integer and `headers` is a list or
|
||
a dictionary with header values.
|
||
======================= ===========================================
|
||
|
||
:param rv: the return value from the view function
|
||
|
||
.. versionchanged:: 0.9
|
||
Previously a tuple was interpreted as the arguments for the
|
||
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:
|
||
raise ValueError('View function did not return a response')
|
||
|
||
if isinstance(status_or_headers, (dict, list)):
|
||
headers, status_or_headers = status_or_headers, None
|
||
|
||
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)):
|
||
rv = self.response_class(rv, headers=headers,
|
||
status=status_or_headers)
|
||
headers = status_or_headers = None
|
||
else:
|
||
rv = self.response_class.force_type(rv, request.environ)
|
||
|
||
if status_or_headers is not None:
|
||
if isinstance(status_or_headers, string_types):
|
||
rv.status = status_or_headers
|
||
else:
|
||
rv.status_code = status_or_headers
|
||
if headers:
|
||
rv.headers.extend(headers)
|
||
|
||
return rv
|
||
|
||
def create_url_adapter(self, request):
|
||
"""Creates a URL adapter for the given request. The URL adapter
|
||
is created at a point where the request context is not yet set up
|
||
so the request is passed explicitly.
|
||
|
||
.. versionadded:: 0.6
|
||
|
||
.. versionchanged:: 0.9
|
||
This can now also be called without a request object when the
|
||
URL adapter is created for the application context.
|
||
"""
|
||
if request is not None:
|
||
return self.url_map.bind_to_environ(request.environ,
|
||
server_name=self.config['SERVER_NAME'])
|
||
# We need at the very least the server name to be set for this
|
||
# to work.
|
||
if self.config['SERVER_NAME'] is not None:
|
||
return self.url_map.bind(
|
||
self.config['SERVER_NAME'],
|
||
script_name=self.config['APPLICATION_ROOT'] or '/',
|
||
url_scheme=self.config['PREFERRED_URL_SCHEME'])
|
||
|
||
def inject_url_defaults(self, endpoint, values):
|
||
"""Injects the URL defaults for the given endpoint directly into
|
||
the values dictionary passed. This is used internally and
|
||
automatically called on URL building.
|
||
|
||
.. versionadded:: 0.7
|
||
"""
|
||
funcs = self.url_default_functions.get(None, ())
|
||
if '.' in endpoint:
|
||
bp = endpoint.rsplit('.', 1)[0]
|
||
funcs = chain(funcs, self.url_default_functions.get(bp, ()))
|
||
for func in funcs:
|
||
func(endpoint, values)
|
||
|
||
def handle_url_build_error(self, error, endpoint, values):
|
||
"""Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`.
|
||
"""
|
||
exc_type, exc_value, tb = sys.exc_info()
|
||
for handler in self.url_build_error_handlers:
|
||
try:
|
||
rv = handler(error, endpoint, values)
|
||
if rv is not None:
|
||
return rv
|
||
except BuildError as e:
|
||
# make error available outside except block (py3)
|
||
error = e
|
||
|
||
# At this point we want to reraise the exception. If the error is
|
||
# still the same one we can reraise it with the original traceback,
|
||
# otherwise we raise it from here.
|
||
if error is exc_value:
|
||
reraise(exc_type, exc_value, tb)
|
||
raise error
|
||
|
||
def preprocess_request(self):
|
||
"""Called before the actual request dispatching and will
|
||
call each :meth:`before_request` decorated function, passing no
|
||
arguments.
|
||
If any of these functions returns a value, it's handled as
|
||
if it was the return value from the view and further
|
||
request handling is stopped.
|
||
|
||
This also triggers the :meth:`url_value_preprocessor` functions before
|
||
the actual :meth:`before_request` functions are called.
|
||
"""
|
||
bp = _request_ctx_stack.top.request.blueprint
|
||
|
||
funcs = self.url_value_preprocessors.get(None, ())
|
||
if bp is not None and bp in self.url_value_preprocessors:
|
||
funcs = chain(funcs, self.url_value_preprocessors[bp])
|
||
for func in funcs:
|
||
func(request.endpoint, request.view_args)
|
||
|
||
funcs = self.before_request_funcs.get(None, ())
|
||
if bp is not None and bp in self.before_request_funcs:
|
||
funcs = chain(funcs, self.before_request_funcs[bp])
|
||
for func in funcs:
|
||
rv = func()
|
||
if rv is not None:
|
||
return rv
|
||
|
||
def process_response(self, response):
|
||
"""Can be overridden in order to modify the response object
|
||
before it's sent to the WSGI server. By default this will
|
||
call all the :meth:`after_request` decorated functions.
|
||
|
||
.. versionchanged:: 0.5
|
||
As of Flask 0.5 the functions registered for after request
|
||
execution are called in reverse order of registration.
|
||
|
||
:param response: a :attr:`response_class` object.
|
||
:return: a new response object or the same, has to be an
|
||
instance of :attr:`response_class`.
|
||
"""
|
||
ctx = _request_ctx_stack.top
|
||
bp = ctx.request.blueprint
|
||
funcs = ctx._after_request_functions
|
||
if bp is not None and bp in self.after_request_funcs:
|
||
funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
|
||
if None in self.after_request_funcs:
|
||
funcs = chain(funcs, reversed(self.after_request_funcs[None]))
|
||
for handler in funcs:
|
||
response = handler(response)
|
||
if not self.session_interface.is_null_session(ctx.session):
|
||
self.save_session(ctx.session, response)
|
||
return response
|
||
|
||
def do_teardown_request(self, exc=_sentinel):
|
||
"""Called after the actual request dispatching and will
|
||
call every as :meth:`teardown_request` decorated function. This is
|
||
not actually called by the :class:`Flask` object itself but is always
|
||
triggered when the request context is popped. That way we have a
|
||
tighter control over certain resources under testing environments.
|
||
|
||
.. versionchanged:: 0.9
|
||
Added the `exc` argument. Previously this was always using the
|
||
current exception information.
|
||
"""
|
||
if exc is _sentinel:
|
||
exc = sys.exc_info()[1]
|
||
funcs = reversed(self.teardown_request_funcs.get(None, ()))
|
||
bp = _request_ctx_stack.top.request.blueprint
|
||
if bp is not None and bp in self.teardown_request_funcs:
|
||
funcs = chain(funcs, reversed(self.teardown_request_funcs[bp]))
|
||
for func in funcs:
|
||
func(exc)
|
||
request_tearing_down.send(self, exc=exc)
|
||
|
||
def do_teardown_appcontext(self, exc=_sentinel):
|
||
"""Called when an application context is popped. This works pretty
|
||
much the same as :meth:`do_teardown_request` but for the application
|
||
context.
|
||
|
||
.. versionadded:: 0.9
|
||
"""
|
||
if exc is _sentinel:
|
||
exc = sys.exc_info()[1]
|
||
for func in reversed(self.teardown_appcontext_funcs):
|
||
func(exc)
|
||
appcontext_tearing_down.send(self, exc=exc)
|
||
|
||
def app_context(self):
|
||
"""Binds the application only. For as long as the application is bound
|
||
to the current context the :data:`flask.current_app` points to that
|
||
application. An application context is automatically created when a
|
||
request context is pushed if necessary.
|
||
|
||
Example usage::
|
||
|
||
with app.app_context():
|
||
...
|
||
|
||
.. versionadded:: 0.9
|
||
"""
|
||
return AppContext(self)
|
||
|
||
def request_context(self, environ):
|
||
"""Creates a :class:`~flask.ctx.RequestContext` from the given
|
||
environment and binds it to the current context. This must be used in
|
||
combination with the ``with`` statement because the request is only bound
|
||
to the current context for the duration of the ``with`` block.
|
||
|
||
Example usage::
|
||
|
||
with app.request_context(environ):
|
||
do_something_with(request)
|
||
|
||
The object returned can also be used without the ``with`` statement
|
||
which is useful for working in the shell. The example above is
|
||
doing exactly the same as this code::
|
||
|
||
ctx = app.request_context(environ)
|
||
ctx.push()
|
||
try:
|
||
do_something_with(request)
|
||
finally:
|
||
ctx.pop()
|
||
|
||
.. versionchanged:: 0.3
|
||
Added support for non-with statement usage and ``with`` statement
|
||
is now passed the ctx object.
|
||
|
||
:param environ: a WSGI environment
|
||
"""
|
||
return RequestContext(self, environ)
|
||
|
||
def test_request_context(self, *args, **kwargs):
|
||
"""Creates a WSGI environment from the given values (see
|
||
:class:`werkzeug.test.EnvironBuilder` for more information, this
|
||
function accepts the same arguments).
|
||
"""
|
||
from flask.testing import make_test_environ_builder
|
||
builder = make_test_environ_builder(self, *args, **kwargs)
|
||
try:
|
||
return self.request_context(builder.get_environ())
|
||
finally:
|
||
builder.close()
|
||
|
||
def wsgi_app(self, environ, start_response):
|
||
"""The actual WSGI application. This is not implemented in
|
||
`__call__` so that middlewares can be applied without losing a
|
||
reference to the class. So instead of doing this::
|
||
|
||
app = MyMiddleware(app)
|
||
|
||
It's a better idea to do this instead::
|
||
|
||
app.wsgi_app = MyMiddleware(app.wsgi_app)
|
||
|
||
Then you still have the original application object around and
|
||
can continue to call methods on it.
|
||
|
||
.. versionchanged:: 0.7
|
||
The behavior of the before and after request callbacks was changed
|
||
under error conditions and a new callback was added that will
|
||
always execute at the end of the request, independent on if an
|
||
error occurred or not. See :ref:`callbacks-and-errors`.
|
||
|
||
:param environ: a WSGI environment
|
||
:param start_response: a callable accepting a status code,
|
||
a list of headers and an optional
|
||
exception context to start the response
|
||
"""
|
||
ctx = self.request_context(environ)
|
||
ctx.push()
|
||
error = None
|
||
try:
|
||
try:
|
||
response = self.full_dispatch_request()
|
||
except Exception as e:
|
||
error = e
|
||
response = self.handle_exception(e)
|
||
except:
|
||
error = sys.exc_info()[1]
|
||
raise
|
||
return response(environ, start_response)
|
||
finally:
|
||
if self.should_ignore_error(error):
|
||
error = None
|
||
ctx.auto_pop(error)
|
||
|
||
def __call__(self, environ, start_response):
|
||
"""Shortcut for :attr:`wsgi_app`."""
|
||
return self.wsgi_app(environ, start_response)
|
||
|
||
def __repr__(self):
|
||
return '<%s %r>' % (
|
||
self.__class__.__name__,
|
||
self.name,
|
||
)
|