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