1 "Functions that help with dynamically creating decorators for views." |
1 "Functions that help with dynamically creating decorators for views." |
2 |
2 |
3 import types |
3 import types |
4 try: |
4 try: |
5 from functools import wraps |
5 from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS |
6 except ImportError: |
6 except ImportError: |
7 from django.utils.functional import wraps # Python 2.3, 2.4 fallback. |
7 from django.utils.functional import wraps, update_wrapper, WRAPPER_ASSIGNMENTS # Python 2.4 fallback. |
|
8 |
|
9 |
|
10 def method_decorator(decorator): |
|
11 """ |
|
12 Converts a function decorator into a method decorator |
|
13 """ |
|
14 def _dec(func): |
|
15 def _wrapper(self, *args, **kwargs): |
|
16 def bound_func(*args2, **kwargs2): |
|
17 return func(self, *args2, **kwargs2) |
|
18 # bound_func has the signature that 'decorator' expects i.e. no |
|
19 # 'self' argument, but it is a closure over self so it can call |
|
20 # 'func' correctly. |
|
21 return decorator(bound_func)(*args, **kwargs) |
|
22 return wraps(func)(_wrapper) |
|
23 update_wrapper(_dec, decorator) |
|
24 # Change the name to aid debugging. |
|
25 _dec.__name__ = 'method_dec(%s)' % decorator.__name__ |
|
26 return _dec |
|
27 |
|
28 |
|
29 def decorator_from_middleware_with_args(middleware_class): |
|
30 """ |
|
31 Like decorator_from_middleware, but returns a function |
|
32 that accepts the arguments to be passed to the middleware_class. |
|
33 Use like:: |
|
34 |
|
35 cache_page = decorator_from_middleware_with_args(CacheMiddleware) |
|
36 # ... |
|
37 |
|
38 @cache_page(3600) |
|
39 def my_view(request): |
|
40 # ... |
|
41 """ |
|
42 return make_middleware_decorator(middleware_class) |
|
43 |
8 |
44 |
9 def decorator_from_middleware(middleware_class): |
45 def decorator_from_middleware(middleware_class): |
10 """ |
46 """ |
11 Given a middleware class (not an instance), returns a view decorator. This |
47 Given a middleware class (not an instance), returns a view decorator. This |
12 lets you use middleware functionality on a per-view basis. |
48 lets you use middleware functionality on a per-view basis. The middleware |
|
49 is created with no params passed. |
13 """ |
50 """ |
14 def _decorator_from_middleware(*args, **kwargs): |
51 return make_middleware_decorator(middleware_class)() |
15 # For historical reasons, these "decorators" are also called as |
|
16 # dec(func, *args) instead of dec(*args)(func). We handle both forms |
|
17 # for backwards compatibility. |
|
18 has_func = True |
|
19 try: |
|
20 view_func = kwargs.pop('view_func') |
|
21 except KeyError: |
|
22 if len(args): |
|
23 view_func, args = args[0], args[1:] |
|
24 else: |
|
25 has_func = False |
|
26 if not (has_func and isinstance(view_func, types.FunctionType)): |
|
27 # We are being called as a decorator. |
|
28 if has_func: |
|
29 args = (view_func,) + args |
|
30 middleware = middleware_class(*args, **kwargs) |
|
31 |
52 |
32 def decorator_func(fn): |
53 def available_attrs(fn): |
33 return _decorator_from_middleware(fn, *args, **kwargs) |
54 """ |
34 return decorator_func |
55 Return the list of functools-wrappable attributes on a callable. |
|
56 This is required as a workaround for http://bugs.python.org/issue3445. |
|
57 """ |
|
58 return tuple(a for a in WRAPPER_ASSIGNMENTS if hasattr(fn, a)) |
35 |
59 |
36 middleware = middleware_class(*args, **kwargs) |
60 def make_middleware_decorator(middleware_class): |
37 |
61 def _make_decorator(*m_args, **m_kwargs): |
38 def _wrapped_view(request, *args, **kwargs): |
62 middleware = middleware_class(*m_args, **m_kwargs) |
39 if hasattr(middleware, 'process_request'): |
63 def _decorator(view_func): |
40 result = middleware.process_request(request) |
64 def _wrapped_view(request, *args, **kwargs): |
41 if result is not None: |
65 if hasattr(middleware, 'process_request'): |
42 return result |
66 result = middleware.process_request(request) |
43 if hasattr(middleware, 'process_view'): |
|
44 result = middleware.process_view(request, view_func, args, kwargs) |
|
45 if result is not None: |
|
46 return result |
|
47 try: |
|
48 response = view_func(request, *args, **kwargs) |
|
49 except Exception, e: |
|
50 if hasattr(middleware, 'process_exception'): |
|
51 result = middleware.process_exception(request, e) |
|
52 if result is not None: |
67 if result is not None: |
53 return result |
68 return result |
54 raise |
69 if hasattr(middleware, 'process_view'): |
55 if hasattr(middleware, 'process_response'): |
70 result = middleware.process_view(request, view_func, args, kwargs) |
56 result = middleware.process_response(request, response) |
71 if result is not None: |
57 if result is not None: |
72 return result |
58 return result |
73 try: |
59 return response |
74 response = view_func(request, *args, **kwargs) |
60 return wraps(view_func)(_wrapped_view) |
75 except Exception, e: |
61 return _decorator_from_middleware |
76 if hasattr(middleware, 'process_exception'): |
|
77 result = middleware.process_exception(request, e) |
|
78 if result is not None: |
|
79 return result |
|
80 raise |
|
81 if hasattr(middleware, 'process_response'): |
|
82 result = middleware.process_response(request, response) |
|
83 if result is not None: |
|
84 return result |
|
85 return response |
|
86 return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view) |
|
87 return _decorator |
|
88 return _make_decorator |