web/lib/django/utils/decorators.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
--- a/web/lib/django/utils/decorators.py	Wed May 19 17:43:59 2010 +0200
+++ b/web/lib/django/utils/decorators.py	Tue May 25 02:43:45 2010 +0200
@@ -2,60 +2,87 @@
 
 import types
 try:
-    from functools import wraps
+    from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS
 except ImportError:
-    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
+    from django.utils.functional import wraps, update_wrapper, WRAPPER_ASSIGNMENTS  # Python 2.4 fallback.
+
+
+def method_decorator(decorator):
+    """
+    Converts a function decorator into a method decorator
+    """
+    def _dec(func):
+        def _wrapper(self, *args, **kwargs):
+            def bound_func(*args2, **kwargs2):
+                return func(self, *args2, **kwargs2)
+            # bound_func has the signature that 'decorator' expects i.e.  no
+            # 'self' argument, but it is a closure over self so it can call
+            # 'func' correctly.
+            return decorator(bound_func)(*args, **kwargs)
+        return wraps(func)(_wrapper)
+    update_wrapper(_dec, decorator)
+    # Change the name to aid debugging.
+    _dec.__name__ = 'method_dec(%s)' % decorator.__name__
+    return _dec
+
+
+def decorator_from_middleware_with_args(middleware_class):
+    """
+    Like decorator_from_middleware, but returns a function
+    that accepts the arguments to be passed to the middleware_class.
+    Use like::
+
+         cache_page = decorator_from_middleware_with_args(CacheMiddleware)
+         # ...
+
+         @cache_page(3600)
+         def my_view(request):
+             # ...
+    """
+    return make_middleware_decorator(middleware_class)
+
 
 def decorator_from_middleware(middleware_class):
     """
     Given a middleware class (not an instance), returns a view decorator. This
-    lets you use middleware functionality on a per-view basis.
+    lets you use middleware functionality on a per-view basis. The middleware
+    is created with no params passed.
     """
-    def _decorator_from_middleware(*args, **kwargs):
-        # For historical reasons, these "decorators" are also called as
-        # dec(func, *args) instead of dec(*args)(func). We handle both forms
-        # for backwards compatibility.
-        has_func = True
-        try:
-            view_func = kwargs.pop('view_func')
-        except KeyError:
-            if len(args):
-                view_func, args = args[0], args[1:]
-            else:
-                has_func = False
-        if not (has_func and isinstance(view_func, types.FunctionType)):
-            # We are being called as a decorator.
-            if has_func:
-                args = (view_func,) + args
-            middleware = middleware_class(*args, **kwargs)
+    return make_middleware_decorator(middleware_class)()
 
-            def decorator_func(fn):
-                return _decorator_from_middleware(fn, *args, **kwargs)
-            return decorator_func
-
-        middleware = middleware_class(*args, **kwargs)
+def available_attrs(fn):
+    """
+    Return the list of functools-wrappable attributes on a callable.
+    This is required as a workaround for http://bugs.python.org/issue3445.
+    """
+    return tuple(a for a in WRAPPER_ASSIGNMENTS if hasattr(fn, a))
 
-        def _wrapped_view(request, *args, **kwargs):
-            if hasattr(middleware, 'process_request'):
-                result = middleware.process_request(request)
-                if result is not None:
-                    return result
-            if hasattr(middleware, 'process_view'):
-                result = middleware.process_view(request, view_func, args, kwargs)
-                if result is not None:
-                    return result
-            try:
-                response = view_func(request, *args, **kwargs)
-            except Exception, e:
-                if hasattr(middleware, 'process_exception'):
-                    result = middleware.process_exception(request, e)
+def make_middleware_decorator(middleware_class):
+    def _make_decorator(*m_args, **m_kwargs):
+        middleware = middleware_class(*m_args, **m_kwargs)
+        def _decorator(view_func):
+            def _wrapped_view(request, *args, **kwargs):
+                if hasattr(middleware, 'process_request'):
+                    result = middleware.process_request(request)
                     if result is not None:
                         return result
-                raise
-            if hasattr(middleware, 'process_response'):
-                result = middleware.process_response(request, response)
-                if result is not None:
-                    return result
-            return response
-        return wraps(view_func)(_wrapped_view)
-    return _decorator_from_middleware
+                if hasattr(middleware, 'process_view'):
+                    result = middleware.process_view(request, view_func, args, kwargs)
+                    if result is not None:
+                        return result
+                try:
+                    response = view_func(request, *args, **kwargs)
+                except Exception, e:
+                    if hasattr(middleware, 'process_exception'):
+                        result = middleware.process_exception(request, e)
+                        if result is not None:
+                            return result
+                    raise
+                if hasattr(middleware, 'process_response'):
+                    result = middleware.process_response(request, response)
+                    if result is not None:
+                        return result
+                return response
+            return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view)
+        return _decorator
+    return _make_decorator