Mercurial > libervia-backend
comparison src/core/sat_main.py @ 1535:c9ef16de3f13
core: more robust plugins loading:
- avoid stopping loading remaining plugins when a plugin raise an error
- new error exceptions.MissingModule allows to detect a missing third party module, and to give instructions to get it
- error during instanciation are catched too
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 29 Sep 2015 17:54:23 +0200 |
parents | d749922300d0 |
children | 465d4d484e7c |
comparison
equal
deleted
inserted
replaced
1534:a5e0393a06cd | 1535:c9ef16de3f13 |
---|---|
149 plugins_to_import = {} # plugins we still have to import | 149 plugins_to_import = {} # plugins we still have to import |
150 for plug in plug_lst: | 150 for plug in plug_lst: |
151 plugin_path = 'sat.plugins.' + plug | 151 plugin_path = 'sat.plugins.' + plug |
152 try: | 152 try: |
153 __import__(plugin_path) | 153 __import__(plugin_path) |
154 except ImportError as e: | 154 except exceptions.MissingModule as e: |
155 log.error(_(u"Can't import plugin [%(path)s]: %(error)s") % {'path': plugin_path, 'error':e}) | 155 try: |
156 del sys.modules[plugin_path] | |
157 except KeyError: | |
158 pass | |
159 log.warning(u"Can't import plugin [{path}] because of an unavailale third party module:\n{msg}".format( | |
160 path=plugin_path, msg=e)) | |
161 continue | |
162 except Exception as e: | |
163 import traceback | |
164 log.error(_(u"Can't import plugin [{path}]:\n{error}").format(path=plugin_path, error=traceback.format_exc())) | |
156 continue | 165 continue |
157 mod = sys.modules[plugin_path] | 166 mod = sys.modules[plugin_path] |
158 plugin_info = mod.PLUGIN_INFO | 167 plugin_info = mod.PLUGIN_INFO |
159 import_name = plugin_info['import_name'] | 168 import_name = plugin_info['import_name'] |
160 if import_name in plugins_to_import: | 169 if import_name in plugins_to_import: |
161 log.error(_(u"Name conflict for import name [{import_name}], can't import plugin [{name}]").format(**plugin_info)) | 170 log.error(_(u"Name conflict for import name [{import_name}], can't import plugin [{name}]").format(**plugin_info)) |
162 continue | 171 continue |
163 plugins_to_import[import_name] = (plugin_path, mod, plugin_info) | 172 plugins_to_import[import_name] = (plugin_path, mod, plugin_info) |
164 while True: | 173 while True: |
165 self._import_plugins_from_dict(plugins_to_import) | 174 try: |
175 self._import_plugins_from_dict(plugins_to_import) | |
176 except ImportError: | |
177 pass | |
166 if not plugins_to_import: | 178 if not plugins_to_import: |
167 break | 179 break |
168 | 180 |
169 def _import_plugins_from_dict(self, plugins_to_import, import_name=None, optional=False): | 181 def _import_plugins_from_dict(self, plugins_to_import, import_name=None, optional=False): |
170 """Recursively import and their dependencies in the right order | 182 """Recursively import and their dependencies in the right order |
171 @param plugins_to_import: dict where key=import_name and values= (plugin_path, module, plugin_info) | 183 |
172 @param import_name: name of the plugin to import as found in PLUGIN_INFO['import_name'] | 184 @param plugins_to_import(dict): key=import_name and values=(plugin_path, module, plugin_info) |
173 @param optional: if False and plugin is not found, an ImportError exception is raised | 185 @param import_name(unicode, None): name of the plugin to import as found in PLUGIN_INFO['import_name'] |
174 | 186 @param optional(bool): if False and plugin is not found, an ImportError exception is raised |
175 """ | 187 """ |
176 if import_name in self.plugins: | 188 if import_name in self.plugins: |
177 log.debug(u'Plugin [%s] already imported, passing' % import_name) | 189 log.debug(u'Plugin {} already imported, passing'.format(import_name)) |
178 return | 190 return |
179 if not import_name: | 191 if not import_name: |
180 import_name, (plugin_path, mod, plugin_info) = plugins_to_import.popitem() | 192 import_name, (plugin_path, mod, plugin_info) = plugins_to_import.popitem() |
181 else: | 193 else: |
182 if not import_name in plugins_to_import: | 194 if not import_name in plugins_to_import: |
183 if optional: | 195 if optional: |
184 log.warning(_(u"Recommended plugin not found: %s") % import_name) | 196 log.warning(_(u"Recommended plugin not found: {}").format(import_name)) |
185 return | 197 return |
186 log.error(_(u"Dependency not found: %s") % import_name) | 198 msg = u"Dependency not found: {}".format(import_name) |
187 raise ImportError(_('Dependency plugin not found: [%s]') % import_name) | 199 log.error(msg) |
200 raise ImportError(msg) | |
188 plugin_path, mod, plugin_info = plugins_to_import.pop(import_name) | 201 plugin_path, mod, plugin_info = plugins_to_import.pop(import_name) |
189 dependencies = plugin_info.setdefault("dependencies", []) | 202 dependencies = plugin_info.setdefault("dependencies", []) |
190 recommendations = plugin_info.setdefault("recommendations", []) | 203 recommendations = plugin_info.setdefault("recommendations", []) |
191 for to_import in dependencies + recommendations: | 204 for to_import in dependencies + recommendations: |
192 if to_import not in self.plugins: | 205 if to_import not in self.plugins: |
193 log.debug(u'Recursively import dependency of [%s]: [%s]' % (import_name, to_import)) | 206 log.debug(u'Recursively import dependency of [%s]: [%s]' % (import_name, to_import)) |
194 try: | 207 try: |
195 self._import_plugins_from_dict(plugins_to_import, to_import, to_import not in dependencies) | 208 self._import_plugins_from_dict(plugins_to_import, to_import, to_import not in dependencies) |
196 except ImportError as e: | 209 except ImportError as e: |
197 log.error(_(u"Can't import plugin %(name)s: %(error)s") % {'name':plugin_info['name'], 'error':e}) | 210 log.warning(_(u"Can't import plugin {name}: {error}").format(name=plugin_info['name'], error=e)) |
198 return | 211 if optional: |
199 log.info(_("importing plugin: %s") % plugin_info['name']) | 212 return |
200 self.plugins[import_name] = getattr(mod, plugin_info['main'])(self) | 213 raise e |
214 log.info("importing plugin: {}".format(plugin_info['name'])) | |
215 # we instanciate the plugin here | |
216 try: | |
217 self.plugins[import_name] = getattr(mod, plugin_info['main'])(self) | |
218 except Exception as e: | |
219 log.warning(u'Error while loading plugin "{name}", ignoring it: {error}' | |
220 .format(name=plugin_info['name'], error=e)) | |
221 if optional: | |
222 return | |
223 raise ImportError(u"Error during initiation") | |
201 if 'handler' in plugin_info and plugin_info['handler'] == 'yes': | 224 if 'handler' in plugin_info and plugin_info['handler'] == 'yes': |
202 self.plugins[import_name].is_handler = True | 225 self.plugins[import_name].is_handler = True |
203 else: | 226 else: |
204 self.plugins[import_name].is_handler = False | 227 self.plugins[import_name].is_handler = False |
205 #TODO: test xmppclient presence and register handler parent | 228 #TODO: test xmppclient presence and register handler parent |