From 17cac57721dedf6ca4b538aa4381f0bc01f48065 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Fri, 30 Nov 2012 14:37:02 -0600 Subject: [PATCH] Clean up __before__ and __after__ handling and make it Python 3-compatible --HG-- branch : py3k --- src/milla/app.py | 57 +++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/milla/app.py b/src/milla/app.py index 20dd1ae..c0b67d8 100644 --- a/src/milla/app.py +++ b/src/milla/app.py @@ -90,40 +90,12 @@ class Application(object): 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) + self._call_before(func)(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) + self._call_after(func)(request) # The callable might have returned just a string, which is OK, # but we need to wrap it in a Response object @@ -141,6 +113,31 @@ class Application(object): start_response(response.status, response.headerlist) if not environ['REQUEST_METHOD'] == 'HEAD': return response.app_iter + + def _call_after(self, func): + try: + return self._find_attr(func, '__after__') + except AttributeError: + return lambda r: None + + def _call_before(self, func): + try: + return self._find_attr(func, '__before__') + except AttributeError: + return lambda r: None + + def _find_attr(self, obj, attr): + try: + # Object has the specified attribute itself + return getattr(obj, attr) + except AttributeError: + # Object is a bound method; look for the attribute on the instance + if hasattr(obj, '__self__'): + return self._find_attr(obj.__self__, attr) + # Object is a partial; look for the attribute on the inner function + elif hasattr(obj, 'func'): + return self._find_attr(obj.func, attr) + raise class StartResponseWrapper():