Support for `__before__` and `__after__` method calls for controllers
For convenience, a `Controller` class now exists from which all classes wanting to implement these methods should descend. This will allow sane cooperative multiple inheritance.master
parent
02bc0ea404
commit
9b30000a36
|
@ -7,10 +7,12 @@ Please give me a docstring!
|
||||||
:Updated: $Date$
|
:Updated: $Date$
|
||||||
:Updater: $Author$
|
:Updater: $Author$
|
||||||
'''
|
'''
|
||||||
import milla.dispatch.traversal
|
|
||||||
from webob.exc import HTTPNotFound, WSGIHTTPException
|
from webob.exc import HTTPNotFound, WSGIHTTPException
|
||||||
|
import milla.dispatch
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
|
__all__ = ['Application']
|
||||||
|
|
||||||
class Application(object):
|
class Application(object):
|
||||||
'''Represents a Milla web application
|
'''Represents a Milla web application
|
||||||
|
|
||||||
|
@ -22,33 +24,81 @@ class Application(object):
|
||||||
automatically created if a root is given
|
automatically created if a root is given
|
||||||
:param dispatcher: An object implementing the dispatcher protocol
|
:param dispatcher: An object implementing the dispatcher protocol
|
||||||
|
|
||||||
``Application`` instances are WSGI applications
|
``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, root=None, dispatcher=None):
|
def __init__(self, dispatcher):
|
||||||
if not dispatcher:
|
self.dispatcher = dispatcher
|
||||||
if root:
|
self.config = {}
|
||||||
self.dispatcher = milla.dispatch.traversal.Traverser(root)
|
|
||||||
else:
|
|
||||||
raise ValueError('Must specify either a root object or a '
|
|
||||||
'dispatcher')
|
|
||||||
else:
|
|
||||||
self.dispatcher = dispatcher
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
def __call__(self, environ, start_response):
|
||||||
|
path_info = environ['PATH_INFO']
|
||||||
try:
|
try:
|
||||||
func = self.dispatcher.resolve(environ['PATH_INFO'])
|
func = self.dispatcher.resolve(path_info)
|
||||||
except milla.dispatch.UnresolvedPath:
|
except milla.dispatch.UnresolvedPath:
|
||||||
return HTTPNotFound()(environ, start_response)
|
return HTTPNotFound()(environ, start_response)
|
||||||
|
|
||||||
request = webob.Request(environ)
|
request = webob.Request(environ)
|
||||||
|
request.config = self.config.copy()
|
||||||
|
|
||||||
|
start_response_wrapper = StartResponseWrapper(start_response)
|
||||||
|
request.start_response = start_response_wrapper
|
||||||
try:
|
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)
|
response = func(request)
|
||||||
except WSGIHTTPException as e:
|
except WSGIHTTPException as e:
|
||||||
return e(environ, start_response)
|
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)
|
||||||
|
|
||||||
if isinstance(response, basestring):
|
# 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)
|
response = webob.Response(response)
|
||||||
|
|
||||||
start_response(response.status, response.headerlist)
|
if not start_response_wrapper.called:
|
||||||
|
start_response(response.status, response.headerlist)
|
||||||
return response.app_iter
|
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)
|
|
@ -0,0 +1,23 @@
|
||||||
|
'''Stub controller classes
|
||||||
|
|
||||||
|
These classes can be used as base classes for controllers. While any
|
||||||
|
callable can technically be a controller, using a class that inherits
|
||||||
|
from one or more of these classes can make things significantly easier.
|
||||||
|
|
||||||
|
:Created: Mar 27, 2011
|
||||||
|
:Author: dustin
|
||||||
|
:Updated: $Date$
|
||||||
|
:Updater: $Author$
|
||||||
|
'''
|
||||||
|
class Controller(object):
|
||||||
|
'''The base controller class
|
||||||
|
|
||||||
|
This class simply provides empty ``__before__`` and ``__after__``
|
||||||
|
methods to facilitate cooperative multiple inheritance.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __before__(self, request):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __after__(self, request):
|
||||||
|
pass
|
Loading…
Reference in New Issue