1
2
3
4 """
5 Defines plugin managers that can handle configuration files similar to
6 the ini files manipulated by Python's ConfigParser module.
7 """
8
9 import sys, os
10 import logging
11 import ConfigParser
12
13 from IPlugin import IPlugin
14
15
16 from PluginManager import PluginManager,PluginManagerDecorator
17 from PluginManager import PLUGIN_NAME_FORBIDEN_STRING
18
19
20
22 """
23 A plugin manager that also manages a configuration file.
24
25 The configuration file will be accessed through a ``ConfigParser``
26 derivated object. The file can be used for other purpose by the
27 application using this plugin manager as it will only add a new
28 specific section ``[Plugin Management]`` for itself and also new
29 sections for some plugins that will start with ``[Plugin:...]``
30 (only the plugins that explicitly requires to save configuration
31 options will have this kind of section).
32
33 .. warning:: when giving/building the list of plugins to activate by
34 default, there must not be any space in the list (neither in the
35 names nor in between)
36 """
37
38 CONFIG_SECTION_NAME = "Plugin Management"
39
40
41 - def __init__(self,
42 configparser_instance=None,
43 config_change_trigger= lambda x:True,
44 decorated_manager=None,
45
46
47 categories_filter={"Default":IPlugin},
48 directories_list=None,
49 plugin_info_ext="yapsy-plugin"):
50 """
51 Create the plugin manager and record the ConfigParser instance
52 that will be used afterwards.
53
54 The ``config_change_trigger`` argument can be used to set a
55 specific method to call when the configuration is
56 altered. This will let the client application manage the way
57 they want the configuration to be updated (e.g. write on file
58 at each change or at precise time intervalls or whatever....)
59 """
60
61 PluginManagerDecorator.__init__(self,decorated_manager,
62 categories_filter,
63 directories_list,
64 plugin_info_ext)
65 self.setConfigParser(configparser_instance, config_change_trigger)
66
67
69 """
70 Set the ConfigParser instance.
71 """
72 self.config_parser = configparser_instance
73
74
75 self.config_has_changed = config_change_trigger
76
78 """
79 Parse the string describing the list of plugins to activate,
80 to discover their actual names and return them.
81 """
82 return plugin_list_str.strip(" ").split("%s"%PLUGIN_NAME_FORBIDEN_STRING)
83
89
91 """
92 Return the appropirately formated version of the category's
93 option.
94 """
95 return "%s_plugins_to_load" % category_name.replace(" ","_")
96
122
146
147
148
152 """
153 To be called from a plugin object, register a given option in
154 the name of a given plugin.
155 """
156 section_name = "%s Plugin: %s" % (category_name,plugin_name)
157
158 if not self.config_parser.has_section(section_name):
159 self.config_parser.add_section(section_name)
160
161 self.config_parser.set(section_name,option_name,option_value)
162 self.config_has_changed()
163
166 """
167 To be called from a plugin object, return True if the option
168 has already been registered.
169 """
170 section_name = "%s Plugin: %s" % (category_name,plugin_name)
171 return self.config_parser.has_section(section_name) and self.config_parser.has_option(section_name,option_name)
172
175 """
176 To be called from a plugin object, read a given option in
177 the name of a given plugin.
178 """
179 section_name = "%s Plugin: %s" % (category_name,plugin_name)
180 return self.config_parser.get(section_name,option_name)
181
182
184 """
185 Add two methods to the plugin objects that will make it
186 possible for it to benefit from this class's api concerning
187 the management of the options.
188 """
189 plugin_object.setConfigOption = lambda x,y: self.registerOptionFromPlugin(category_name,
190 plugin_name,
191 x,y)
192 plugin_object.setConfigOption.__doc__ = self.registerOptionFromPlugin.__doc__
193 plugin_object.getConfigOption = lambda x: self.readOptionFromPlugin(category_name,
194 plugin_name,
195 x)
196 plugin_object.getConfigOption.__doc__ = self.readOptionFromPlugin.__doc__
197 plugin_object.hasConfigOption = lambda x: self.hasOptionFromPlugin(category_name,
198 plugin_name,
199 x)
200 plugin_object.hasConfigOption.__doc__ = self.hasOptionFromPlugin.__doc__
201
203 """
204 Activate a plugin, , and remember it (in the config file).
205
206 If you want the plugin to benefit from the configuration
207 utility defined by this manager, it is crucial to use this
208 method to activate a plugin and not call the plugin object's
209 ``activate`` method. In fact, this method will also "decorate"
210 the plugin object so that it can use this class's methods to
211 register its own options.
212
213 By default, the plugin's activation is registered in the
214 config file but if you d'ont want this set the 'save_state'
215 argument to False.
216 """
217
218 pta = self._component.getPluginByName(plugin_name,category_name)
219 if pta is None:
220 return None
221 self.__decoratePluginObject(category_name,plugin_name,pta.plugin_object)
222
223 plugin_object = self._component.activatePluginByName(plugin_name,category_name)
224
225 if plugin_object.is_activated:
226 if save_state:
227 self.__addPluginToConfig(category_name,plugin_name)
228 return plugin_object
229 return None
230
232 """
233 Deactivate a plugin, and remember it (in the config file).
234
235 By default, the plugin's deactivation is registered in the
236 config file but if you d'ont want this set the ``save_state``
237 argument to False.
238 """
239
240 plugin_object = self._component.deactivatePluginByName(plugin_name,category_name)
241 if plugin_object is None:
242 return None
243
244 if not plugin_object.is_activated:
245 if save_state:
246 self.__removePluginFromConfig(category_name,plugin_name)
247 return plugin_object
248 return None
249
251 """
252 Walk through the plugins' places and look for plugins. Then
253 for each plugin candidate look for its category, load it and
254 stores it in the appropriate slot of the ``category_mapping``.
255 """
256 self._component.loadPlugins()
257
258 if self.config_parser.has_section(self.CONFIG_SECTION_NAME):
259
260 for category_name in self._component.category_mapping.keys():
261
262
263 option_name = "%s_plugins_to_load"%category_name
264 if self.config_parser.has_option(self.CONFIG_SECTION_NAME,
265 option_name):
266 plugin_list_str = self.config_parser.get(self.CONFIG_SECTION_NAME,
267 option_name)
268 plugin_list = self.__getCategoryPluginsListFromConfig(plugin_list_str)
269
270
271 for plugin_name in plugin_list:
272 self.activatePluginByName(plugin_name,category_name)
273