'''Module milla.app Please give me a docstring! :Created: Mar 26, 2011 :Author: dustin :Updated: $Date$ :Updater: $Author$ ''' from milla.controllers import FaviconController from webob.exc import HTTPNotFound, WSGIHTTPException import milla.dispatch import webob __all__ = ['Application'] class Application(object): '''Represents a Milla web application Constructing an ``Application`` instance needs a dispatcher, or alternatively, a root object that will be passed to a new :py:class:``milla.dispatch.traversal.Traverser`. :param root: A root object, passed to a traverser, which is automatically created if a root is given :param dispatcher: An object implementing the dispatcher protocol ``Application`` instances are WSGI applications. .. py:attribute:: config A mapping of configuration settings. For each request, the configuration is copied and assigned to ``request.config``. ''' def __init__(self, dispatcher): self.dispatcher = dispatcher self.config = {'milla.favicon': True} def __call__(self, environ, start_response): path_info = environ['PATH_INFO'] try: func = self.dispatcher.resolve(path_info) except milla.dispatch.UnresolvedPath: def asbool(val): if not val: return False try: val = val.lower() except AttributeError: pass if val in ('false', 'no', 'f', 'n', 'off'): return False return True if asbool(self.config.get('milla.favicon')) and \ path_info == '/favicon.ico': func = FaviconController() else: return HTTPNotFound()(environ, start_response) request = webob.Request(environ) request.config = self.config.copy() start_response_wrapper = StartResponseWrapper(start_response) request.start_response = start_response_wrapper try: # If the callable has an __before__ attribute, call it if hasattr(func, '__before__'): func.__before__(request) # If the callable is an instance method and its class has # a __before__ method, call that elif hasattr(func, 'im_self') and \ hasattr(func.im_self, '__before__'): func.im_self.__before__(request) # The callable might be a partial, so check the inner func elif hasattr(func, 'func'): if hasattr(func.func, '__before__'): func.func.__before__(request) elif hasattr(func.func, 'im_self') and \ hasattr(func.func.im_self, '__before__'): func.func.im_self.__before__(request) response = func(request) except WSGIHTTPException as e: return e(environ, start_response) finally: # If the callable has an __after__ method, call it if hasattr(func, '__after__'): func.__after__(request) # If the callable is an instance method and its class has # an __after__ method, call that elif hasattr(func, 'im_self') and \ hasattr(func.im_self, '__after__'): func.im_self.__after__(request) # The callable might be a partial, so check the inner func elif hasattr(func, 'func'): if hasattr(func.func, '__after__'): func.func.__after__(request) elif hasattr(func.func, 'im_self') and \ hasattr(func.func.im_self, '__after__'): func.func.im_self.__after__(request) # The callable might have returned just a string, which is OK, # but we need to wrap it in a WebOb response if isinstance(response, basestring) or not response: response = webob.Response(response) if not start_response_wrapper.called: start_response(response.status, response.headerlist) return response.app_iter class StartResponseWrapper(): def __init__(self, start_response): self.start_response = start_response self.called = False def __call__(self, *args, **kwargs): self.called = True return self.start_response(*args, **kwargs)