diff -r b758351d191f -r cc9b7e14412b web/lib/django/utils/decorators.py --- 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