1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import sys
18
19 from libxyz.exceptions import PluginError
20 from libxyz.exceptions import XYZValueError
21 from libxyz.core.plugins import BasePlugin
22 from libxyz.core.plugins import Namespace
23 from libxyz.core.utils import ustring
37
38 return _trans
39
43 """
44 Plugin manager class
45 It is supposed to provide easy access to plugin data
46 """
47
48 PLUGIN_CLASS = u"XYZPlugin"
49 PLUGIN_FILE = u"main"
50 VIRTUAL_NAMESPACE = u"sys"
51 EVENT_INIT = u"event:plugin_init"
52 EVENT_FROM_LOAD = u"event:plugin_from_load"
53 EVENT_FROM_LOAD_DATA = u"event:plugin_from_load_data"
54 EVENT_PREPARE = u"event:plugin_prepare"
55 EVENT_FIN = u"event:plugin_fin"
56
58 """
59 @param xyz: XYZ data
60 @param dirs: Plugin directories list
61 @type dirs: list
62 """
63
64 if not isinstance(dirs, list):
65 raise XYZValueError(_(u"Invalid argument type %s. List expected" %
66 type(dirs)))
67 else:
68 sys.path = dirs + sys.path
69
70 self.xyz = xyz
71
72 self.enabled = self._enabled_list()
73
74
75 self._loaded = {}
76 self._waiting = {}
77
78
79
80 @ns_transform
81 - def load(self, plugin, *initargs, **initkwargs):
82 """
83 Load and initiate required plugin
84 @param plugin: Plugin namespace path
85 @param initargs: Necessary arguments to initiate plugin
86 @param initkwargs: Necessary kw arguments to initiate plugin
87 """
88
89 virtual = self.is_virtual(plugin)
90
91 if plugin.pfull not in self.enabled:
92 raise PluginError(_(u"Plugin %s is disabled or does not exist" %
93 plugin))
94
95 if self.is_loaded(plugin):
96 return self.get_loaded(plugin)
97
98 if virtual:
99
100
101 return None
102
103 plugin.set_method(self.PLUGIN_FILE)
104
105 self.xyz.hm.dispatch(self.EVENT_INIT, plugin)
106
107
108
109 try:
110 _loaded = __import__(plugin.internal, globals(), locals(),
111 [self.PLUGIN_CLASS])
112 except ImportError, e:
113 raise PluginError(_(u"Unable to load plugin %s: %s" % (plugin, e)))
114
115 try:
116 _loaded = getattr(_loaded, self.PLUGIN_CLASS)
117 except AttributeError, e:
118 raise PluginError(_(u"Unable to find required %s class" % \
119 self.PLUGIN_CLASS))
120
121
122 _obj = _loaded(self.xyz, *initargs, **initkwargs)
123
124
125 self.xyz.hm.dispatch(self.EVENT_PREPARE, _obj)
126 _obj.prepare()
127
128 self.set_loaded(plugin, _obj)
129
130 return _obj
131
132
133
134 @ns_transform
135 - def reload(self, plugin, *initargs, **initkwargs):
136 """
137 Force load plugin if it's already in cache.
138 """
139
140 if self.is_virtual(plugin):
141
142 return None
143
144 if self.is_loaded(plugin):
145 self.del_loaded(plugin)
146
147 return self.load(plugin, *initargs, **initkwargs)
148
149
150
151 @ns_transform
153 """
154 Load method from plugin.
155 If plugin was not loaded before, load and initiate it first.
156
157 @param plugin: Plugin namespace path
158 @param method: Public method name
159 """
160
161 self.xyz.hm.dispatch(self.EVENT_FROM_LOAD, plugin, method)
162
163 if not self.is_loaded(plugin):
164 _obj = self.load(plugin)
165 else:
166 _obj = self.get_loaded(plugin)
167
168
169 if _obj is None:
170 return None
171
172 if method not in _obj.public:
173 raise PluginError(_(u"%s plugin instance does not export "\
174 u"method %s" % (plugin, method)))
175 else:
176 return _obj.public[method]
177
178
179
180 @ns_transform
182 """
183 Load data object from plugin.
184 If plugin was not loaded before, load and initiate it first.
185
186 @param plugin: Plugin namespace path
187 @param obj: Public data object name
188 """
189
190 self.xyz.hm.dispatch(self.EVENT_FROM_LOAD_DATA, plugin, obj)
191
192 if not self.is_loaded(plugin):
193 _obj = self.load(plugin)
194 else:
195 _obj = self.get_loaded(plugin)
196
197 if obj not in _obj.public_data:
198 raise PluginError(_(u"%s plugin instance does not export "\
199 u"data object %s" % (plugin, obj)))
200 else:
201 return _obj.public_data[obj]
202
203
204
205 @ns_transform
207 """
208 Check if plugin already loaded
209 @param plugin: Plugin namespace path
210 """
211
212 return plugin.full in self._loaded
213
214
215
216 @ns_transform
218 """
219 Return loaded and initiated inistance of plugin
220 @param plugin: Plugin namespace path
221 """
222
223 return self._loaded[plugin.pfull]
224
225
226
228 """
229 Return all currenty loaded plugins as dictionary with plugins ns path
230 as keys and instances as values
231 """
232
233 return self._loaded
234
235
236
237 @ns_transform
239 """
240 Set loaded and initiated inistance of plugin
241 @param plugin: Plugin namespace path
242 @param inst: Plugin instance
243 """
244
245
246 if plugin.pfull in self._waiting:
247
248 for _cb, _args in self._waiting[plugin.pfull]:
249 try:
250 _cb(inst, *_args)
251 except Exception, e:
252 xyzlog.warning(_(u"Error in wait_for() callback: %s" %
253 ustring(str(e))))
254 del(self._waiting[plugin.pfull])
255
256 self._loaded[plugin.pfull] = inst
257
258
259
260 @ns_transform
262 """
263 Delete loaded instance from cache
264 @param plugin: Plugin namespace path
265 """
266
267 try:
268 self.shutdown(plugin.pfull)
269 del(self._loaded[plugin.pfull])
270 except KeyError:
271 pass
272
273
274
275 @ns_transform
276 - def wait_for(self, plugin, callback, *args):
277 """
278 Some virtual plugins are not available at the parsing time.
279 This method is used to wait while plugin is loaded and then run
280 callback.
281 Arguments to callback: loaded plugin obj, and all optional *args passed
282 """
283
284
285 if self.is_loaded(plugin):
286 return callback(self.get_loaded(plugin), *args)
287
288
289 if plugin.pfull not in self._waiting:
290 self._waiting[plugin.pfull] = []
291
292
293 self._waiting[plugin.pfull].append((callback, args))
294
295
296
298 """
299 Run destructors on specified or all loaded plugins
300 """
301
302 def _fin(p):
303 try:
304 self._loaded[p].finalize()
305 except Exception:
306 pass
307
308
309
310 if self._loaded:
311 _plugins = self._loaded
312 else:
313 _plugins = [plugin]
314
315 for plugin_name in self._loaded:
316 self.xyz.hm.dispatch(self.EVENT_FIN, self._loaded[plugin_name])
317 _fin(plugin_name)
318
319
320
322 """
323 Register new plugin.
324 @param obj: libxyz.core.BasePlugin inherited instance
325 """
326
327 if not isinstance(obj, BasePlugin):
328 raise XYZValueError(_(u"BasePlugin instance expected, got: %s" %
329 type(obj)))
330
331 self.set_loaded(obj.ns, obj)
332
333
334
337
338
339
341 """
342 Make list of enabled plugins
343 """
344
345 _data = self.xyz.conf[u"xyz"][u"plugins"]
346 return [_pname for _pname in _data if _data[_pname]]
347