Home | History | Annotate | Download | only in webapp2
      1 # -*- coding: utf-8 -*-
      2 """
      3     webapp2
      4     =======
      5 
      6     Taking Google App Engine's webapp to the next level!
      7 
      8     :copyright: 2011 by tipfy.org.
      9     :license: Apache Sotware License, see LICENSE for details.
     10 """
     11 from __future__ import with_statement
     12 
     13 import cgi
     14 import inspect
     15 import logging
     16 import os
     17 import re
     18 import sys
     19 import threading
     20 import traceback
     21 import urllib
     22 import urlparse
     23 from wsgiref import handlers
     24 
     25 import webob
     26 from webob import exc
     27 
     28 _webapp = _webapp_util = _local = None
     29 
     30 try: # pragma: no cover
     31     # WebOb < 1.0 (App Engine Python 2.5).
     32     from webob.statusreasons import status_reasons
     33     from webob.headerdict import HeaderDict as BaseResponseHeaders
     34 except ImportError: # pragma: no cover
     35     # WebOb >= 1.0.
     36     from webob.util import status_reasons
     37     from webob.headers import ResponseHeaders as BaseResponseHeaders
     38 
     39 # google.appengine.ext.webapp imports webapp2 in the
     40 # App Engine Python 2.7 runtime.
     41 if os.environ.get('APPENGINE_RUNTIME') != 'python27': # pragma: no cover
     42     try:
     43         from google.appengine.ext import webapp as _webapp
     44     except ImportError: # pragma: no cover
     45         # Running webapp2 outside of GAE.
     46         pass
     47 
     48 try: # pragma: no cover
     49     # Thread-local variables container.
     50     from webapp2_extras import local
     51     _local = local.Local()
     52 except ImportError: # pragma: no cover
     53     logging.warning("webapp2_extras.local is not available "
     54                     "so webapp2 won't be thread-safe!")
     55 
     56 
     57 __version_info__ = (2, 5, 1)
     58 __version__ = '.'.join(str(n) for n in __version_info__)
     59 
     60 #: Base HTTP exception, set here as public interface.
     61 HTTPException = exc.HTTPException
     62 
     63 #: Regex for route definitions.
     64 _route_re = re.compile(r"""
     65     \<               # The exact character "<"
     66     ([a-zA-Z_]\w*)?  # The optional variable name
     67     (?:\:([^\>]*))?  # The optional :regex part
     68     \>               # The exact character ">"
     69     """, re.VERBOSE)
     70 #: Regex extract charset from environ.
     71 _charset_re = re.compile(r';\s*charset=([^;]*)', re.I)
     72 
     73 #: To show exceptions in debug mode.
     74 _debug_template = """<html>
     75   <head>
     76     <title>Internal Server Error</title>
     77     <style>
     78       body {
     79         padding: 20px;
     80         font-family: arial, sans-serif;
     81         font-size: 14px;
     82       }
     83       pre {
     84         background: #F2F2F2;
     85         padding: 10px;
     86       }
     87     </style>
     88   </head>
     89   <body>
     90     <h1>Internal Server Error</h1>
     91     <p>The server has either erred or is incapable of performing
     92     the requested operation.</p>
     93     <pre>%s</pre>
     94   </body>
     95 </html>"""
     96 
     97 # Set same default messages from webapp plus missing ones.
     98 _webapp_status_reasons = {
     99     203: 'Non-Authoritative Information',
    100     302: 'Moved Temporarily',
    101     306: 'Unused',
    102     408: 'Request Time-out',
    103     414: 'Request-URI Too Large',
    104     504: 'Gateway Time-out',
    105     505: 'HTTP Version not supported',
    106 }
    107 status_reasons.update(_webapp_status_reasons)
    108 for code, message in _webapp_status_reasons.iteritems():
    109     cls = exc.status_map.get(code)
    110     if cls:
    111         cls.title = message
    112 
    113 
    114 class Request(webob.Request):
    115     """Abstraction for an HTTP request.
    116 
    117     Most extra methods and attributes are ported from webapp. Check the
    118     `WebOb documentation <WebOb>`_ for the ones not listed here.
    119     """
    120 
    121     #: A reference to the active :class:`WSGIApplication` instance.
    122     app = None
    123     #: A reference to the active :class:`Response` instance.
    124     response = None
    125     #: A reference to the matched :class:`Route`.
    126     route = None
    127     #: The matched route positional arguments.
    128     route_args = None
    129     #: The matched route keyword arguments.
    130     route_kwargs = None
    131     #: A dictionary to register objects used during the request lifetime.
    132     registry = None
    133     # Attributes from webapp.
    134     request_body_tempfile_limit = 0
    135     uri = property(lambda self: self.url)
    136     query = property(lambda self: self.query_string)
    137 
    138     def __init__(self, environ, *args, **kwargs):
    139         """Constructs a Request object from a WSGI environment.
    140 
    141         :param environ:
    142             A WSGI-compliant environment dictionary.
    143         """
    144         if kwargs.get('charset') is None and not hasattr(webob, '__version__'):
    145             # webob 0.9 didn't have a __version__ attribute and also defaulted
    146             # to None rather than UTF-8 if no charset was provided. Providing a
    147             # default charset is required for backwards compatibility.
    148             match = _charset_re.search(environ.get('CONTENT_TYPE', ''))
    149             if match:
    150                 charset = match.group(1).lower().strip().strip('"').strip()
    151             else:
    152                 charset = 'utf-8'
    153             kwargs['charset'] = charset
    154 
    155         super(Request, self).__init__(environ, *args, **kwargs)
    156         self.registry = {}
    157 
    158     def get(self, argument_name, default_value='', allow_multiple=False):
    159         """Returns the query or POST argument with the given name.
    160 
    161         We parse the query string and POST payload lazily, so this will be a
    162         slower operation on the first call.
    163 
    164         :param argument_name:
    165             The name of the query or POST argument.
    166         :param default_value:
    167             The value to return if the given argument is not present.
    168         :param allow_multiple:
    169             Return a list of values with the given name (deprecated).
    170         :returns:
    171             If allow_multiple is False (which it is by default), we return
    172             the first value with the given name given in the request. If it
    173             is True, we always return a list.
    174         """
    175         param_value = self.get_all(argument_name)
    176         if allow_multiple:
    177             logging.warning('allow_multiple is a deprecated param. '
    178                 'Please use the Request.get_all() method instead.')
    179 
    180         if len(param_value) > 0:
    181             if allow_multiple:
    182                 return param_value
    183 
    184             return param_value[0]
    185         else:
    186             if allow_multiple and not default_value:
    187                 return []
    188 
    189             return default_value
    190 
    191     def get_all(self, argument_name, default_value=None):
    192         """Returns a list of query or POST arguments with the given name.
    193 
    194         We parse the query string and POST payload lazily, so this will be a
    195         slower operation on the first call.
    196 
    197         :param argument_name:
    198             The name of the query or POST argument.
    199         :param default_value:
    200             The value to return if the given argument is not present,
    201             None may not be used as a default, if it is then an empty
    202             list will be returned instead.
    203         :returns:
    204             A (possibly empty) list of values.
    205         """
    206         if self.charset:
    207             argument_name = argument_name.encode(self.charset)
    208 
    209         if default_value is None:
    210             default_value = []
    211 
    212         param_value = self.params.getall(argument_name)
    213 
    214         if param_value is None or len(param_value) == 0:
    215             return default_value
    216 
    217         for i in xrange(len(param_value)):
    218             if isinstance(param_value[i], cgi.FieldStorage):
    219                 param_value[i] = param_value[i].value
    220 
    221         return param_value
    222 
    223     def arguments(self):
    224         """Returns a list of the arguments provided in the query and/or POST.
    225 
    226         The return value is a list of strings.
    227         """
    228         return list(set(self.params.keys()))
    229 
    230     def get_range(self, name, min_value=None, max_value=None, default=0):
    231         """Parses the given int argument, limiting it to the given range.
    232 
    233         :param name:
    234             The name of the argument.
    235         :param min_value:
    236             The minimum int value of the argument (if any).
    237         :param max_value:
    238             The maximum int value of the argument (if any).
    239         :param default:
    240             The default value of the argument if it is not given.
    241         :returns:
    242             An int within the given range for the argument.
    243         """
    244         value = self.get(name, default)
    245         if value is None:
    246             return value
    247 
    248         try:
    249             value = int(value)
    250         except ValueError:
    251             value = default
    252             if value is not None:
    253                 if max_value is not None:
    254                     value = min(value, max_value)
    255 
    256                 if min_value is not None:
    257                     value = max(value, min_value)
    258 
    259         return value
    260 
    261     @classmethod
    262     def blank(cls, path, environ=None, base_url=None,
    263               headers=None, **kwargs): # pragma: no cover
    264         """Adds parameters compatible with WebOb >= 1.0: POST and **kwargs."""
    265         try:
    266             return super(Request, cls).blank(path, environ=environ,
    267                                              base_url=base_url,
    268                                              headers=headers, **kwargs)
    269         except TypeError:
    270             if not kwargs:
    271                 raise
    272 
    273         data = kwargs.pop('POST', None)
    274         if data is not None:
    275             from cStringIO import StringIO
    276             environ = environ or {}
    277             environ['REQUEST_METHOD'] = 'POST'
    278             if hasattr(data, 'items'):
    279                 data = data.items()
    280             if not isinstance(data, str):
    281                 data = urllib.urlencode(data)
    282             environ['wsgi.input'] = StringIO(data)
    283             environ['webob.is_body_seekable'] = True
    284             environ['CONTENT_LENGTH'] = str(len(data))
    285             environ['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
    286 
    287         base = super(Request, cls).blank(path, environ=environ,
    288                                          base_url=base_url, headers=headers)
    289         if kwargs:
    290             obj = cls(base.environ, **kwargs)
    291             obj.headers.update(base.headers)
    292             return obj
    293         else:
    294             return base
    295 
    296 
    297 class ResponseHeaders(BaseResponseHeaders):
    298     """Implements methods from ``wsgiref.headers.Headers``, used by webapp."""
    299 
    300     get_all = BaseResponseHeaders.getall
    301 
    302     def add_header(self, _name, _value, **_params):
    303         """Extended header setting.
    304 
    305         _name is the header field to add.  keyword arguments can be used to set
    306         additional parameters for the header field, with underscores converted
    307         to dashes.  Normally the parameter will be added as key="value" unless
    308         value is None, in which case only the key will be added.
    309 
    310         Example::
    311 
    312             h.add_header('content-disposition', 'attachment',
    313                          filename='bud.gif')
    314 
    315         Note that unlike the corresponding 'email.message' method, this does
    316         *not* handle '(charset, language, value)' tuples: all values must be
    317         strings or None.
    318         """
    319         parts = []
    320         if _value is not None:
    321             parts.append(_value)
    322 
    323         for k, v in _params.items():
    324             k = k.replace('_', '-')
    325             if v is not None and len(v) > 0:
    326                 v = v.replace('\\', '\\\\').replace('"', r'\"')
    327                 parts.append('%s="%s"' % (k, v))
    328             else:
    329                 parts.append(k)
    330 
    331         self.add(_name, '; '.join(parts))
    332 
    333     def __str__(self):
    334         """Returns the formatted headers ready for HTTP transmission."""
    335         return '\r\n'.join(['%s: %s' % v for v in self.items()] + ['', ''])
    336 
    337 
    338 class Response(webob.Response):
    339     """Abstraction for an HTTP response.
    340 
    341     Most extra methods and attributes are ported from webapp. Check the
    342     `WebOb documentation <WebOb>`_ for the ones not listed here.
    343 
    344     Differences from webapp.Response:
    345 
    346     - ``out`` is not a ``StringIO.StringIO`` instance. Instead it is the
    347       response itself, as it has the method ``write()``.
    348     - As in WebOb, ``status`` is the code plus message, e.g., '200 OK', while
    349       in webapp it is the integer code. The status code as an integer is
    350       available in ``status_int``, and the status message is available in
    351       ``status_message``.
    352     - ``response.headers`` raises an exception when a key that doesn't exist
    353       is accessed or deleted, differently from ``wsgiref.headers.Headers``.
    354     """
    355 
    356     #: Default charset as in webapp.
    357     default_charset = 'utf-8'
    358 
    359     def __init__(self, *args, **kwargs):
    360         """Constructs a response with the default settings."""
    361         super(Response, self).__init__(*args, **kwargs)
    362         self.headers['Cache-Control'] = 'no-cache'
    363 
    364     @property
    365     def out(self):
    366         """A reference to the Response instance itself, for compatibility with
    367         webapp only: webapp uses `Response.out.write()`, so we point `out` to
    368         `self` and it will use `Response.write()`.
    369         """
    370         return self
    371 
    372     def write(self, text):
    373         """Appends a text to the response body."""
    374         # webapp uses StringIO as Response.out, so we need to convert anything
    375         # that is not str or unicode to string to keep same behavior.
    376         if not isinstance(text, basestring):
    377             text = unicode(text)
    378 
    379         if isinstance(text, unicode) and not self.charset:
    380             self.charset = self.default_charset
    381 
    382         super(Response, self).write(text)
    383 
    384     def _set_status(self, value):
    385         """The status string, including code and message."""
    386         message = None
    387         # Accept long because urlfetch in App Engine returns codes as longs.
    388         if isinstance(value, (int, long)):
    389             code = int(value)
    390         else:
    391             if isinstance(value, unicode):
    392                 # Status messages have to be ASCII safe, so this is OK.
    393                 value = str(value)
    394 
    395             if not isinstance(value, str):
    396                 raise TypeError(
    397                     'You must set status to a string or integer (not %s)' %
    398                     type(value))
    399 
    400             parts = value.split(' ', 1)
    401             code = int(parts[0])
    402             if len(parts) == 2:
    403                 message = parts[1]
    404 
    405         message = message or Response.http_status_message(code)
    406         self._status = '%d %s' % (code, message)
    407 
    408     def _get_status(self):
    409         return self._status
    410 
    411     status = property(_get_status, _set_status, doc=_set_status.__doc__)
    412 
    413     def set_status(self, code, message=None):
    414         """Sets the HTTP status code of this response.
    415 
    416         :param code:
    417             The HTTP status string to use
    418         :param message:
    419             A status string. If none is given, uses the default from the
    420             HTTP/1.1 specification.
    421         """
    422         if message:
    423             self.status = '%d %s' % (code, message)
    424         else:
    425             self.status = code
    426 
    427     def _get_status_message(self):
    428         """The response status message, as a string."""
    429         return self.status.split(' ', 1)[1]
    430 
    431     def _set_status_message(self, message):
    432         self.status = '%d %s' % (self.status_int, message)
    433 
    434     status_message = property(_get_status_message, _set_status_message,
    435                               doc=_get_status_message.__doc__)
    436 
    437     def _get_headers(self):
    438         """The headers as a dictionary-like object."""
    439         if self._headers is None:
    440             self._headers = ResponseHeaders.view_list(self.headerlist)
    441 
    442         return self._headers
    443 
    444     def _set_headers(self, value):
    445         if hasattr(value, 'items'):
    446             value = value.items()
    447         elif not isinstance(value, list):
    448             raise TypeError('Response headers must be a list or dictionary.')
    449 
    450         self.headerlist = value
    451         self._headers = None
    452 
    453     headers = property(_get_headers, _set_headers, doc=_get_headers.__doc__)
    454 
    455     def has_error(self):
    456         """Indicates whether the response was an error response."""
    457         return self.status_int >= 400
    458 
    459     def clear(self):
    460         """Clears all data written to the output stream so that it is empty."""
    461         self.body = ''
    462 
    463     def wsgi_write(self, start_response):
    464         """Writes this response using using the given WSGI function.
    465 
    466         This is only here for compatibility with ``webapp.WSGIApplication``.
    467 
    468         :param start_response:
    469             The WSGI-compatible start_response function.
    470         """
    471         if (self.headers.get('Cache-Control') == 'no-cache' and
    472             not self.headers.get('Expires')):
    473             self.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT'
    474             self.headers['Content-Length'] = str(len(self.body))
    475 
    476         write = start_response(self.status, self.headerlist)
    477         write(self.body)
    478 
    479     @staticmethod
    480     def http_status_message(code):
    481         """Returns the default HTTP status message for the given code.
    482 
    483         :param code:
    484             The HTTP code for which we want a message.
    485         """
    486         message = status_reasons.get(code)
    487         if not message:
    488             raise KeyError('Invalid HTTP status code: %d' % code)
    489 
    490         return message
    491 
    492 
    493 class RequestHandler(object):
    494     """Base HTTP request handler.
    495 
    496     Implements most of ``webapp.RequestHandler`` interface.
    497     """
    498 
    499     #: A :class:`Request` instance.
    500     request = None
    501     #: A :class:`Response` instance.
    502     response = None
    503     #: A :class:`WSGIApplication` instance.
    504     app = None
    505 
    506     def __init__(self, request=None, response=None):
    507         """Initializes this request handler with the given WSGI application,
    508         Request and Response.
    509 
    510         When instantiated by ``webapp.WSGIApplication``, request and response
    511         are not set on instantiation. Instead, initialize() is called right
    512         after the handler is created to set them.
    513 
    514         Also in webapp dispatching is done by the WSGI app, while webapp2
    515         does it here to allow more flexibility in extended classes: handlers
    516         can wrap :meth:`dispatch` to check for conditions before executing the
    517         requested method and/or post-process the response.
    518 
    519         .. note::
    520            Parameters are optional only to support webapp's constructor which
    521            doesn't take any arguments. Consider them as required.
    522 
    523         :param request:
    524             A :class:`Request` instance.
    525         :param response:
    526             A :class:`Response` instance.
    527         """
    528         self.initialize(request, response)
    529 
    530     def initialize(self, request, response):
    531         """Initializes this request handler with the given WSGI application,
    532         Request and Response.
    533 
    534         :param request:
    535             A :class:`Request` instance.
    536         :param response:
    537             A :class:`Response` instance.
    538         """
    539         self.request = request
    540         self.response = response
    541         self.app = WSGIApplication.active_instance
    542 
    543     def dispatch(self):
    544         """Dispatches the request.
    545 
    546         This will first check if there's a handler_method defined in the
    547         matched route, and if not it'll use the method correspondent to the
    548         request method (``get()``, ``post()`` etc).
    549         """
    550         request = self.request
    551         method_name = request.route.handler_method
    552         if not method_name:
    553             method_name = _normalize_handler_method(request.method)
    554 
    555         method = getattr(self, method_name, None)
    556         if method is None:
    557             # 405 Method Not Allowed.
    558             # The response MUST include an Allow header containing a
    559             # list of valid methods for the requested resource.
    560             # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.6
    561             valid = ', '.join(_get_handler_methods(self))
    562             self.abort(405, headers=[('Allow', valid)])
    563 
    564         # The handler only receives *args if no named variables are set.
    565         args, kwargs = request.route_args, request.route_kwargs
    566         if kwargs:
    567             args = ()
    568 
    569         try:
    570             return method(*args, **kwargs)
    571         except Exception, e:
    572             return self.handle_exception(e, self.app.debug)
    573 
    574     def error(self, code):
    575         """Clears the response and sets the given HTTP status code.
    576 
    577         This doesn't stop code execution; for this, use :meth:`abort`.
    578 
    579         :param code:
    580             HTTP status error code (e.g., 501).
    581         """
    582         self.response.status = code
    583         self.response.clear()
    584 
    585     def abort(self, code, *args, **kwargs):
    586         """Raises an :class:`HTTPException`.
    587 
    588         This stops code execution, leaving the HTTP exception to be handled
    589         by an exception handler.
    590 
    591         :param code:
    592             HTTP status code (e.g., 404).
    593         :param args:
    594             Positional arguments to be passed to the exception class.
    595         :param kwargs:
    596             Keyword arguments to be passed to the exception class.
    597         """
    598         abort(code, *args, **kwargs)
    599 
    600     def redirect(self, uri, permanent=False, abort=False, code=None,
    601                  body=None):
    602         """Issues an HTTP redirect to the given relative URI.
    603 
    604         The arguments are described in :func:`redirect`.
    605         """
    606         return redirect(uri, permanent=permanent, abort=abort, code=code,
    607                         body=body, request=self.request,
    608                         response=self.response)
    609 
    610     def redirect_to(self, _name, _permanent=False, _abort=False, _code=None,
    611                     _body=None, *args, **kwargs):
    612         """Convenience method mixing :meth:`redirect` and :meth:`uri_for`.
    613 
    614         The arguments are described in :func:`redirect` and :func:`uri_for`.
    615         """
    616         uri = self.uri_for(_name, *args, **kwargs)
    617         return self.redirect(uri, permanent=_permanent, abort=_abort,
    618                              code=_code, body=_body)
    619 
    620     def uri_for(self, _name, *args, **kwargs):
    621         """Returns a URI for a named :class:`Route`.
    622 
    623         .. seealso:: :meth:`Router.build`.
    624         """
    625         return self.app.router.build(self.request, _name, args, kwargs)
    626     # Alias.
    627     url_for = uri_for
    628 
    629     def handle_exception(self, exception, debug):
    630         """Called if this handler throws an exception during execution.
    631 
    632         The default behavior is to re-raise the exception to be handled by
    633         :meth:`WSGIApplication.handle_exception`.
    634 
    635         :param exception:
    636             The exception that was thrown.
    637         :param debug_mode:
    638             True if the web application is running in debug mode.
    639         """
    640         raise
    641 
    642 
    643 class RedirectHandler(RequestHandler):
    644     """Redirects to the given URI for all GET requests.
    645 
    646     This is intended to be used when defining URI routes. You must provide at
    647     least the keyword argument *url* in the route default values. Example::
    648 
    649         def get_redirect_url(handler, *args, **kwargs):
    650             return handler.uri_for('new-route-name')
    651 
    652         app = WSGIApplication([
    653             Route('/old-url', RedirectHandler, defaults={'_uri': '/new-url'}),
    654             Route('/other-old-url', RedirectHandler, defaults={
    655                   '_uri': get_redirect_url}),
    656         ])
    657 
    658     Based on idea from `Tornado`_.
    659     """
    660 
    661     def get(self, *args, **kwargs):
    662         """Performs a redirect.
    663 
    664         Two keyword arguments can be passed through the URI route:
    665 
    666         - **_uri**: A URI string or a callable that returns a URI. The callable
    667           is called passing ``(handler, *args, **kwargs)`` as arguments.
    668         - **_code**: The redirect status code. Default is 301 (permanent
    669           redirect).
    670         """
    671         uri = kwargs.pop('_uri', '/')
    672         permanent = kwargs.pop('_permanent', True)
    673         code = kwargs.pop('_code', None)
    674 
    675         func = getattr(uri, '__call__', None)
    676         if func:
    677             uri = func(self, *args, **kwargs)
    678 
    679         self.redirect(uri, permanent=permanent, code=code)
    680 
    681 
    682 class cached_property(object):
    683     """A decorator that converts a function into a lazy property.
    684 
    685     The function wrapped is called the first time to retrieve the result
    686     and then that calculated result is used the next time you access
    687     the value::
    688 
    689         class Foo(object):
    690 
    691             @cached_property
    692             def foo(self):
    693                 # calculate something important here
    694                 return 42
    695 
    696     The class has to have a `__dict__` in order for this property to
    697     work.
    698 
    699     .. note:: Implementation detail: this property is implemented as non-data
    700        descriptor.  non-data descriptors are only invoked if there is
    701        no entry with the same name in the instance's __dict__.
    702        this allows us to completely get rid of the access function call
    703        overhead.  If one choses to invoke __get__ by hand the property
    704        will still work as expected because the lookup logic is replicated
    705        in __get__ for manual invocation.
    706 
    707     This class was ported from `Werkzeug`_ and `Flask`_.
    708     """
    709 
    710     _default_value = object()
    711 
    712     def __init__(self, func, name=None, doc=None):
    713         self.__name__ = name or func.__name__
    714         self.__module__ = func.__module__
    715         self.__doc__ = doc or func.__doc__
    716         self.func = func
    717         self.lock = threading.RLock()
    718 
    719     def __get__(self, obj, type=None):
    720         if obj is None:
    721             return self
    722 
    723         with self.lock:
    724             value = obj.__dict__.get(self.__name__, self._default_value)
    725             if value is self._default_value:
    726                 value = self.func(obj)
    727                 obj.__dict__[self.__name__] = value
    728 
    729             return value
    730 
    731 
    732 class BaseRoute(object):
    733     """Interface for URI routes."""
    734 
    735     #: The regex template.
    736     template = None
    737     #: Route name, used to build URIs.
    738     name = None
    739     #: True if this route is only used for URI generation and never matches.
    740     build_only = False
    741     #: The handler or string in dotted notation to be lazily imported.
    742     handler = None
    743     #: The custom handler method, if handler is a class.
    744     handler_method = None
    745     #: The handler, imported and ready for dispatching.
    746     handler_adapter = None
    747 
    748     def __init__(self, template, handler=None, name=None, build_only=False):
    749         """Initializes this route.
    750 
    751         :param template:
    752             A regex to be matched.
    753         :param handler:
    754             A callable or string in dotted notation to be lazily imported,
    755             e.g., ``'my.module.MyHandler'`` or ``'my.module.my_function'``.
    756         :param name:
    757             The name of this route, used to build URIs based on it.
    758         :param build_only:
    759             If True, this route never matches and is used only to build URIs.
    760         """
    761         if build_only and name is None:
    762             raise ValueError(
    763                 "Route %r is build_only but doesn't have a name." % self)
    764 
    765         self.template = template
    766         self.handler = handler
    767         self.name = name
    768         self.build_only = build_only
    769 
    770     def match(self, request):
    771         """Matches all routes against a request object.
    772 
    773         The first one that matches is returned.
    774 
    775         :param request:
    776             A :class:`Request` instance.
    777         :returns:
    778             A tuple ``(route, args, kwargs)`` if a route matched, or None.
    779         """
    780         raise NotImplementedError()
    781 
    782     def build(self, request, args, kwargs):
    783         """Returns a URI for this route.
    784 
    785         :param request:
    786             The current :class:`Request` object.
    787         :param args:
    788             Tuple of positional arguments to build the URI.
    789         :param kwargs:
    790             Dictionary of keyword arguments to build the URI.
    791         :returns:
    792             An absolute or relative URI.
    793         """
    794         raise NotImplementedError()
    795 
    796     def get_routes(self):
    797         """Generator to get all routes from a route.
    798 
    799         :yields:
    800             This route or all nested routes that it contains.
    801         """
    802         yield self
    803 
    804     def get_match_routes(self):
    805         """Generator to get all routes that can be matched from a route.
    806 
    807         Match routes must implement :meth:`match`.
    808 
    809         :yields:
    810             This route or all nested routes that can be matched.
    811         """
    812         if not self.build_only:
    813             yield self
    814 
    815     def get_build_routes(self):
    816         """Generator to get all routes that can be built from a route.
    817 
    818         Build routes must implement :meth:`build`.
    819 
    820         :yields:
    821             A tuple ``(name, route)`` for all nested routes that can be built.
    822         """
    823         if self.name is not None:
    824             yield self.name, self
    825 
    826 
    827 class SimpleRoute(BaseRoute):
    828     """A route that is compatible with webapp's routing mechanism.
    829 
    830     URI building is not implemented as webapp has rudimentar support for it,
    831     and this is the most unknown webapp feature anyway.
    832     """
    833 
    834     @cached_property
    835     def regex(self):
    836         """Lazy regex compiler."""
    837         if not self.template.startswith('^'):
    838             self.template = '^' + self.template
    839 
    840         if not self.template.endswith('$'):
    841             self.template += '$'
    842 
    843         return re.compile(self.template)
    844 
    845     def match(self, request):
    846         """Matches this route against the current request.
    847 
    848         .. seealso:: :meth:`BaseRoute.match`.
    849         """
    850         match = self.regex.match(urllib.unquote(request.path))
    851         if match:
    852             return self, match.groups(), {}
    853 
    854     def __repr__(self):
    855         return '<SimpleRoute(%r, %r)>' % (self.template, self.handler)
    856 
    857 
    858 class Route(BaseRoute):
    859     """A route definition that maps a URI path to a handler.
    860 
    861     The initial concept was based on `Another Do-It-Yourself Framework`_, by
    862     Ian Bicking.
    863     """
    864 
    865     #: Default parameters values.
    866     defaults = None
    867     #: Sequence of allowed HTTP methods. If not set, all methods are allowed.
    868     methods = None
    869     #: Sequence of allowed URI schemes. If not set, all schemes are allowed.
    870     schemes = None
    871     # Lazy properties extracted from the route template.
    872     regex = None
    873     reverse_template = None
    874     variables = None
    875     args_count = 0
    876     kwargs_count = 0
    877 
    878     def __init__(self, template, handler=None, name=None, defaults=None,
    879                  build_only=False, handler_method=None, methods=None,
    880                  schemes=None):
    881         """Initializes this route.
    882 
    883         :param template:
    884             A route template to match against the request path. A template
    885             can have variables enclosed by ``<>`` that define a name, a
    886             regular expression or both. Examples:
    887 
    888               =================  ==================================
    889               Format             Example
    890               =================  ==================================
    891               ``<name>``         ``'/blog/<year>/<month>'``
    892               ``<:regex>``       ``'/blog/<:\d{4}>/<:\d{2}>'``
    893               ``<name:regex>``   ``'/blog/<year:\d{4}>/<month:\d{2}>'``
    894               =================  ==================================
    895 
    896             The same template can mix parts with name, regular expression or
    897             both.
    898 
    899             If the name is set, the value of the matched regular expression
    900             is passed as keyword argument to the handler. Otherwise it is
    901             passed as positional argument.
    902 
    903             If only the name is set, it will match anything except a slash.
    904             So these routes are equivalent::
    905 
    906                 Route('/<user_id>/settings', handler=SettingsHandler,
    907                       name='user-settings')
    908                 Route('/<user_id:[^/]+>/settings', handler=SettingsHandler,
    909                       name='user-settings')
    910 
    911             .. note::
    912                The handler only receives ``*args`` if no named variables are
    913                set. Otherwise, the handler only receives ``**kwargs``. This
    914                allows you to set regular expressions that are not captured:
    915                just mix named and unnamed variables and the handler will
    916                only receive the named ones.
    917 
    918         :param handler:
    919             A callable or string in dotted notation to be lazily imported,
    920             e.g., ``'my.module.MyHandler'`` or ``'my.module.my_function'``.
    921             It is possible to define a method if the callable is a class,
    922             separating it by a colon: ``'my.module.MyHandler:my_method'``.
    923             This is a shortcut and has the same effect as defining the
    924             `handler_method` parameter.
    925         :param name:
    926             The name of this route, used to build URIs based on it.
    927         :param defaults:
    928             Default or extra keywords to be returned by this route. Values
    929             also present in the route variables are used to build the URI
    930             when they are missing.
    931         :param build_only:
    932             If True, this route never matches and is used only to build URIs.
    933         :param handler_method:
    934             The name of a custom handler method to be called, in case `handler`
    935             is a class. If not defined, the default behavior is to call the
    936             handler method correspondent to the HTTP request method in lower
    937             case (e.g., `get()`, `post()` etc).
    938         :param methods:
    939             A sequence of HTTP methods. If set, the route will only match if
    940             the request method is allowed.
    941         :param schemes:
    942             A sequence of URI schemes, e.g., ``['http']`` or ``['https']``.
    943             If set, the route will only match requests with these schemes.
    944         """
    945         super(Route, self).__init__(template, handler=handler, name=name,
    946                                     build_only=build_only)
    947         self.defaults = defaults or {}
    948         self.methods = methods
    949         self.schemes = schemes
    950         if isinstance(handler, basestring) and ':' in handler:
    951             if handler_method:
    952                 raise ValueError(
    953                     "If handler_method is defined in a Route, handler "
    954                     "can't have a colon (got %r)." % handler)
    955             else:
    956                 self.handler, self.handler_method = handler.rsplit(':', 1)
    957         else:
    958             self.handler_method = handler_method
    959 
    960     @cached_property
    961     def regex(self):
    962         """Lazy route template parser."""
    963         regex, self.reverse_template, self.args_count, self.kwargs_count, \
    964             self.variables = _parse_route_template(self.template,
    965                                                    default_sufix='[^/]+')
    966         return regex
    967 
    968     def match(self, request):
    969         """Matches this route against the current request.
    970 
    971         :raises:
    972             ``exc.HTTPMethodNotAllowed`` if the route defines :attr:`methods`
    973             and the request method isn't allowed.
    974 
    975         .. seealso:: :meth:`BaseRoute.match`.
    976         """
    977         match = self.regex.match(urllib.unquote(request.path))
    978         if not match or self.schemes and request.scheme not in self.schemes:
    979             return None
    980 
    981         if self.methods and request.method not in self.methods:
    982             # This will be caught by the router, so routes with different
    983             # methods can be tried.
    984             raise exc.HTTPMethodNotAllowed()
    985 
    986         args, kwargs = _get_route_variables(match, self.defaults.copy())
    987         return self, args, kwargs
    988 
    989     def build(self, request, args, kwargs):
    990         """Returns a URI for this route.
    991 
    992         .. seealso:: :meth:`Router.build`.
    993         """
    994         scheme = kwargs.pop('_scheme', None)
    995         netloc = kwargs.pop('_netloc', None)
    996         anchor = kwargs.pop('_fragment', None)
    997         full = kwargs.pop('_full', False) and not scheme and not netloc
    998 
    999         if full or scheme or netloc:
   1000             netloc = netloc or request.host
   1001             scheme = scheme or request.scheme
   1002 
   1003         path, query = self._build(args, kwargs)
   1004         return _urlunsplit(scheme, netloc, path, query, anchor)
   1005 
   1006     def _build(self, args, kwargs):
   1007         """Returns the URI path for this route.
   1008 
   1009         :returns:
   1010             A tuple ``(path, kwargs)`` with the built URI path and extra
   1011             keywords to be used as URI query arguments.
   1012         """
   1013         # Access self.regex just to set the lazy properties.
   1014         regex = self.regex
   1015         variables = self.variables
   1016         if self.args_count:
   1017             for index, value in enumerate(args):
   1018                 key = '__%d__' % index
   1019                 if key in variables:
   1020                     kwargs[key] = value
   1021 
   1022         values = {}
   1023         for name, regex in variables.iteritems():
   1024             value = kwargs.pop(name, self.defaults.get(name))
   1025             if value is None:
   1026                 raise KeyError('Missing argument "%s" to build URI.' % \
   1027                     name.strip('_'))
   1028 
   1029             if not isinstance(value, basestring):
   1030                 value = str(value)
   1031 
   1032             if not regex.match(value):
   1033                 raise ValueError('URI buiding error: Value "%s" is not '
   1034                     'supported for argument "%s".' % (value, name.strip('_')))
   1035 
   1036             values[name] = value
   1037 
   1038         return (self.reverse_template % values, kwargs)
   1039 
   1040     def __repr__(self):
   1041         return '<Route(%r, %r, name=%r, defaults=%r, build_only=%r)>' % \
   1042             (self.template, self.handler, self.name, self.defaults,
   1043             self.build_only)
   1044 
   1045 
   1046 class BaseHandlerAdapter(object):
   1047     """A basic adapter to dispatch a handler.
   1048 
   1049     This is used when the handler is a simple function: it just calls the
   1050     handler and returns the resulted response.
   1051     """
   1052 
   1053     #: The handler to be dispatched.
   1054     handler = None
   1055 
   1056     def __init__(self, handler):
   1057         self.handler = handler
   1058 
   1059     def __call__(self, request, response):
   1060         # The handler only receives *args if no named variables are set.
   1061         args, kwargs = request.route_args, request.route_kwargs
   1062         if kwargs:
   1063             args = ()
   1064 
   1065         return self.handler(request, *args, **kwargs)
   1066 
   1067 
   1068 class WebappHandlerAdapter(BaseHandlerAdapter):
   1069     """An adapter to dispatch a ``webapp.RequestHandler``.
   1070 
   1071     Like in webapp, the handler is constructed, then ``initialize()`` is
   1072     called, then the method corresponding to the HTTP request method is called.
   1073     """
   1074 
   1075     def __call__(self, request, response):
   1076         handler = self.handler()
   1077         handler.initialize(request, response)
   1078         method_name = _normalize_handler_method(request.method)
   1079         method = getattr(handler, method_name, None)
   1080         if not method:
   1081             abort(501)
   1082 
   1083         # The handler only receives *args if no named variables are set.
   1084         args, kwargs = request.route_args, request.route_kwargs
   1085         if kwargs:
   1086             args = ()
   1087 
   1088         try:
   1089             method(*args, **kwargs)
   1090         except Exception, e:
   1091             handler.handle_exception(e, request.app.debug)
   1092 
   1093 
   1094 class Webapp2HandlerAdapter(BaseHandlerAdapter):
   1095     """An adapter to dispatch a ``webapp2.RequestHandler``.
   1096 
   1097     The handler is constructed then ``dispatch()`` is called.
   1098     """
   1099 
   1100     def __call__(self, request, response):
   1101         handler = self.handler(request, response)
   1102         return handler.dispatch()
   1103 
   1104 
   1105 class Router(object):
   1106     """A URI router used to match, dispatch and build URIs."""
   1107 
   1108     #: Class used when the route is set as a tuple.
   1109     route_class = SimpleRoute
   1110     #: All routes that can be matched.
   1111     match_routes = None
   1112     #: All routes that can be built.
   1113     build_routes = None
   1114     #: Handler classes imported lazily.
   1115     handlers = None
   1116 
   1117     def __init__(self, routes=None):
   1118         """Initializes the router.
   1119 
   1120         :param routes:
   1121             A sequence of :class:`Route` instances or, for simple routes,
   1122             tuples ``(regex, handler)``.
   1123         """
   1124         self.match_routes = []
   1125         self.build_routes = {}
   1126         self.handlers = {}
   1127         if routes:
   1128             for route in routes:
   1129                 self.add(route)
   1130 
   1131     def add(self, route):
   1132         """Adds a route to this router.
   1133 
   1134         :param route:
   1135             A :class:`Route` instance or, for simple routes, a tuple
   1136             ``(regex, handler)``.
   1137         """
   1138         if isinstance(route, tuple):
   1139             # Exceptional case: simple routes defined as a tuple.
   1140             route = self.route_class(*route)
   1141 
   1142         for r in route.get_match_routes():
   1143             self.match_routes.append(r)
   1144 
   1145         for name, r in route.get_build_routes():
   1146             self.build_routes[name] = r
   1147 
   1148     def set_matcher(self, func):
   1149         """Sets the function called to match URIs.
   1150 
   1151         :param func:
   1152             A function that receives ``(router, request)`` and returns
   1153             a tuple ``(route, args, kwargs)`` if any route matches, or
   1154             raise ``exc.HTTPNotFound`` if no route matched or
   1155             ``exc.HTTPMethodNotAllowed`` if a route matched but the HTTP
   1156             method was not allowed.
   1157         """
   1158         # Functions are descriptors, so bind it to this instance with __get__.
   1159         self.match = func.__get__(self, self.__class__)
   1160 
   1161     def set_builder(self, func):
   1162         """Sets the function called to build URIs.
   1163 
   1164         :param func:
   1165             A function that receives ``(router, request, name, args, kwargs)``
   1166             and returns a URI.
   1167         """
   1168         self.build = func.__get__(self, self.__class__)
   1169 
   1170     def set_dispatcher(self, func):
   1171         """Sets the function called to dispatch the handler.
   1172 
   1173         :param func:
   1174             A function that receives ``(router, request, response)``
   1175             and returns the value returned by the dispatched handler.
   1176         """
   1177         self.dispatch = func.__get__(self, self.__class__)
   1178 
   1179     def set_adapter(self, func):
   1180         """Sets the function that adapts loaded handlers for dispatching.
   1181 
   1182         :param func:
   1183             A function that receives ``(router, handler)`` and returns a
   1184             handler callable.
   1185         """
   1186         self.adapt = func.__get__(self, self.__class__)
   1187 
   1188     def default_matcher(self, request):
   1189         """Matches all routes against a request object.
   1190 
   1191         The first one that matches is returned.
   1192 
   1193         :param request:
   1194             A :class:`Request` instance.
   1195         :returns:
   1196             A tuple ``(route, args, kwargs)`` if a route matched, or None.
   1197         :raises:
   1198             ``exc.HTTPNotFound`` if no route matched or
   1199             ``exc.HTTPMethodNotAllowed`` if a route matched but the HTTP
   1200             method was not allowed.
   1201         """
   1202         method_not_allowed = False
   1203         for route in self.match_routes:
   1204             try:
   1205                 match = route.match(request)
   1206                 if match:
   1207                     return match
   1208             except exc.HTTPMethodNotAllowed:
   1209                 method_not_allowed = True
   1210 
   1211         if method_not_allowed:
   1212             raise exc.HTTPMethodNotAllowed()
   1213 
   1214         raise exc.HTTPNotFound()
   1215 
   1216     def default_builder(self, request, name, args, kwargs):
   1217         """Returns a URI for a named :class:`Route`.
   1218 
   1219         :param request:
   1220             The current :class:`Request` object.
   1221         :param name:
   1222             The route name.
   1223         :param args:
   1224             Tuple of positional arguments to build the URI. All positional
   1225             variables defined in the route must be passed and must conform
   1226             to the format set in the route. Extra arguments are ignored.
   1227         :param kwargs:
   1228             Dictionary of keyword arguments to build the URI. All variables
   1229             not set in the route default values must be passed and must
   1230             conform to the format set in the route. Extra keywords are
   1231             appended as a query string.
   1232 
   1233             A few keywords have special meaning:
   1234 
   1235             - **_full**: If True, builds an absolute URI.
   1236             - **_scheme**: URI scheme, e.g., `http` or `https`. If defined,
   1237               an absolute URI is always returned.
   1238             - **_netloc**: Network location, e.g., `www.google.com`. If
   1239               defined, an absolute URI is always returned.
   1240             - **_fragment**: If set, appends a fragment (or "anchor") to the
   1241               generated URI.
   1242         :returns:
   1243             An absolute or relative URI.
   1244         """
   1245         route = self.build_routes.get(name)
   1246         if route is None:
   1247             raise KeyError('Route named %r is not defined.' % name)
   1248 
   1249         return route.build(request, args, kwargs)
   1250 
   1251     def default_dispatcher(self, request, response):
   1252         """Dispatches a handler.
   1253 
   1254         :param request:
   1255             A :class:`Request` instance.
   1256         :param response:
   1257             A :class:`Response` instance.
   1258         :raises:
   1259             ``exc.HTTPNotFound`` if no route matched or
   1260             ``exc.HTTPMethodNotAllowed`` if a route matched but the HTTP
   1261             method was not allowed.
   1262         :returns:
   1263             The returned value from the handler.
   1264         """
   1265         route, args, kwargs = rv = self.match(request)
   1266         request.route, request.route_args, request.route_kwargs = rv
   1267 
   1268         if route.handler_adapter is None:
   1269             handler = route.handler
   1270             if isinstance(handler, basestring):
   1271                 if handler not in self.handlers:
   1272                     self.handlers[handler] = handler = import_string(handler)
   1273                 else:
   1274                     handler = self.handlers[handler]
   1275 
   1276             route.handler_adapter = self.adapt(handler)
   1277 
   1278         return route.handler_adapter(request, response)
   1279 
   1280     def default_adapter(self, handler):
   1281         """Adapts a handler for dispatching.
   1282 
   1283         Because handlers use or implement different dispatching mechanisms,
   1284         they can be wrapped to use a unified API for dispatching.
   1285         This way webapp2 can support, for example, a :class:`RequestHandler`
   1286         class and function views or, for compatibility purposes, a
   1287         ``webapp.RequestHandler`` class. The adapters follow the same router
   1288         dispatching API but dispatch each handler type differently.
   1289 
   1290         :param handler:
   1291             A handler callable.
   1292         :returns:
   1293             A wrapped handler callable.
   1294         """
   1295         if inspect.isclass(handler):
   1296             if _webapp and issubclass(handler, _webapp.RequestHandler):
   1297                 # Compatible with webapp.RequestHandler.
   1298                 adapter = WebappHandlerAdapter
   1299             else:
   1300                 # Default, compatible with webapp2.RequestHandler.
   1301                 adapter = Webapp2HandlerAdapter
   1302         else:
   1303             # A "view" function.
   1304             adapter = BaseHandlerAdapter
   1305 
   1306         return adapter(handler)
   1307 
   1308     def __repr__(self):
   1309         routes = self.match_routes + [v for k, v in \
   1310             self.build_routes.iteritems() if v not in self.match_routes]
   1311 
   1312         return '<Router(%r)>' % routes
   1313 
   1314     # Default matcher, builder, dispatcher and adapter.
   1315     match = default_matcher
   1316     build = default_builder
   1317     dispatch = default_dispatcher
   1318     adapt = default_adapter
   1319 
   1320 
   1321 class Config(dict):
   1322     """A simple configuration dictionary for the :class:`WSGIApplication`."""
   1323 
   1324     #: Loaded configurations.
   1325     loaded = None
   1326 
   1327     def __init__(self, defaults=None):
   1328         dict.__init__(self, defaults or ())
   1329         self.loaded = []
   1330 
   1331     def load_config(self, key, default_values=None, user_values=None,
   1332                     required_keys=None):
   1333         """Returns a configuration for a given key.
   1334 
   1335         This can be used by objects that define a default configuration. It
   1336         will update the app configuration with the default values the first
   1337         time it is requested, and mark the key as loaded.
   1338 
   1339         :param key:
   1340             A configuration key.
   1341         :param default_values:
   1342             Default values defined by a module or class.
   1343         :param user_values:
   1344             User values, used when an object can be initialized with
   1345             configuration. This overrides the app configuration.
   1346         :param required_keys:
   1347             Keys that can not be None.
   1348         :raises:
   1349             Exception, when a required key is not set or is None.
   1350         """
   1351         if key in self.loaded:
   1352             config = self[key]
   1353         else:
   1354             config = dict(default_values or ())
   1355             if key in self:
   1356                 config.update(self[key])
   1357 
   1358             self[key] = config
   1359             self.loaded.append(key)
   1360             if required_keys and not user_values:
   1361                 self._validate_required(key, config, required_keys)
   1362 
   1363         if user_values:
   1364             config = config.copy()
   1365             config.update(user_values)
   1366             if required_keys:
   1367                 self._validate_required(key, config, required_keys)
   1368 
   1369         return config
   1370 
   1371     def _validate_required(self, key, config, required_keys):
   1372         missing = [k for k in required_keys if config.get(k) is None]
   1373         if missing:
   1374             raise Exception(
   1375                 'Missing configuration keys for %r: %r.' % (key, missing))
   1376 
   1377 
   1378 class RequestContext(object):
   1379     """Context for a single request.
   1380 
   1381     The context is responsible for setting and cleaning global variables for
   1382     a request.
   1383     """
   1384 
   1385     #: A :class:`WSGIApplication` instance.
   1386     app = None
   1387     #: WSGI environment dictionary.
   1388     environ = None
   1389 
   1390     def __init__(self, app, environ):
   1391         """Initializes the request context.
   1392 
   1393         :param app:
   1394             An :class:`WSGIApplication` instance.
   1395         :param environ:
   1396             A WSGI environment dictionary.
   1397         """
   1398         self.app = app
   1399         self.environ = environ
   1400 
   1401     def __enter__(self):
   1402         """Enters the request context.
   1403 
   1404         :returns:
   1405             A tuple ``(request, response)``.
   1406         """
   1407         # Build request and response.
   1408         request = self.app.request_class(self.environ)
   1409         response = self.app.response_class()
   1410         # Make active app and response available through the request object.
   1411         request.app = self.app
   1412         request.response = response
   1413         # Register global variables.
   1414         self.app.set_globals(app=self.app, request=request)
   1415         return request, response
   1416 
   1417     def __exit__(self, exc_type, exc_value, traceback):
   1418         """Exits the request context.
   1419 
   1420         This release the context locals except if an exception is caught
   1421         in debug mode. In this case they are kept to be inspected.
   1422         """
   1423         if exc_type is None or not self.app.debug:
   1424             # Unregister global variables.
   1425             self.app.clear_globals()
   1426 
   1427 
   1428 class WSGIApplication(object):
   1429     """A WSGI-compliant application."""
   1430 
   1431     #: Allowed request methods.
   1432     allowed_methods = frozenset(('GET', 'POST', 'HEAD', 'OPTIONS', 'PUT',
   1433                                  'DELETE', 'TRACE'))
   1434     #: Class used for the request object.
   1435     request_class = Request
   1436     #: Class used for the response object.
   1437     response_class = Response
   1438     #: Class used for the router object.
   1439     router_class = Router
   1440     #: Class used for the request context object.
   1441     request_context_class = RequestContext
   1442     #: Class used for the configuration object.
   1443     config_class = Config
   1444     #: A general purpose flag to indicate development mode: if True, uncaught
   1445     #: exceptions are raised instead of using ``HTTPInternalServerError``.
   1446     debug = False
   1447     #: A :class:`Router` instance with all URIs registered for the application.
   1448     router = None
   1449     #: A :class:`Config` instance with the application configuration.
   1450     config = None
   1451     #: A dictionary to register objects used during the app lifetime.
   1452     registry = None
   1453     #: A dictionary mapping HTTP error codes to callables to handle those
   1454     #: HTTP exceptions. See :meth:`handle_exception`.
   1455     error_handlers = None
   1456     #: Active :class:`WSGIApplication` instance. See :meth:`set_globals`.
   1457     app = None
   1458     #: Active :class:`Request` instance. See :meth:`set_globals`.
   1459     request = None
   1460     #: Same as :attr:`app`, for webapp compatibility. See :meth:`set_globals`.
   1461     active_instance = None
   1462 
   1463     def __init__(self, routes=None, debug=False, config=None):
   1464         """Initializes the WSGI application.
   1465 
   1466         :param routes:
   1467             A sequence of :class:`Route` instances or, for simple routes,
   1468             tuples ``(regex, handler)``.
   1469         :param debug:
   1470             True to enable debug mode, False otherwise.
   1471         :param config:
   1472             A configuration dictionary for the application.
   1473         """
   1474         self.debug = debug
   1475         self.registry = {}
   1476         self.error_handlers = {}
   1477         self.set_globals(app=self)
   1478         self.config = self.config_class(config)
   1479         self.router = self.router_class(routes)
   1480 
   1481     def set_globals(self, app=None, request=None):
   1482         """Registers the global variables for app and request.
   1483 
   1484         If :mod:`webapp2_extras.local` is available the app and request
   1485         class attributes are assigned to a proxy object that returns them
   1486         using thread-local, making the application thread-safe. This can also
   1487         be used in environments that don't support threading.
   1488 
   1489         If :mod:`webapp2_extras.local` is not available app and request will
   1490         be assigned directly as class attributes. This should only be used in
   1491         non-threaded environments (e.g., App Engine Python 2.5).
   1492 
   1493         :param app:
   1494             A :class:`WSGIApplication` instance.
   1495         :param request:
   1496             A :class:`Request` instance.
   1497         """
   1498         if _local is not None: # pragma: no cover
   1499             _local.app = app
   1500             _local.request = request
   1501         else: # pragma: no cover
   1502             WSGIApplication.app = WSGIApplication.active_instance = app
   1503             WSGIApplication.request = request
   1504 
   1505     def clear_globals(self):
   1506         """Clears global variables. See :meth:`set_globals`."""
   1507         if _local is not None: # pragma: no cover
   1508             _local.__release_local__()
   1509         else: # pragma: no cover
   1510             WSGIApplication.app = WSGIApplication.active_instance = None
   1511             WSGIApplication.request = None
   1512 
   1513     def __call__(self, environ, start_response):
   1514         """Called by WSGI when a request comes in.
   1515 
   1516         :param environ:
   1517             A WSGI environment.
   1518         :param start_response:
   1519             A callable accepting a status code, a list of headers and an
   1520             optional exception context to start the response.
   1521         :returns:
   1522             An iterable with the response to return to the client.
   1523         """
   1524         with self.request_context_class(self, environ) as (request, response):
   1525             try:
   1526                 if request.method not in self.allowed_methods:
   1527                     # 501 Not Implemented.
   1528                     raise exc.HTTPNotImplemented()
   1529 
   1530                 rv = self.router.dispatch(request, response)
   1531                 if rv is not None:
   1532                     response = rv
   1533             except Exception, e:
   1534                 try:
   1535                     # Try to handle it with a custom error handler.
   1536                     rv = self.handle_exception(request, response, e)
   1537                     if rv is not None:
   1538                         response = rv
   1539                 except HTTPException, e:
   1540                     # Use the HTTP exception as response.
   1541                     response = e
   1542                 except Exception, e:
   1543                     # Error wasn't handled so we have nothing else to do.
   1544                     response = self._internal_error(e)
   1545 
   1546             try:
   1547                 return response(environ, start_response)
   1548             except Exception, e:
   1549                 return self._internal_error(e)(environ, start_response)
   1550 
   1551     def _internal_error(self, exception):
   1552         """Last resource error for :meth:`__call__`."""
   1553         logging.exception(exception)
   1554         if self.debug:
   1555             lines = ''.join(traceback.format_exception(*sys.exc_info()))
   1556             html = _debug_template % (cgi.escape(lines, quote=True))
   1557             return Response(body=html, status=500)
   1558 
   1559         return exc.HTTPInternalServerError()
   1560 
   1561     def handle_exception(self, request, response, e):
   1562         """Handles a uncaught exception occurred in :meth:`__call__`.
   1563 
   1564         Uncaught exceptions can be handled by error handlers registered in
   1565         :attr:`error_handlers`. This is a dictionary that maps HTTP status
   1566         codes to callables that will handle the corresponding error code.
   1567         If the exception is not an ``HTTPException``, the status code 500
   1568         is used.
   1569 
   1570         The error handlers receive (request, response, exception) and can be
   1571         a callable or a string in dotted notation to be lazily imported.
   1572 
   1573         If no error handler is found, the exception is re-raised.
   1574 
   1575         Based on idea from `Flask`_.
   1576 
   1577         :param request:
   1578             A :class:`Request` instance.
   1579         :param response:
   1580             A :class:`Response` instance.
   1581         :param e:
   1582             The uncaught exception.
   1583         :returns:
   1584             The returned value from the error handler.
   1585         """
   1586         if isinstance(e, HTTPException):
   1587             code = e.code
   1588         else:
   1589             code = 500
   1590 
   1591         handler = self.error_handlers.get(code)
   1592         if handler:
   1593             if isinstance(handler, basestring):
   1594                 self.error_handlers[code] = handler = import_string(handler)
   1595 
   1596             return handler(request, response, e)
   1597         else:
   1598             # Re-raise it to be caught by the WSGI app.
   1599             raise
   1600 
   1601     def run(self, bare=False):
   1602         """Runs this WSGI-compliant application in a CGI environment.
   1603 
   1604         This uses functions provided by ``google.appengine.ext.webapp.util``,
   1605         if available: ``run_bare_wsgi_app`` and ``run_wsgi_app``.
   1606 
   1607         Otherwise, it uses ``wsgiref.handlers.CGIHandler().run()``.
   1608 
   1609         :param bare:
   1610             If True, doesn't add registered WSGI middleware: use
   1611             ``run_bare_wsgi_app`` instead of ``run_wsgi_app``.
   1612         """
   1613         if _webapp_util:
   1614             if bare:
   1615                 _webapp_util.run_bare_wsgi_app(self)
   1616             else:
   1617                 _webapp_util.run_wsgi_app(self)
   1618         else: # pragma: no cover
   1619             handlers.CGIHandler().run(self)
   1620 
   1621     def get_response(self, *args, **kwargs):
   1622         """Creates a request and returns a response for this app.
   1623 
   1624         This is a convenience for unit testing purposes. It receives
   1625         parameters to build a request and calls the application, returning
   1626         the resulting response::
   1627 
   1628             class HelloHandler(webapp2.RequestHandler):
   1629                 def get(self):
   1630                     self.response.write('Hello, world!')
   1631 
   1632             app = webapp2.WSGIapplication([('/', HelloHandler)])
   1633 
   1634             # Test the app, passing parameters to build a request.
   1635             response = app.get_response('/')
   1636             assert response.status_int == 200
   1637             assert response.body == 'Hello, world!'
   1638 
   1639         :param args:
   1640             Positional arguments to be passed to ``Request.blank()``.
   1641         :param kwargs:
   1642             Keyword arguments to be passed to ``Request.blank()``.
   1643         :returns:
   1644             A :class:`Response` object.
   1645         """
   1646         return self.request_class.blank(*args, **kwargs).get_response(self)
   1647 
   1648 
   1649 _import_string_error = """\
   1650 import_string() failed for %r. Possible reasons are:
   1651 
   1652 - missing __init__.py in a package;
   1653 - package or module path not included in sys.path;
   1654 - duplicated package or module name taking precedence in sys.path;
   1655 - missing module, class, function or variable;
   1656 
   1657 Original exception:
   1658 
   1659 %s: %s
   1660 
   1661 Debugged import:
   1662 
   1663 %s"""
   1664 
   1665 
   1666 class ImportStringError(Exception):
   1667     """Provides information about a failed :func:`import_string` attempt."""
   1668 
   1669     #: String in dotted notation that failed to be imported.
   1670     import_name = None
   1671     #: Wrapped exception.
   1672     exception = None
   1673 
   1674     def __init__(self, import_name, exception):
   1675         self.import_name = import_name
   1676         self.exception = exception
   1677         msg = _import_string_error
   1678         name = ''
   1679         tracked = []
   1680         for part in import_name.split('.'):
   1681             name += (name and '.') + part
   1682             imported = import_string(name, silent=True)
   1683             if imported:
   1684                 tracked.append((name, imported.__file__))
   1685             else:
   1686                 track = ['- %r found in %r.' % rv for rv in tracked]
   1687                 track.append('- %r not found.' % name)
   1688                 msg = msg % (import_name, exception.__class__.__name__,
   1689                              str(exception), '\n'.join(track))
   1690                 break
   1691 
   1692         Exception.__init__(self, msg)
   1693 
   1694 
   1695 _get_app_error = 'WSGIApplication global variable is not set.'
   1696 _get_request_error = 'Request global variable is not set.'
   1697 
   1698 
   1699 def get_app():
   1700     """Returns the active app instance.
   1701 
   1702     :returns:
   1703         A :class:`WSGIApplication` instance.
   1704     """
   1705     if _local:
   1706         assert getattr(_local, 'app', None) is not None, _get_app_error
   1707     else:
   1708         assert WSGIApplication.app is not None, _get_app_error
   1709 
   1710     return WSGIApplication.app
   1711 
   1712 
   1713 def get_request():
   1714     """Returns the active request instance.
   1715 
   1716     :returns:
   1717         A :class:`Request` instance.
   1718     """
   1719     if _local:
   1720         assert getattr(_local, 'request', None) is not None, _get_request_error
   1721     else:
   1722         assert WSGIApplication.request is not None, _get_request_error
   1723 
   1724     return WSGIApplication.request
   1725 
   1726 
   1727 def uri_for(_name, _request=None, *args, **kwargs):
   1728     """A standalone uri_for version that can be passed to templates.
   1729 
   1730     .. seealso:: :meth:`Router.build`.
   1731     """
   1732     request = _request or get_request()
   1733     return request.app.router.build(request, _name, args, kwargs)
   1734 
   1735 
   1736 def redirect(uri, permanent=False, abort=False, code=None, body=None,
   1737              request=None, response=None):
   1738     """Issues an HTTP redirect to the given relative URI.
   1739 
   1740     This won't stop code execution unless **abort** is True. A common
   1741     practice is to return when calling this method::
   1742 
   1743         return redirect('/some-path')
   1744 
   1745     :param uri:
   1746         A relative or absolute URI (e.g., ``'../flowers.html'``).
   1747     :param permanent:
   1748         If True, uses a 301 redirect instead of a 302 redirect.
   1749     :param abort:
   1750         If True, raises an exception to perform the redirect.
   1751     :param code:
   1752         The redirect status code. Supported codes are 301, 302, 303, 305,
   1753         and 307.  300 is not supported because it's not a real redirect
   1754         and 304 because it's the answer for a request with defined
   1755         ``If-Modified-Since`` headers.
   1756     :param body:
   1757         Response body, if any.
   1758     :param request:
   1759         Optional request object. If not set, uses :func:`get_request`.
   1760     :param response:
   1761         Optional response object. If not set, a new response is created.
   1762     :returns:
   1763         A :class:`Response` instance.
   1764     """
   1765     if uri.startswith(('.', '/')):
   1766         request = request or get_request()
   1767         uri = str(urlparse.urljoin(request.url, uri))
   1768 
   1769     if code is None:
   1770         if permanent:
   1771             code = 301
   1772         else:
   1773             code = 302
   1774 
   1775     assert code in (301, 302, 303, 305, 307), \
   1776         'Invalid redirect status code.'
   1777 
   1778     if abort:
   1779         _abort(code, headers=[('Location', uri)])
   1780 
   1781     if response is None:
   1782         request = request or get_request()
   1783         response = request.app.response_class()
   1784     else:
   1785         response.clear()
   1786 
   1787     response.headers['Location'] = uri
   1788     response.status = code
   1789     if body is not None:
   1790         response.write(body)
   1791 
   1792     return response
   1793 
   1794 
   1795 def redirect_to(_name, _permanent=False, _abort=False, _code=None,
   1796                 _body=None, _request=None, _response=None, *args, **kwargs):
   1797     """Convenience function mixing :func:`redirect` and :func:`uri_for`.
   1798 
   1799     Issues an HTTP redirect to a named URI built using :func:`uri_for`.
   1800 
   1801     :param _name:
   1802         The route name to redirect to.
   1803     :param args:
   1804         Positional arguments to build the URI.
   1805     :param kwargs:
   1806         Keyword arguments to build the URI.
   1807     :returns:
   1808         A :class:`Response` instance.
   1809 
   1810     The other arguments are described in :func:`redirect`.
   1811     """
   1812     uri = uri_for(_name, _request=_request, *args, **kwargs)
   1813     return redirect(uri, permanent=_permanent, abort=_abort, code=_code,
   1814                     body=_body, request=_request, response=_response)
   1815 
   1816 
   1817 def abort(code, *args, **kwargs):
   1818     """Raises an ``HTTPException``.
   1819 
   1820     :param code:
   1821         An integer that represents a valid HTTP status code.
   1822     :param args:
   1823         Positional arguments to instantiate the exception.
   1824     :param kwargs:
   1825         Keyword arguments to instantiate the exception.
   1826     """
   1827     cls = exc.status_map.get(code)
   1828     if not cls:
   1829         raise KeyError('No exception is defined for code %r.' % code)
   1830 
   1831     raise cls(*args, **kwargs)
   1832 
   1833 
   1834 def import_string(import_name, silent=False):
   1835     """Imports an object based on a string in dotted notation.
   1836 
   1837     Simplified version of the function with same name from `Werkzeug`_.
   1838 
   1839     :param import_name:
   1840         String in dotted notation of the object to be imported.
   1841     :param silent:
   1842         If True, import or attribute errors are ignored and None is returned
   1843         instead of raising an exception.
   1844     :returns:
   1845         The imported object.
   1846     """
   1847     import_name = _to_utf8(import_name)
   1848     try:
   1849         if '.' in import_name:
   1850             module, obj = import_name.rsplit('.', 1)
   1851             return getattr(__import__(module, None, None, [obj]), obj)
   1852         else:
   1853             return __import__(import_name)
   1854     except (ImportError, AttributeError), e:
   1855         if not silent:
   1856             raise ImportStringError(import_name, e), None, sys.exc_info()[2]
   1857 
   1858 
   1859 def _urlunsplit(scheme=None, netloc=None, path=None, query=None,
   1860                 fragment=None):
   1861     """Like ``urlparse.urlunsplit``, but will escape values and urlencode and
   1862     sort query arguments.
   1863 
   1864     :param scheme:
   1865         URI scheme, e.g., `http` or `https`.
   1866     :param netloc:
   1867         Network location, e.g., `localhost:8080` or `www.google.com`.
   1868     :param path:
   1869         URI path.
   1870     :param query:
   1871         URI query as an escaped string, or a dictionary or list of key-values
   1872         tuples to build a query.
   1873     :param fragment:
   1874         Fragment identifier, also known as "anchor".
   1875     :returns:
   1876         An assembled absolute or relative URI.
   1877     """
   1878     if not scheme or not netloc:
   1879         scheme = None
   1880         netloc = None
   1881 
   1882     if path:
   1883         path = urllib.quote(_to_utf8(path))
   1884 
   1885     if query and not isinstance(query, basestring):
   1886         if isinstance(query, dict):
   1887             query = query.iteritems()
   1888 
   1889         # Sort args: commonly needed to build signatures for services.
   1890         query = urllib.urlencode(sorted(query))
   1891 
   1892     if fragment:
   1893         fragment = urllib.quote(_to_utf8(fragment))
   1894 
   1895     return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
   1896 
   1897 
   1898 def _get_handler_methods(handler):
   1899     """Returns a list of HTTP methods supported by a handler.
   1900 
   1901     :param handler:
   1902         A :class:`RequestHandler` instance.
   1903     :returns:
   1904         A list of HTTP methods supported by the handler.
   1905     """
   1906     methods = []
   1907     for method in get_app().allowed_methods:
   1908         if getattr(handler, _normalize_handler_method(method), None):
   1909             methods.append(method)
   1910 
   1911     return methods
   1912 
   1913 
   1914 def _normalize_handler_method(method):
   1915     """Transforms an HTTP method into a valid Python identifier."""
   1916     return method.lower().replace('-', '_')
   1917 
   1918 
   1919 def _to_utf8(value):
   1920     """Encodes a unicode value to UTF-8 if not yet encoded."""
   1921     if isinstance(value, str):
   1922         return value
   1923 
   1924     return value.encode('utf-8')
   1925 
   1926 
   1927 def _parse_route_template(template, default_sufix=''):
   1928     """Lazy route template parser."""
   1929     variables = {}
   1930     reverse_template = pattern = ''
   1931     args_count = last = 0
   1932     for match in _route_re.finditer(template):
   1933         part = template[last:match.start()]
   1934         name = match.group(1)
   1935         expr = match.group(2) or default_sufix
   1936         last = match.end()
   1937 
   1938         if not name:
   1939             name = '__%d__' % args_count
   1940             args_count += 1
   1941 
   1942         pattern += '%s(?P<%s>%s)' % (re.escape(part), name, expr)
   1943         reverse_template += '%s%%(%s)s' % (part, name)
   1944         variables[name] = re.compile('^%s$' % expr)
   1945 
   1946     part = template[last:]
   1947     kwargs_count = len(variables) - args_count
   1948     reverse_template += part
   1949     regex = re.compile('^%s%s$' % (pattern, re.escape(part)))
   1950     return regex, reverse_template, args_count, kwargs_count, variables
   1951 
   1952 
   1953 def _get_route_variables(match, default_kwargs=None):
   1954     """Returns (args, kwargs) for a route match."""
   1955     kwargs = default_kwargs or {}
   1956     kwargs.update(match.groupdict())
   1957     if kwargs:
   1958         args = tuple(value[1] for value in sorted(
   1959             (int(key[2:-2]), kwargs.pop(key)) for key in kwargs.keys() \
   1960             if key.startswith('__') and key.endswith('__')))
   1961     else:
   1962         args = ()
   1963 
   1964     return args, kwargs
   1965 
   1966 
   1967 def _set_thread_safe_app():
   1968     """Assigns WSGIApplication globals to a proxy pointing to thread-local."""
   1969     if _local is not None: # pragma: no cover
   1970         WSGIApplication.app = WSGIApplication.active_instance = _local('app')
   1971         WSGIApplication.request = _local('request')
   1972 
   1973 
   1974 Request.ResponseClass = Response
   1975 Response.RequestClass = Request
   1976 # Alias.
   1977 _abort = abort
   1978 # Thread-safety support.
   1979 _set_thread_safe_app()
   1980 
   1981 # Defer importing google.appengine.ext.webapp.util until every public symbol
   1982 # has been defined since google.appengine.ext.webapp in App Engine Python 2.7
   1983 # runtime imports this module to provide its public interface.
   1984 try:
   1985     from google.appengine.ext.webapp import util as _webapp_util
   1986 except ImportError: # pragma: no cover
   1987     pass
   1988