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