Author: russellm
Date: 2010-03-12 07:06:13 -0600 (Fri, 12 Mar 2010)
New Revision: 12762

Modified:
   django/trunk/django/utils/decorators.py
   django/trunk/django/views/decorators/cache.py
   django/trunk/django/views/decorators/csrf.py
   django/trunk/django/views/decorators/http.py
   django/trunk/django/views/decorators/vary.py
   django/trunk/tests/regressiontests/utils/decorators.py
   django/trunk/tests/regressiontests/utils/urls.py
   django/trunk/tests/regressiontests/utils/views.py
Log:
Fixed #13093 -- Updated some decorators and the decorator_from_middleware 
function to allow callable classes to be decorated. Thanks to Brian Neal for 
the report.

Modified: django/trunk/django/utils/decorators.py
===================================================================
--- django/trunk/django/utils/decorators.py     2010-03-11 14:14:07 UTC (rev 
12761)
+++ django/trunk/django/utils/decorators.py     2010-03-12 13:06:13 UTC (rev 
12762)
@@ -2,9 +2,9 @@
 
 import types
 try:
-    from functools import wraps, update_wrapper
+    from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS
 except ImportError:
-    from django.utils.functional import wraps, update_wrapper  # Python 2.3, 
2.4 fallback.
+    from django.utils.functional import wraps, update_wrapper, 
WRAPPER_ASSIGNMENTS  # Python 2.3, 2.4 fallback.
 
 
 def method_decorator(decorator):
@@ -50,6 +50,12 @@
     """
     return make_middleware_decorator(middleware_class)()
 
+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 make_middleware_decorator(middleware_class):
     def _make_decorator(*m_args, **m_kwargs):
@@ -77,6 +83,6 @@
                     if result is not None:
                         return result
                 return response
-            return wraps(view_func)(_wrapped_view)
+            return wraps(view_func, 
assigned=available_attrs(view_func))(_wrapped_view)
         return _decorator
     return _make_decorator

Modified: django/trunk/django/views/decorators/cache.py
===================================================================
--- django/trunk/django/views/decorators/cache.py       2010-03-11 14:14:07 UTC 
(rev 12761)
+++ django/trunk/django/views/decorators/cache.py       2010-03-12 13:06:13 UTC 
(rev 12762)
@@ -16,7 +16,7 @@
 except ImportError:
     from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
 
-from django.utils.decorators import decorator_from_middleware_with_args
+from django.utils.decorators import decorator_from_middleware_with_args, 
available_attrs
 from django.utils.cache import patch_cache_control, add_never_cache_headers
 from django.middleware.cache import CacheMiddleware
 
@@ -56,7 +56,7 @@
             response = viewfunc(request, *args, **kw)
             patch_cache_control(response, **kwargs)
             return response
-        return wraps(viewfunc)(_cache_controlled)
+        return wraps(viewfunc, 
assigned=available_attrs(viewfunc))(_cache_controlled)
     return _cache_controller
 
 
@@ -69,4 +69,4 @@
         response = view_func(request, *args, **kwargs)
         add_never_cache_headers(response)
         return response
-    return wraps(view_func)(_wrapped_view_func)
+    return wraps(view_func, 
assigned=available_attrs(view_func))(_wrapped_view_func)

Modified: django/trunk/django/views/decorators/csrf.py
===================================================================
--- django/trunk/django/views/decorators/csrf.py        2010-03-11 14:14:07 UTC 
(rev 12761)
+++ django/trunk/django/views/decorators/csrf.py        2010-03-12 13:06:13 UTC 
(rev 12762)
@@ -1,5 +1,6 @@
 from django.middleware.csrf import CsrfViewMiddleware
-from django.utils.decorators import decorator_from_middleware
+from django.utils.decorators import decorator_from_middleware, available_attrs
+
 try:
     from functools import wraps
 except ImportError:
@@ -22,7 +23,7 @@
         resp = view_func(*args, **kwargs)
         resp.csrf_exempt = True
         return resp
-    return wraps(view_func)(wrapped_view)
+    return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
 
 def csrf_view_exempt(view_func):
     """
@@ -34,7 +35,7 @@
     def wrapped_view(*args, **kwargs):
         return view_func(*args, **kwargs)
     wrapped_view.csrf_exempt = True
-    return wraps(view_func)(wrapped_view)
+    return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
 
 def csrf_exempt(view_func):
     """

Modified: django/trunk/django/views/decorators/http.py
===================================================================
--- django/trunk/django/views/decorators/http.py        2010-03-11 14:14:07 UTC 
(rev 12761)
+++ django/trunk/django/views/decorators/http.py        2010-03-12 13:06:13 UTC 
(rev 12762)
@@ -11,7 +11,7 @@
 from datetime import timedelta
 from email.Utils import formatdate
 
-from django.utils.decorators import decorator_from_middleware
+from django.utils.decorators import decorator_from_middleware, available_attrs
 from django.utils.http import parse_etags, quote_etag
 from django.middleware.http import ConditionalGetMiddleware
 from django.http import HttpResponseNotAllowed, HttpResponseNotModified, 
HttpResponse
@@ -35,7 +35,7 @@
             if request.method not in request_method_list:
                 return HttpResponseNotAllowed(request_method_list)
             return func(request, *args, **kwargs)
-        return wraps(func)(inner)
+        return wraps(func, assigned=available_attrs(func))(inner)
     return decorator
 
 require_GET = require_http_methods(["GET"])

Modified: django/trunk/django/views/decorators/vary.py
===================================================================
--- django/trunk/django/views/decorators/vary.py        2010-03-11 14:14:07 UTC 
(rev 12761)
+++ django/trunk/django/views/decorators/vary.py        2010-03-12 13:06:13 UTC 
(rev 12762)
@@ -4,6 +4,7 @@
     from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
 
 from django.utils.cache import patch_vary_headers
+from django.utils.decorators import available_attrs
 
 def vary_on_headers(*headers):
     """
@@ -21,7 +22,7 @@
             response = func(*args, **kwargs)
             patch_vary_headers(response, headers)
             return response
-        return wraps(func)(inner_func)
+        return wraps(func, assigned=available_attrs(func))(inner_func)
     return decorator
 
 def vary_on_cookie(func):
@@ -37,4 +38,4 @@
         response = func(*args, **kwargs)
         patch_vary_headers(response, ('Cookie',))
         return response
-    return wraps(func)(inner_func)
+    return wraps(func, assigned=available_attrs(func))(inner_func)

Modified: django/trunk/tests/regressiontests/utils/decorators.py
===================================================================
--- django/trunk/tests/regressiontests/utils/decorators.py      2010-03-11 
14:14:07 UTC (rev 12761)
+++ django/trunk/tests/regressiontests/utils/decorators.py      2010-03-12 
13:06:13 UTC (rev 12762)
@@ -11,3 +11,9 @@
         Test a middleware that implements process_view.
         """
         self.client.get('/utils/xview/')
+
+    def test_callable_process_view_middleware(self):
+        """
+        Test a middleware that implements process_view, operating on a 
callable class.
+        """
+        self.client.get('/utils/class_xview/')

Modified: django/trunk/tests/regressiontests/utils/urls.py
===================================================================
--- django/trunk/tests/regressiontests/utils/urls.py    2010-03-11 14:14:07 UTC 
(rev 12761)
+++ django/trunk/tests/regressiontests/utils/urls.py    2010-03-12 13:06:13 UTC 
(rev 12762)
@@ -4,4 +4,5 @@
 
 urlpatterns = patterns('',
     (r'^xview/$', views.xview),
+    (r'^class_xview/$', views.class_xview),
 )

Modified: django/trunk/tests/regressiontests/utils/views.py
===================================================================
--- django/trunk/tests/regressiontests/utils/views.py   2010-03-11 14:14:07 UTC 
(rev 12761)
+++ django/trunk/tests/regressiontests/utils/views.py   2010-03-12 13:06:13 UTC 
(rev 12762)
@@ -8,3 +8,10 @@
 def xview(request):
     return HttpResponse()
 xview = xview_dec(xview)
+
+
+class ClassXView(object):
+    def __call__(self, request):
+        return HttpResponse()
+
+class_xview = xview_dec(ClassXView())

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to