Source code for weblayer.wsgi
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" :py:mod:`weblayer.wsgi` provides :py:class:`WSGIApplication`, an
implementation of :py:class:`~weblayer.interfaces.IWSGIApplication` that
adapts :py:class:`~weblayer.interfaces.ISettings` and an
:py:class:`~weblayer.interfaces.IPathRouter`::
>>> settings = {}
>>> path_router = object()
To provide a callable `WSGI`_ application::
>>> application = WSGIApplication(settings, path_router)
.. _`WSGI`: http://www.python.org/dev/peps/pep-0333/
"""
__all__ = [
'WSGIApplication'
]
from zope.component import adapts
from zope.interface import implements
from base import Request, Response
from interfaces import IPathRouter, ISettings, IWSGIApplication
[docs]class WSGIApplication(object):
adapts(ISettings, IPathRouter)
implements(IWSGIApplication)
def __init__(
self,
settings,
path_router,
request_class=None,
response_class=None,
default_content_type='text/html; charset=UTF-8'
):
"""
"""
self._settings = settings
self._path_router = path_router
if request_class is None:
self._Request = Request
else:
self._Request = request_class
if response_class is None:
self._Response = Response
else:
self._Response = response_class
self._content_type = default_content_type
[docs] def __call__(self, environ, start_response):
""" Checks ``self._path_router`` for a
:py:meth:`~weblayer.interfaces.IPathRouter.match` against the
incoming :py:attr:`~weblayer.interfaces.IRequest.path`::
handler_class, args, kwargs = self._path_router.match(request.path)
If ``handler_class`` is not ``None``, instantiates the
:py:class:`~weblayer.interfaces.IRequestHandler`::
handler = handler_class(request, response, self._settings)
And calls it with ``environ['REQUEST_METHOD']`` and the ``args`` and
``kwargs`` from :py:meth:`~weblayer.interfaces.IPathRouter.match`::
response = handler(environ['REQUEST_METHOD'], *args, **kwargs)
.. note::
If calling the handler errors (which is shouldn't normally do, as
the handler *should* catch the error), returns a minimalist 500
response.
.. note::
If no match is found, returns a minimalist 404 response. To handle
404 responses more elegantly, define a catch all URL handler.
"""
request = self._Request(environ)
response = self._Response(
request=request,
status=200,
content_type=self._content_type
)
handler_class, args, kwargs = self._path_router.match(request.path)
if handler_class is not None:
handler = handler_class(request, response, self._settings)
try: # handler *should* catch all exceptions
response = handler(environ['REQUEST_METHOD'], *args, **kwargs)
except Exception: # unless deliberately bubbling them up
if environ.get('paste.throw_errors', False):
raise
else:
response.status = 500
else: # to handle 404 nicely, define a catch all url handler
response.status = 404
return response(environ, start_response)