diff options
| author | Luke Plant <L.Plant.98@cantab.net> | 2009-09-21 22:31:51 +0000 |
|---|---|---|
| committer | Luke Plant <L.Plant.98@cantab.net> | 2009-09-21 22:31:51 +0000 |
| commit | afeafcd492eec9f9cb333c8c55502c1c50b3b151 (patch) | |
| tree | e86ff8c27deec468e4220e3d9fbfcd8b2a80ebe7 /django/utils | |
| parent | d56c1ab7f07eeaae3a0fc996169be7cae6a94bf4 (diff) | |
Fixed #6371 - several decorators don't work with bound methods.
This involved changing the way the internal function
decorator_from_middleware works slightly, breaking some code that relied on
the old behaviour. As a result, it is much simpler, but cache_page has been
made slightly more complex to cope with the change.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11586 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/utils')
| -rw-r--r-- | django/utils/decorators.py | 124 |
1 files changed, 76 insertions, 48 deletions
diff --git a/django/utils/decorators.py b/django/utils/decorators.py index 8fc4c1d96a..3d616f2627 100644 --- a/django/utils/decorators.py +++ b/django/utils/decorators.py @@ -2,60 +2,88 @@ import types try: - from functools import wraps + from functools import wraps, update_wrapper except ImportError: - from django.utils.functional import wraps # Python 2.3, 2.4 fallback. + from django.utils.functional import wraps, update_wrapper # Python 2.3, 2.4 fallback. -def decorator_from_middleware(middleware_class): +class MethodDecoratorAdaptor(object): """ - Given a middleware class (not an instance), returns a view decorator. This - lets you use middleware functionality on a per-view basis. + Generic way of creating decorators that adapt to being + used on methods + """ + def __init__(self, decorator, func): + update_wrapper(self, func) + # NB: update the __dict__ first, *then* set + # our own .func and .decorator, in case 'func' is actually + # another MethodDecoratorAdaptor object, which has its + # 'func' and 'decorator' attributes in its own __dict__ + self.decorator = decorator + self.func = func + def __call__(self, *args, **kwargs): + return self.decorator(self.func)(*args, **kwargs) + def __get__(self, instance, owner): + return self.decorator(self.func.__get__(instance, owner)) + def _get_name(self): + return self.func.__name__ + def _get_doc(self): + return self.func.__doc__ + +def auto_adapt_to_methods(decorator): + """Allows you to use the same decorator on methods and functions, + hiding the self argument from the decorator.""" + def adapt(func): + return MethodDecoratorAdaptor(decorator, func) + return wraps(decorator)(adapt) + +def decorator_from_middleware_with_args(middleware_class): """ - 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) + Like decorator_from_middleware, but returns a function + that accepts the arguments to be passed to the middleware_class. + Use like:: - def decorator_func(fn): - return _decorator_from_middleware(fn, *args, **kwargs) - return decorator_func + cache_page = decorator_from_middleware(CacheMiddleware) + # ... - middleware = middleware_class(*args, **kwargs) + @cache_page(3600) + def my_view(request): + # ... + """ + return make_middleware_decorator(middleware_class) - 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 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. The middleware + is created with no params passed. + """ + return make_middleware_decorator(middleware_class)() + +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 + 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 - 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 + return response + return wraps(view_func)(_wrapped_view) + return auto_adapt_to_methods(_decorator) + return _make_decorator |
