]> git.openstreetmap.org Git - osqa.git/blob - forum/modules/decorators.py
OSQA-829, resolves a unicode problem when answering question, use smart_unicode for...
[osqa.git] / forum / modules / decorators.py
1 import inspect
2
3 class DecoratableObject(object):
4     MODE_OVERRIDE = 0
5     MODE_PARAMS = 1
6     MODE_RESULT = 2
7
8     def __init__(self, fn, is_method=False):
9         self._callable = fn
10         self.is_method = is_method
11
12         self._params_decoration = None
13         self._result_decoration = None
14
15     def _decorate(self, fn, mode, **kwargs):
16         if mode == self.MODE_OVERRIDE:
17             self._decorate_full(fn, **kwargs)
18         elif mode == self.MODE_PARAMS:
19             self._decorate_params(fn)
20         elif mode == self.MODE_RESULT:
21             self._decorate_result(fn, **kwargs)
22
23     def _decorate_full(self, fn, needs_origin=True):
24         origin = self._callable
25
26         if needs_origin:
27             if self.is_method:
28                 self._callable = lambda inst, *args, **kwargs: fn(inst, origin, *args, **kwargs)
29             else:
30                 self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)
31         else:
32             self._callable = fn
33
34     def _decorate_params(self, fn):
35         if not self._params_decoration:
36             self._params_decoration = []
37
38         self._params_decoration.append(fn)
39
40     def _decorate_result(self, fn, needs_params=False):
41         if not self._result_decoration:
42             self._result_decoration = []
43
44         fn._needs_params = needs_params
45         self._result_decoration.append(fn)
46
47     def __call__(self, *args, **kwargs):
48         if self._params_decoration:
49             for dec in self._params_decoration:
50                 try:
51                     args, kwargs = dec(*args, **kwargs)
52                 except ReturnImediatelyException, e:
53                     return e.ret
54
55         res = self._callable(*args, **kwargs)
56
57         if self._result_decoration:
58             for dec in self._result_decoration:
59                 if dec._needs_params:
60                     res = dec(res, *args, **kwargs)
61                 else:
62                     res = dec(res)
63
64         return res
65
66 class ReturnImediatelyException(Exception):
67     def __init__(self, ret):
68         super(Exception, self).__init__()
69         self.ret = ret
70
71 def _check_decoratable(origin, install=True):
72     if not hasattr(origin, '_decoratable_obj'):
73         if inspect.ismethod(origin) and not hasattr(origin, '_decoratable_obj'):
74             decoratable = DecoratableObject(origin)
75
76             def decoratable_method(self, *args, **kwargs):
77                 return decoratable(self, *args, **kwargs)
78
79             decoratable_method._decoratable_obj = decoratable
80
81             def decoratable_decorate(fn, mode, **kwargs):
82                 decoratable._decorate(fn, mode, **kwargs)
83
84             decoratable_method._decorate = decoratable_decorate
85
86             if install:
87                 setattr(origin.im_class, origin.__name__, decoratable_method)
88
89             return decoratable_method
90                 
91         elif inspect.isfunction(origin):
92             decoratable = DecoratableObject(origin)
93
94             def decorated(*args, **kwargs):
95                 return decoratable(*args, **kwargs)
96
97             decorated._decoratable_obj = decoratable
98
99             if install:
100                 setattr(inspect.getmodule(origin), origin.__name__, decorated)
101
102             decorated.__name__ = origin.__name__
103             decorated.__module__ = origin.__module__
104
105             return decorated
106
107     return origin
108
109
110 def decorate(origin, needs_origin=True):
111     origin = _check_decoratable(origin)
112
113     def decorator(fn):
114         origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_OVERRIDE, needs_origin=needs_origin)
115         
116     return decorator
117
118
119 def _decorate_params(origin):
120     origin = _check_decoratable(origin)
121
122     def decorator(fn):
123         origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_PARAMS)
124
125     return decorator
126
127 decorate.params = _decorate_params
128
129 def _decorate_result(origin, needs_params=False):
130     origin = _check_decoratable(origin)
131
132     def decorator(fn):
133         origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_RESULT, needs_params=needs_params)
134
135     return decorator
136
137 decorate.result = _decorate_result
138
139 def _decorate_with(fn):
140     def decorator(origin):
141         origin = _check_decoratable(origin)
142         origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_OVERRIDE, needs_origin=True)
143         return origin
144     return decorator
145
146 decorate.withfn = _decorate_with
147
148 def _decorate_result_with(fn, needs_params=False):
149     def decorator(origin):
150         origin = _check_decoratable(origin)
151         origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_RESULT, needs_params=needs_params)
152         return origin
153     return decorator
154
155 decorate.result.withfn = _decorate_result_with
156
157 def _decorate_params_with(fn):
158     def decorator(origin):
159         origin = _check_decoratable(origin)
160         origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_PARAMS)
161         return origin
162     return decorator
163
164 decorate.params.withfn = _decorate_params_with