# -*- coding: utf-8 -*- """ flask ~~~~~ A microframework based on Werkzeug. It's extensively documented and follows best practice patterns. :copyright: (c) 2010 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ from __future__ import with_statement import os import sys import mimetypes from datetime import datetime, timedelta from itertools import chain from jinja2 import Environment, PackageLoader, FileSystemLoader from werkzeug import Request as RequestBase, Response as ResponseBase, \ LocalStack, LocalProxy, create_environ, SharedDataMiddleware, \ ImmutableDict, cached_property, wrap_file, Headers from werkzeug.routing import Map, Rule from werkzeug.exceptions import HTTPException from werkzeug.contrib.securecookie import SecureCookie # try to load the best simplejson implementation available. If JSON # is not installed, we add a failing class. json_available = True try: import simplejson as json except ImportError: try: import json except ImportError: json_available = False # utilities we import from Werkzeug and Jinja2 that are unused # in the module but are exported as public interface. from werkzeug import abort, redirect from jinja2 import Markup, escape # use pkg_resource if that works, otherwise fall back to cwd. The # current working directory is generally not reliable with the notable # exception of google appengine. try: import pkg_resources pkg_resources.resource_stream except (ImportError, AttributeError): pkg_resources = None class Request(RequestBase): """The request object used by default in flask. Remembers the matched endpoint and view arguments. It is what ends up as :class:`~flask.request`. If you want to replace the request object used you can subclass this and set :attr:`~flask.Flask.request_class` to your subclass. """ endpoint = view_args = routing_exception = None @property def module(self): """The name of the current module""" if self.endpoint and '.' in self.endpoint: return self.endpoint.rsplit('.', 1)[0] @cached_property def json(self): """If the mimetype is `application/json` this will contain the parsed JSON data. """ if __debug__: _assert_have_json() if self.mimetype == 'application/json': return json.loads(self.data) class Response(ResponseBase): """The response object that is used by default in flask. Works like the response object from Werkzeug but is set to have a HTML mimetype by default. Quite often you don't have to create this object yourself because :meth:`~flask.Flask.make_response` will take care of that for you. If you want to replace the response object used you can subclass this and set :attr:`~flask.Flask.request_class` to your subclass. """ default_mimetype = 'text/html' class _RequestGlobals(object): pass class Session(SecureCookie): """Expands the session with support for switching between permanent and non-permanent sessions. """ def _get_permanent(self): return self.get('_permanent', False) def _set_permanent(self, value): self['_permanent'] = bool(value) permanent = property(_get_permanent, _set_permanent) del _get_permanent, _set_permanent class _NullSession(Session): """Class used to generate nicer error messages if sessions are not available. Will still allow read-only access to the empty session but fail on setting. """ def _fail(self, *args, **kwargs): raise RuntimeError('the session is unavailable because no secret ' 'key was set. Set the secret_key on the ' 'application to something unique and secret') __setitem__ = __delitem__ = clear = pop = popitem = \ update = setdefault = _fail del _fail class _RequestContext(object): """The request context contains all request relevant information. It is created at the beginning of the request and pushed to the `_request_ctx_stack` and removed at the end of it. It will create the URL adapter and request object for the WSGI environment provided. """ def __init__(self, app, environ): self.app = app self.url_adapter = app.url_map.bind_to_environ(environ) self.request = app.request_class(environ) self.session = app.open_session(self.request) if self.session is None: self.session = _NullSession() self.g = _RequestGlobals() self.flashes = None try: self.request.endpoint, self.request.view_args = \ self.url_adapter.match() except HTTPException, e: self.request.routing_exception = e def __enter__(self): _request_ctx_stack.push(self) def __exit__(self, exc_type, exc_value, tb): # do not pop the request stack if we are in debug mode and an # exception happened. This will allow the debugger to still # access the request object in the interactive shell. if tb is None or not self.app.debug: _request_ctx_stack.pop() def url_for(endpoint, **values): """Generates a URL to the given endpoint with the method provided. The endpoint is relative to the active module if modules are in use. Here some examples: ==================== ======================= ============================= Active Module Target Endpoint Target Function ==================== ======================= ============================= `None` ``'index'`` `index` of the application `None` ``'.index'`` `index` of the application ``'admin'`` ``'index'`` `index` of the `admin` module any ``'.index'`` `index` of the application any ``'admin.index'`` `index` of the `admin` module ==================== ======================= ============================= Variable arguments that are unknown to the target endpoint are appended to the generated URL as query arguments. For more information, head over to the :ref:`Quickstart `. :param endpoint: the endpoint of the URL (name of the function) :param values: the variable arguments of the URL rule :param _external: if set to `True`, an absolute URL is generated. """ ctx = _request_ctx_stack.top if '.' not in endpoint: mod = ctx.request.module if mod is not None: endpoint = mod + '.' + endpoint elif endpoint.startswith('.'): endpoint = endpoint[1:] external = values.pop('_external', False) return ctx.url_adapter.build(endpoint, values, force_external=external) def get_template_attribute(template_name, attribute): """Loads a macro (or variable) a template exports. This can be used to invoke a macro from within Python code. If you for example have a template named `_foo.html` with the following contents: .. sourcecode:: html+jinja {% macro hello(name) %}Hello {{ name }}!{% endmacro %} You can access this from Python code like this:: hello = get_template_attribute('_foo.html', 'hello') return hello('World') .. versionadded:: 0.2 :param template_name: the name of the template :param attribute: the name of the variable of macro to acccess """ return getattr(current_app.jinja_env.get_template(template_name).module, attribute) def flash(message): """Flashes a message to the next request. In order to remove the flashed message from the session and to display it to the user, the template has to call :func:`get_flashed_messages`. :param message: the message to be flashed. """ session.setdefault('_flashes', []).append(message) def get_flashed_messages(): """Pulls all flashed messages from the session and returns them. Further calls in the same request to the function will return the same messages. """ flashes = _request_ctx_stack.top.flashes if flashes is None: _request_ctx_stack.top.flashes = flashes = session.pop('_flashes', []) return flashes def jsonify(*args, **kwargs): """Creates a :class:`~flask.Response` with the JSON representation of the given arguments with an `application/json` mimetype. The arguments to this function are the same as to the :class:`dict` constructor. Example usage:: @app.route('/_get_current_user') def get_current_user(): return jsonify(username=g.user.username, email=g.user.email, id=g.user.id) This will send a JSON response like this to the browser:: { "username": "admin", "email": "admin@localhost", "id": 42 } This requires Python 2.6 or an installed version of simplejson. .. versionadded:: 0.2 """ if __debug__: _assert_have_json() return current_app.response_class(json.dumps(dict(*args, **kwargs), indent=None if request.is_xhr else 2), mimetype='application/json') def send_file(filename_or_fp, mimetype=None, as_attachment=False, attachment_filename=None): """Sends the contents of a file to the client. This will use the most efficient method available and configured. By default it will try to use the WSGI server's file_wrapper support. Alternatively you can set the application's :attr:`~Flask.use_x_sendfile` attribute to ``True`` to directly emit an `X-Sendfile` header. This however requires support of the underlying webserver for `X-Sendfile`. By default it will try to guess the mimetype for you, but you can also explicitly provide one. For extra security you probably want to sent certain files as attachment (HTML for instance). Please never pass filenames to this function from user sources without checking them first. Something like this is usually sufficient to avoid security problems:: if '..' in filename or filename.startswith('/'): abort(404) .. versionadded:: 0.2 :param filename_or_fp: the filename of the file to send. This is relative to the :attr:`~Flask.root_path` if a relative path is specified. Alternatively a file object might be provided in which case `X-Sendfile` might not work and fall back to the traditional method. :param mimetype: the mimetype of the file if provided, otherwise auto detection happens. :param as_attachment: set to `True` if you want to send this file with a ``Content-Disposition: attachment`` header. :param attachment_filename: the filename for the attachment if it differs from the file's filename. """ if isinstance(filename_or_fp, basestring): filename = filename_or_fp file = None else: file = filename_or_fp filename = getattr(file, 'name', None) if filename is not None: filename = os.path.join(current_app.root_path, filename) if mimetype is None and (filename or attachment_filename): mimetype = mimetypes.guess_type(filename or attachment_filename)[0] if mimetype is None: mimetype = 'application/octet-stream' headers = Headers() if as_attachment: if attachment_filename is None: if filename is None: raise TypeError('filename unavailable, required for ' 'sending as attachment') attachment_filename = os.path.basename(filename) headers.add('Content-Disposition', 'attachment', filename=attachment_filename) if current_app.use_x_sendfile and filename: if file is not None: file.close() headers['X-Sendfile'] = filename data = None else: if file is None: file = open(filename, 'rb') data = wrap_file(request.environ, file) return Response(data, mimetype=mimetype, headers=headers, direct_passthrough=True) def render_template(template_name, **context): """Renders a template from the template folder with the given context. :param template_name: the name of the template to be rendered :param context: the variables that should be available in the context of the template. """ current_app.update_template_context(context) return current_app.jinja_env.get_template(template_name).render(context) def render_template_string(source, **context): """Renders a template from the given template source string with the given context. :param template_name: the sourcecode of the template to be rendered :param context: the variables that should be available in the context of the template. """ current_app.update_template_context(context) return current_app.jinja_env.from_string(source).render(context) def _default_template_ctx_processor(): """Default template context processor. Injects `request`, `session` and `g`. """ reqctx = _request_ctx_stack.top return dict( request=reqctx.request, session=reqctx.session, g=reqctx.g ) def _assert_have_json(): """Helper function that fails if JSON is unavailable.""" if not json_available: raise RuntimeError('simplejson not installed') def _get_package_path(name): """Returns the path to a package or cwd if that cannot be found.""" try: return os.path.abspath(os.path.dirname(sys.modules[name].__file__)) except (KeyError, AttributeError): return os.getcwd() # figure out if simplejson escapes slashes. This behaviour was changed # from one version to another without reason. if not json_available or '\\/' not in json.dumps('/'): def _tojson_filter(*args, **kwargs): if __debug__: _assert_have_json() return json.dumps(*args, **kwargs).replace('/', '\\/') else: _tojson_filter = json.dumps class _PackageBoundObject(object): def __init__(self, import_name): #: the name of the package or module. Do not change this once #: it was set by the constructor. self.import_name = import_name #: where is the app root located? self.root_path = _get_package_path(self.import_name) def open_resource(self, resource): """Opens a resource from the application's resource folder. To see how this works, consider the following folder structure:: /myapplication.py /schemal.sql /static /style.css /template /layout.html /index.html If you want to open the `schema.sql` file you would do the following:: with app.open_resource('schema.sql') as f: contents = f.read() do_something_with(contents) :param resource: the name of the resource. To access resources within subfolders use forward slashes as separator. """ if pkg_resources is None: return open(os.path.join(self.root_path, resource), 'rb') return pkg_resources.resource_stream(self.import_name, resource) class _ModuleSetupState(object): def __init__(self, app, url_prefix=None): self.app = app self.url_prefix = url_prefix class Module(_PackageBoundObject): """Container object that enables pluggable applications. A module can be used to organize larger applications. They represent blueprints that, in combination with a :class:`Flask` object are used to create a large application. A module is like an application bound to an `import_name`. Multiple modules can share the same import names, but in that case a `name` has to be provided to keep them apart. If different import names are used, the rightmost part of the import name is used as name. Here an example structure for a larger appliation:: /myapplication /__init__.py /views /__init__.py /admin.py /frontend.py The `myapplication/__init__.py` can look like this:: from flask import Flask from myapplication.views.admin import admin from myapplication.views.frontend import frontend app = Flask(__name__) app.register_module(admin, url_prefix='/admin') app.register_module(frontend) And here an example view module (`myapplication/views/admin.py`):: from flask import Module admin = Module(__name__) @admin.route('/') def index(): pass @admin.route('/login') def login(): pass For a gentle introduction into modules, checkout the :ref:`working-with-modules` section. """ def __init__(self, import_name, name=None, url_prefix=None): if name is None: assert '.' in import_name, 'name required if package name ' \ 'does not point to a submodule' name = import_name.rsplit('.', 1)[1] _PackageBoundObject.__init__(self, import_name) self.name = name self.url_prefix = url_prefix self._register_events = [] def route(self, rule, **options): """Like :meth:`Flask.route` but for a module. The endpoint for the :func:`url_for` function is prefixed with the name of the module. """ def decorator(f): self.add_url_rule(rule, f.__name__, f, **options) return f return decorator def add_url_rule(self, rule, endpoint, view_func=None, **options): """Like :meth:`Flask.add_url_rule` but for a module. The endpoint for the :func:`url_for` function is prefixed with the name of the module. """ def register_rule(state): the_rule = rule if state.url_prefix: the_rule = state.url_prefix + rule state.app.add_url_rule(the_rule, '%s.%s' % (self.name, endpoint), view_func, **options) self._record(register_rule) def before_request(self, f): """Like :meth:`Flask.before_request` but for a module. This function is only executed before each request that is handled by a function of that module. """ self._record(lambda s: s.app.before_request_funcs .setdefault(self.name, []).append(f)) return f def before_app_request(self, f): """Like :meth:`Flask.before_request`. Such a function is executed before each request, even if outside of a module. """ self._record(lambda s: s.app.before_request_funcs .setdefault(None, []).append(f)) return f def after_request(self, f): """Like :meth:`Flask.after_request` but for a module. This function is only executed after each request that is handled by a function of that module. """ self._record(lambda s: s.app.after_request_funcs .setdefault(self.name, []).append(f)) return f def after_app_request(self, f): """Like :meth:`Flask.after_request` but for a module. Such a function is executed after each request, even if outside of the module. """ self._record(lambda s: s.app.after_request_funcs .setdefault(None, []).append(f)) return f def context_processor(self, f): """Like :meth:`Flask.context_processor` but for a modul. This function is only executed for requests handled by a module. """ self._record(lambda s: s.app.template_context_processors .setdefault(self.name, []).append(f)) return f def app_context_processor(self, f): """Like :meth:`Flask.context_processor` but for a module. Such a function is executed each request, even if outside of the module. """ self._record(lambda s: s.app.template_context_processors .setdefault(None, []).append(f)) return f def _record(self, func): self._register_events.append(func) 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 `__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 `__init__.py` file of your package like this:: from flask import Flask app = Flask(__name__) """ #: 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 #: path for the static files. If you don't want to use static files #: you can set this value to `None` in which case no URL rule is added #: and the development server will no longer serve any static files. static_path = '/static' #: 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. secret_key = None #: The secure cookie uses this for the name of the session cookie session_cookie_name = 'session' #: 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. permanent_session_lifetime = timedelta(days=31) #: 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 use_x_sendfile = False #: options that are passed directly to the Jinja2 environment jinja_options = ImmutableDict( autoescape=True, extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'] ) def __init__(self, import_name): _PackageBoundObject.__init__(self, import_name) #: 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 ocurrs and the integrated server #: will automatically reload the application if changes in the #: code are detected. self.debug = False #: 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 = {} #: a dictionary of all registered error handlers. The key is #: be the error code as integer, the value the function that #: should handle that error. #: To register a error handler, use the :meth:`errorhandler` #: decorator. self.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 module 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 dictionary with lists of functions that should be called after #: each request. The key of the dictionary is the name of the module #: 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.after_request_funcs = {} #: a dictionary with list of functions that are called without argument #: to populate the template context. They key of the dictionary is the #: name of the module 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] } #: 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 import BaseConverter #: #: class ListConverter(BaseConverter): #: def to_python(self, value): #: return value.split(',') #: def to_url(self, values): #: return ','.join(BaseConverter.to_url(value) #: for value in values) #: #: app = Flask(__name__) #: app.url_map.converters['list'] = ListConverter self.url_map = Map() if self.static_path is not None: self.add_url_rule(self.static_path + '/', build_only=True, endpoint='static') if pkg_resources is not None: target = (self.import_name, 'static') else: target = os.path.join(self.root_path, 'static') self.wsgi_app = SharedDataMiddleware(self.wsgi_app, { self.static_path: target }) #: the Jinja2 environment. It is created from the #: :attr:`jinja_options` and the loader that is returned #: by the :meth:`create_jinja_loader` function. self.jinja_env = Environment(loader=self.create_jinja_loader(), **self.jinja_options) self.jinja_env.globals.update( url_for=url_for, get_flashed_messages=get_flashed_messages ) self.jinja_env.filters['tojson'] = _tojson_filter def create_jinja_loader(self): """Creates the Jinja loader. By default just a package loader for the configured package is returned that looks up templates in the `templates` folder. To add other loaders it's possible to override this method. """ if pkg_resources is None: return FileSystemLoader(os.path.join(self.root_path, 'templates')) return PackageLoader(self.import_name) def update_template_context(self, context): """Update the template context with some commonly used variables. This injects request, session and g into the template context. :param context: the context as a dictionary that is updated in place to add extra variables. """ funcs = self.template_context_processors[None] mod = _request_ctx_stack.top.request.module if mod is not None and mod in self.template_context_processors: funcs = chain(funcs, self.template_context_processors[mod]) for func in funcs: context.update(func()) def run(self, host='127.0.0.1', port=5000, **options): """Runs the application on a local development server. If the :attr:`debug` flag is set the server will automatically reload for code changes and show a debugger in case an exception happened. :param host: the hostname to listen on. set this to ``'0.0.0.0'`` to have the server available externally as well. :param port: the port of the webserver :param options: the options to be forwarded to the underlying Werkzeug server. See :func:`werkzeug.run_simple` for more information. """ from werkzeug import run_simple if 'debug' in options: self.debug = options.pop('debug') options.setdefault('use_reloader', self.debug) options.setdefault('use_debugger', self.debug) return run_simple(host, port, self, **options) def test_client(self): """Creates a test client for this application. For information about unit testing head over to :ref:`testing`. """ from werkzeug import Client return Client(self, self.response_class, use_cookies=True) 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. :param request: an instance of :attr:`request_class`. """ key = self.secret_key if key is not None: return Session.load_cookie(request, self.session_cookie_name, secret_key=key) def save_session(self, session, response): """Saves the session if it needs updates. For the default implementation, check :meth:`open_session`. :param session: the session to be saved (a :class:`~werkzeug.contrib.securecookie.SecureCookie` object) :param response: an instance of :attr:`response_class` """ expires = None if session.permanent: expires = datetime.utcnow() + self.permanent_session_lifetime session.save_cookie(response, self.session_cookie_name, expires=expires, httponly=True) def register_module(self, module, **options): """Registers a module with this application. The keyword argument of this function are the same as the ones for the constructor of the :class:`Module` class and will override the values of the module if provided. """ options.setdefault('url_prefix', module.url_prefix) state = _ModuleSetupState(self, **options) for func in module._register_events: func(state) 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 .. versionchanged:: 0.2 `view_func` parameter added. :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 """ if endpoint is None: assert view_func is not None, 'expected view func if endpoint ' \ 'is not provided.' endpoint = view_func.__name__ options['endpoint'] = endpoint options.setdefault('methods', ('GET',)) self.url_map.add(Rule(rule, **options)) if view_func is not None: 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. Example:: @app.route('/') def index(): return 'Hello World' Variables parts in the route can be specified with angular brackets (``/user/``). By default a variable part in the URL accepts any string without a slash however a different converter can be specified as well by using ````. Variable parts are passed to the view function as keyword arguments. The following converters are possible: =========== =========================================== `int` accepts integers `float` like `int` but for floating point values `path` like the default but also accepts slashes =========== =========================================== Here some examples:: @app.route('/') def index(): pass @app.route('/') def show_user(username): pass @app.route('/post/') def show_post(post_id): pass An important detail to keep in mind is how Flask deals with trailing slashes. The idea is to keep each URL unique so the following rules apply: 1. If a rule ends with a slash and is requested without a slash by the user, the user is automatically redirected to the same page with a trailing slash attached. 2. If a rule does not end with a trailing slash and the user request the page with a trailing slash, a 404 not found is raised. This is consistent with how web servers deal with static files. This also makes it possible to use relative link targets safely. The :meth:`route` decorator accepts a couple of other arguments as well: :param rule: the URL rule as string :param methods: a list of methods this rule should be limited to (``GET``, ``POST`` etc.). By default a rule just listens for ``GET`` (and implicitly ``HEAD``). :param subdomain: specifies the rule for the subdoain in case subdomain matching is in use. :param strict_slashes: can be used to disable the strict slashes setting for this rule. See above. :param options: other options to be forwarded to the underlying :class:`~werkzeug.routing.Rule` object. """ def decorator(f): self.add_url_rule(rule, None, f, **options) return f return decorator def errorhandler(self, code): """A decorator that is used to register a function give a given error code. Example:: @app.errorhandler(404) def page_not_found(): return 'This page does not exist', 404 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(): return 'This page does not exist', 404 app.error_handlers[404] = page_not_found :param code: the code as integer for the handler """ def decorator(f): self.error_handlers[code] = f return f return decorator 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.jinja_env.filters[name or f.__name__] = f return f return decorator def before_request(self, f): """Registers a function to run before each request.""" self.before_request_funcs.setdefault(None, []).append(f) return f def after_request(self, f): """Register a function to be run after each request.""" self.after_request_funcs.setdefault(None, []).append(f) return f def context_processor(self, f): """Registers a template context processor function.""" self.template_context_processors[None].append(f) return f 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`. """ req = _request_ctx_stack.top.request try: if req.routing_exception is not None: raise req.routing_exception return self.view_functions[req.endpoint](**req.view_args) except HTTPException, e: handler = self.error_handlers.get(e.code) if handler is None: return e return handler(e) except Exception, e: handler = self.error_handlers.get(500) if self.debug or handler is None: raise return handler(e) 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`: ======================= =========================================== :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 :class:`tuple` the response object is created with the contents of the tuple as arguments a WSGI function the function is called as WSGI application and buffered as response object ======================= =========================================== :param rv: the return value from the view function """ if rv is None: raise ValueError('View function did not return a response') if isinstance(rv, self.response_class): return rv if isinstance(rv, basestring): return self.response_class(rv) if isinstance(rv, tuple): return self.response_class(*rv) return self.response_class.force_type(rv, request.environ) def preprocess_request(self): """Called before the actual request dispatching and will call every as :meth:`before_request` decorated function. If any of these function returns a value it's handled as if it was the return value from the view and further request handling is stopped. """ funcs = self.before_request_funcs.get(None, ()) mod = request.module if mod and mod in self.before_request_funcs: funcs = chain(funcs, self.before_request_funcs[mod]) 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. :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 mod = ctx.request.module if not isinstance(ctx.session, _NullSession): self.save_session(ctx.session, response) funcs = () if mod and mod in self.after_request_funcs: funcs = chain(funcs, self.after_request_funcs[mod]) if None in self.after_request_funcs: funcs = chain(funcs, self.after_request_funcs[None]) for handler in funcs: response = handler(response) return response 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. :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 """ with self.request_context(environ): rv = self.preprocess_request() if rv is None: rv = self.dispatch_request() response = self.make_response(rv) response = self.process_response(response) return response(environ, start_response) def request_context(self, environ): """Creates a request context 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) :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 :func:`werkzeug.create_environ` for more information, this function accepts the same arguments). """ return self.request_context(create_environ(*args, **kwargs)) def __call__(self, environ, start_response): """Shortcut for :attr:`wsgi_app`.""" return self.wsgi_app(environ, start_response) # context locals _request_ctx_stack = LocalStack() current_app = LocalProxy(lambda: _request_ctx_stack.top.app) request = LocalProxy(lambda: _request_ctx_stack.top.request) session = LocalProxy(lambda: _request_ctx_stack.top.session) g = LocalProxy(lambda: _request_ctx_stack.top.g)