| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  | # -*- 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. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import pkg_resources | 
					
						
							|  |  |  | from threading import local | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  | from contextlib import contextmanager | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  | from jinja2 import Environment, PackageLoader | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  | from werkzeug import Request, Response, LocalStack, LocalProxy, \ | 
					
						
							|  |  |  |      create_environ, cached_property | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  | from werkzeug.routing import Map, Rule | 
					
						
							|  |  |  | from werkzeug.exceptions import HTTPException, InternalServerError | 
					
						
							|  |  |  | from werkzeug.contrib.securecookie import SecureCookie | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # utilities we import from Werkzeug and Jinja2 that are unused | 
					
						
							|  |  |  | # in the module but are exported as public interface. | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  | from werkzeug import abort, redirect | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  | from jinja2 import Markup, escape | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FlaskRequest(Request): | 
					
						
							|  |  |  |     """The request object used by default in flask.  Remembers the
 | 
					
						
							|  |  |  |     matched endpoint and view arguments. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, environ): | 
					
						
							|  |  |  |         Request.__init__(self, environ) | 
					
						
							|  |  |  |         self.endpoint = None | 
					
						
							|  |  |  |         self.view_args = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FlaskResponse(Response): | 
					
						
							|  |  |  |     """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. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     default_mimetype = 'text/html' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _RequestGlobals(object): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							|  |  |  |         self.g = _RequestGlobals() | 
					
						
							|  |  |  |         self.flashes = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def url_for(endpoint, **values): | 
					
						
							|  |  |  |     """Generates a URL to the given endpoint with the method provided.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param endpoint: the endpoint of the URL (name of the function) | 
					
						
							|  |  |  |     :param values: the variable arguments of the URL rule | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     return _request_ctx_stack.top.url_adapter.build(endpoint, values) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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`. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     :param message: the message to be flashed. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     session['_flashes'] = (session.get('_flashes', [])) + [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 render_template(template_name, **context): | 
					
						
							|  |  |  |     """Renders a template from the template folder with the given
 | 
					
						
							|  |  |  |     context. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     :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. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  |     current_app.update_template_context(context) | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     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. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     :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. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  |     current_app.update_template_context(context) | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     return current_app.jinja_env.from_string(source).render(context) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Flask(object): | 
					
						
							|  |  |  |     """The flask object implements a WSGI application and acts as the central
 | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |     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__) | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #: the class that is used for request objects | 
					
						
							|  |  |  |     request_class = FlaskRequest | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #: the class that is used for response objects | 
					
						
							|  |  |  |     response_class = FlaskResponse | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #: 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' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #: options that are passed directly to the Jinja2 environment | 
					
						
							|  |  |  |     jinja_options = dict( | 
					
						
							|  |  |  |         autoescape=True, | 
					
						
							|  |  |  |         extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'] | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, package_name): | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         #: 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. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         self.debug = False | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         #: the name of the package or module.  Do not change this once | 
					
						
							|  |  |  |         #: it was set by the constructor. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         self.package_name = package_name | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         #: 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. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         self.view_functions = {} | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         #: 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. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         self.error_handlers = {} | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         #: a list of functions that should be called at the beginning | 
					
						
							|  |  |  |         #: of the request before request dispatching kicks in.  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:`request_init` | 
					
						
							|  |  |  |         #: decorator. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         self.request_init_funcs = [] | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         #: a list of functions that are called at the end of the | 
					
						
							|  |  |  |         #: request.  Tha function is passed the current response | 
					
						
							|  |  |  |         #: object and modify it in place or replace it. | 
					
						
							|  |  |  |         #: To register a function here use the :meth:`request_shtdown` | 
					
						
							|  |  |  |         #: decorator. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         self.request_shutdown_funcs = [] | 
					
						
							|  |  |  |         self.url_map = Map() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self.static_path is not None: | 
					
						
							|  |  |  |             self.url_map.add(Rule(self.static_path + '/<filename>', | 
					
						
							|  |  |  |                                   build_only=True, endpoint='static')) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         #: the Jinja2 environment.  It is created from the | 
					
						
							|  |  |  |         #: :attr:`jinja_options` and the loader that is returned | 
					
						
							|  |  |  |         #: by the :meth:`create_jinja_loader` function. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         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 | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return PackageLoader(self.package_name) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  |     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. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :param context: the context as a dictionary that is updated in place | 
					
						
							|  |  |  |                         to add extra variables. | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         reqctx = _request_ctx_stack.top | 
					
						
							|  |  |  |         context['request'] = reqctx.request | 
					
						
							|  |  |  |         context['session'] = reqctx.session | 
					
						
							|  |  |  |         context['g'] = reqctx.g | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     def run(self, host='localhost', port=5000, **options): | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         """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. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :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. | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         from werkzeug import run_simple | 
					
						
							|  |  |  |         if 'debug' in options: | 
					
						
							|  |  |  |             self.debug = options.pop('debug') | 
					
						
							|  |  |  |         if self.static_path is not None: | 
					
						
							|  |  |  |             options['static_files'] = { | 
					
						
							|  |  |  |                 self.static_path:   (self.package_name, 'static') | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         options.setdefault('use_reloader', self.debug) | 
					
						
							|  |  |  |         options.setdefault('use_debugger', self.debug) | 
					
						
							|  |  |  |         return run_simple(host, port, self, **options) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @cached_property | 
					
						
							|  |  |  |     def test(self): | 
					
						
							|  |  |  |         """A test client for this application""" | 
					
						
							|  |  |  |         from werkzeug import Client | 
					
						
							|  |  |  |         return Client(self, self.response_class, use_cookies=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def open_resource(self, resource): | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         """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) | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :param resource: the name of the resource.  To access resources within | 
					
						
							|  |  |  |                          subfolders use forward slashes as separator. | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         return pkg_resources.resource_stream(self.package_name, resource) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def open_session(self, request): | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         """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. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :param request: an instance of :attr:`request_class`. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         key = self.secret_key | 
					
						
							|  |  |  |         if key is not None: | 
					
						
							|  |  |  |             return SecureCookie.load_cookie(request, self.session_cookie_name, | 
					
						
							|  |  |  |                                             secret_key=key) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def save_session(self, session, response): | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         """Saves the session if it needs updates.  For the default
 | 
					
						
							|  |  |  |         implementation, check :meth:`open_session`. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :param session: the session to be saved (a | 
					
						
							|  |  |  |                         :class:`~werkzeug.contrib.securecookie.SecureCookie` | 
					
						
							|  |  |  |                         object) | 
					
						
							|  |  |  |         :param request: an instance of :attr:`response_class` | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         if session is not None: | 
					
						
							|  |  |  |             session.save_cookie(response, self.session_cookie_name) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-10 21:49:15 +08:00
										 |  |  |     def add_url_rule(self, rule, endpoint, **options): | 
					
						
							| 
									
										
										
										
											2010-04-09 19:56:47 +08:00
										 |  |  |         """Connects a URL rule.  Works exactly like the :meth:`route`
 | 
					
						
							|  |  |  |         decorator but does not register the view function for the endpoint. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Basically this example:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             @app.route('/') | 
					
						
							|  |  |  |             def index(): | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-10 21:49:15 +08:00
										 |  |  |         Is equivalent to the following:: | 
					
						
							| 
									
										
										
										
											2010-04-09 19:56:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             def index(): | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |             app.add_url_rule('index', '/') | 
					
						
							|  |  |  |             app.view_functions['index'] = index | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :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 | 
					
						
							| 
									
										
										
										
											2010-04-09 19:56:47 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2010-04-10 21:49:15 +08:00
										 |  |  |         options['endpoint'] = endpoint | 
					
						
							| 
									
										
										
										
											2010-04-09 19:56:47 +08:00
										 |  |  |         options.setdefault('methods', ('GET',)) | 
					
						
							|  |  |  |         self.url_map.add(Rule(rule, **options)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     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' | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Variables parts in the route can be specified with angular | 
					
						
							|  |  |  |         brackets (``/user/<username>``).  By default a variable part | 
					
						
							|  |  |  |         in the URL accepts any string without a slash however a differnt | 
					
						
							|  |  |  |         converter can be specified as well by using ``<converter:name>``. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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('/<username>') | 
					
						
							|  |  |  |             def show_user(username): | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             @app.route('/post/<int:post_id>') | 
					
						
							|  |  |  |             def show_post(post_id): | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-09 07:32:39 +08:00
										 |  |  |         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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         The :meth:`route` decorator accepts a couple of other arguments | 
					
						
							|  |  |  |         as well: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  |         :param rule: the URL rule as string | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         :param methods: a list of methods this rule should be limited | 
					
						
							| 
									
										
										
										
											2010-04-09 07:32:39 +08:00
										 |  |  |                         to (``GET``, ``POST`` etc.).  By default a rule | 
					
						
							|  |  |  |                         just listens for ``GET`` (and implicitly ``HEAD``). | 
					
						
							| 
									
										
										
										
											2010-04-06 22:02:14 +08:00
										 |  |  |         :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. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  |         :param options: other options to be forwarded to the underlying | 
					
						
							|  |  |  |                         :class:`~werkzeug.routing.Rule` object. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         def decorator(f): | 
					
						
							| 
									
										
										
										
											2010-04-10 21:49:15 +08:00
										 |  |  |             self.add_url_rule(rule, f.__name__, **options) | 
					
						
							| 
									
										
										
										
											2010-04-09 19:56:47 +08:00
										 |  |  |             self.view_functions[f.__name__] = f | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2010-04-09 19:56:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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 | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :param code: the code as integer for the handler | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         def decorator(f): | 
					
						
							|  |  |  |             self.error_handlers[code] = f | 
					
						
							|  |  |  |             return f | 
					
						
							|  |  |  |         return decorator | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def request_init(self, f): | 
					
						
							|  |  |  |         """Registers a function to run before each request.""" | 
					
						
							|  |  |  |         self.request_init_funcs.append(f) | 
					
						
							|  |  |  |         return f | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def request_shutdown(self, f): | 
					
						
							|  |  |  |         """Register a function to be run after each request.""" | 
					
						
							|  |  |  |         self.request_shutdown_funcs.append(f) | 
					
						
							|  |  |  |         return f | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def match_request(self): | 
					
						
							|  |  |  |         """Matches the current request against the URL map and also
 | 
					
						
							|  |  |  |         stores the endpoint and view arguments on the request object | 
					
						
							|  |  |  |         is successful, otherwise the exception is stored. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         rv = _request_ctx_stack.top.url_adapter.match() | 
					
						
							|  |  |  |         request.endpoint, request.view_args = rv | 
					
						
							|  |  |  |         return rv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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`. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             endpoint, values = self.match_request() | 
					
						
							|  |  |  |             return self.view_functions[endpoint](**values) | 
					
						
							|  |  |  |         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`. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         The following types are allowd 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 | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         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 :func:`request_init` 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. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         for func in self.request_init_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. | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :param response: a :attr:`response_class` object. | 
					
						
							|  |  |  |         :return: a new response object or the same, has to be an | 
					
						
							|  |  |  |                  instance of :attr:`response_class`. | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         session = _request_ctx_stack.top.session | 
					
						
							|  |  |  |         if session is not None: | 
					
						
							|  |  |  |             self.save_session(session, response) | 
					
						
							|  |  |  |         for handler in self.request_shutdown_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: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             app.wsgi_app = MyMiddleware(app.wsgi_app) | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :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 | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  |         with self.request_context(environ): | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |             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) | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @contextmanager | 
					
						
							|  |  |  |     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) | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         :params environ: a WSGI environment | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         _request_ctx_stack.push(_RequestContext(self, environ)) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             yield | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |         finally: | 
					
						
							|  |  |  |             _request_ctx_stack.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  |     def test_request_context(self, *args, **kwargs): | 
					
						
							|  |  |  |         """Creates a WSGI environment from the given values (see
 | 
					
						
							| 
									
										
										
										
											2010-04-11 08:20:10 +08:00
										 |  |  |         :func:`werkzeug.create_environ` for more information, this | 
					
						
							|  |  |  |         function accepts the same arguments). | 
					
						
							| 
									
										
										
										
											2010-04-09 01:03:15 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         return self.request_context(create_environ(*args, **kwargs)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-06 19:12:57 +08:00
										 |  |  |     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) |