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.