summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2010-03-12 13:31:10 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2010-03-12 13:31:10 +0000
commit9137c54353f3356e0f65e0218016e92c5bc9cc43 (patch)
treeadbd236b95a11b288f668774e9977b2d6e965e0c
parent705d6cce0f31140944f8c0b0d42a29a9f69cbf24 (diff)
[1.1.X] 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.
Backport of r12762 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.1.X@12763 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/utils/decorators.py13
-rw-r--r--django/views/decorators/cache.py6
-rw-r--r--django/views/decorators/http.py4
-rw-r--r--django/views/decorators/vary.py5
-rw-r--r--tests/regressiontests/utils/decorators.py6
-rw-r--r--tests/regressiontests/utils/urls.py1
-rw-r--r--tests/regressiontests/utils/views.py7
7 files changed, 32 insertions, 10 deletions
diff --git a/django/utils/decorators.py b/django/utils/decorators.py
index 8fc4c1d96a..683d4c6a7f 100644
--- a/django/utils/decorators.py
+++ b/django/utils/decorators.py
@@ -2,9 +2,16 @@
import types
try:
- from functools import wraps
+ from functools import wraps, WRAPPER_ASSIGNMENTS
except ImportError:
- from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
+ from django.utils.functional import wraps, WRAPPER_ASSIGNMENTS # Python 2.3, 2.4 fallback.
+
+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 decorator_from_middleware(middleware_class):
"""
@@ -57,5 +64,5 @@ def decorator_from_middleware(middleware_class):
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_from_middleware
diff --git a/django/views/decorators/cache.py b/django/views/decorators/cache.py
index 8b620c1345..9abb8d44f1 100644
--- a/django/views/decorators/cache.py
+++ b/django/views/decorators/cache.py
@@ -16,7 +16,7 @@ try:
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4 fallback.
-from django.utils.decorators import decorator_from_middleware
+from django.utils.decorators import decorator_from_middleware, available_attrs
from django.utils.cache import patch_cache_control, add_never_cache_headers
from django.middleware.cache import CacheMiddleware
@@ -31,7 +31,7 @@ def cache_control(**kwargs):
patch_cache_control(response, **kwargs)
return response
- return wraps(viewfunc)(_cache_controlled)
+ return wraps(viewfunc, assigned=available_attrs(viewfunc))(_cache_controlled)
return _cache_controller
@@ -44,4 +44,4 @@ def never_cache(view_func):
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)
diff --git a/django/views/decorators/http.py b/django/views/decorators/http.py
index b51cf9a782..9a5a314f0c 100644
--- a/django/views/decorators/http.py
+++ b/django/views/decorators/http.py
@@ -11,7 +11,7 @@ from calendar import timegm
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 @@ def require_http_methods(request_method_list):
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"])
diff --git a/django/views/decorators/vary.py b/django/views/decorators/vary.py
index ea1b8d307d..e2b87a8c71 100644
--- a/django/views/decorators/vary.py
+++ b/django/views/decorators/vary.py
@@ -4,6 +4,7 @@ except ImportError:
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 @@ def vary_on_headers(*headers):
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 @@ def vary_on_cookie(func):
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)
diff --git a/tests/regressiontests/utils/decorators.py b/tests/regressiontests/utils/decorators.py
index c6ae243c98..ca9214f787 100644
--- a/tests/regressiontests/utils/decorators.py
+++ b/tests/regressiontests/utils/decorators.py
@@ -11,3 +11,9 @@ class DecoratorFromMiddlewareTests(TestCase):
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/')
diff --git a/tests/regressiontests/utils/urls.py b/tests/regressiontests/utils/urls.py
index 7b60d0884c..ba09d14b3d 100644
--- a/tests/regressiontests/utils/urls.py
+++ b/tests/regressiontests/utils/urls.py
@@ -4,4 +4,5 @@ import views
urlpatterns = patterns('',
(r'^xview/$', views.xview),
+ (r'^class_xview/$', views.class_xview),
)
diff --git a/tests/regressiontests/utils/views.py b/tests/regressiontests/utils/views.py
index d22ae26641..ef97c6502d 100644
--- a/tests/regressiontests/utils/views.py
+++ b/tests/regressiontests/utils/views.py
@@ -8,3 +8,10 @@ xview_dec = decorator_from_middleware(XViewMiddleware)
def xview(request):
return HttpResponse()
xview = xview_dec(xview)
+
+
+class ClassXView(object):
+ def __call__(self, request):
+ return HttpResponse()
+
+class_xview = xview_dec(ClassXView())