def __init__(self, plugin_provider, settings, application_context, settings_prefix=''): super(PluginManager, self).__init__() self.setObjectName('PluginManager') self._plugin_provider = plugin_provider self._settings = Settings(SettingsProxy(settings), '/'.join([x for x in ['plugin_manager', settings_prefix] if x != ''])) self._application_context = application_context self._main_window = None self._container_manager = None self._plugin_menu = None self._minimized_dock_widgets_toolbar = None self._global_settings = None self._perspective_settings = None self._plugin_descriptors = None self._running_plugins = {} self._number_of_ongoing_calls = None if self._application_context.options.multi_process or self._application_context.options.embed_plugin: try: from .plugin_handler_xembed import PluginHandlerXEmbed # @UnusedImport except ImportError: qCritical('PluginManager.__init__() multiprocess-mode only available under linux') exit(-1) # force connection type to queued, to delay the 'reloading' giving the 'unloading' time to finish self._deferred_reload_plugin_signal.connect(self._reload_plugin_load, type=Qt.QueuedConnection) if self._application_context.provide_app_dbus_interfaces: from .plugin_manager_dbus_interface import PluginManagerDBusInterface self._dbus_service = PluginManagerDBusInterface(self, self._application_context)
def _shutdown_plugin(self): if hasattr(self._plugin, 'shutdown_plugin'): try: self._plugin.shutdown_plugin() except Exception: qCritical('PluginHandlerDirect._shutdown_plugin() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc())) self.emit_shutdown_plugin_completed()
def _load_plugin_load(self, instance_id, callback, argv=None): # if the requested instance is already running, do nothing if str(instance_id) in self._running_plugins: raise Exception('PluginManager._load_plugin(%s) instance already loaded' % str(instance_id)) # containers are pseudo-plugins and handled by a special handler if self._container_manager is not None and instance_id.plugin_id == self._container_manager.get_container_descriptor().plugin_id(): handler = PluginHandlerContainer(self, self._main_window, instance_id, self._application_context, self._container_manager) # use platform specific handler for multiprocess-mode if available elif self._application_context.options.multi_process or self._application_context.options.embed_plugin: try: from .plugin_handler_xembed import PluginHandlerXEmbed handler = PluginHandlerXEmbed(self, self._main_window, instance_id, self._application_context, self._container_manager, argv) except ImportError: qCritical('PluginManager._load_plugin() could not load plugin in a separate process') return # use direct handler for in-process plugins else: handler = PluginHandlerDirect(self, self._main_window, instance_id, self._application_context, self._container_manager, argv) handler.set_minimized_dock_widgets_toolbar(self._minimized_dock_widgets_toolbar) plugin_descriptor = self._plugin_descriptors[instance_id.plugin_id] handler.set_plugin_descriptor(plugin_descriptor) self._add_running_plugin(instance_id, handler) handler.load(self._plugin_provider, callback)
def __init__(self, plugin_provider, application_context): super(PluginManager, self).__init__() self.setObjectName('PluginManager') self._plugin_provider = plugin_provider self._application_context = application_context self._main_window = None self._container_manager = None self._plugin_menu = None self._global_settings = None self._perspective_settings = None self._plugin_descriptors = None self._running_plugins = {} self._number_of_ongoing_calls = None if self._application_context.options.multi_process or self._application_context.options.embed_plugin: try: from .plugin_handler_xembed import PluginHandlerXEmbed # @UnusedImport except ImportError: qCritical( 'PluginManager.__init__() multiprocess-mode only available under linux' ) exit(-1) # force connection type to queued, to delay the 'reloading' giving the 'unloading' time to finish self._deferred_reload_plugin_signal.connect(self._reload_plugin_load, type=Qt.QueuedConnection) if self._application_context.provide_app_dbus_interfaces: from .plugin_manager_dbus_interface import PluginManagerDBusInterface self._dbus_service = PluginManagerDBusInterface( self, self._application_context)
def _emit_load_completed(self, exception=None): if exception is not None: self._garbage_widgets_and_toolbars() if self.__callback is not None: callback = self.__callback self.__callback = None callback(self, exception) elif exception is not None: qCritical('PluginHandler.load() failed%s' % (':\n%s' % str(exception) if exception != True else ''))
def _save_settings_from_remote(self): qDebug('PluginHandlerXEmbedClient._save_settings_from_remote()') try: plugin_settings = Settings(self._remote_plugin_settings, '') instance_settings = Settings(self._remote_instance_settings, '') self._save_settings(plugin_settings, instance_settings) except Exception: qCritical('PluginHandlerXEmbedClient._save_settings_from_remote() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc())) self.emit_save_settings_completed()
def _restore_settings(self, plugin_settings, instance_settings): if hasattr(self._plugin, 'restore_settings'): plugin_settings_plugin = plugin_settings.get_settings('plugin') instance_settings_plugin = instance_settings.get_settings('plugin') try: self._plugin.restore_settings(plugin_settings_plugin, instance_settings_plugin) except Exception: qCritical('PluginHandlerDirect._restore_settings() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc())) self.emit_restore_settings_completed()
def _call_method_on_all_dock_widgets(self, method_name, instance_settings): for dock_widget, _, _ in self._widgets.values(): name = 'dock_widget' + dock_widget.objectName().replace(self._instance_id.tidy_str(), '', 1) settings = instance_settings.get_settings(name) method = getattr(dock_widget, method_name) try: method(settings) except Exception: qCritical('PluginHandler._call_method_on_all_dock_widgets(%s) failed:\n%s' % (method_name, traceback.format_exc()))
def _shutdown_plugin(self): if hasattr(self._plugin, 'shutdown_plugin'): try: self._plugin.shutdown_plugin() except Exception: qCritical( 'PluginHandlerDirect._shutdown_plugin() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc())) self.emit_shutdown_plugin_completed()
def shutdown_plugin(self, callback): """ Shutdown plugin (`Plugin.shutdown_plugin()`) and remove all added widgets. Completion is signaled asynchronously if a callback is passed. """ self.__callback = callback try: self._shutdown_plugin() except Exception: qCritical('PluginHandler.shutdown_plugin() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc())) self.emit_shutdown_plugin_completed()
def unload(self, callback=None): """ Unload plugin. Completion is signaled asynchronously if a callback is passed. """ self.__callback = callback try: self._unload() except Exception: qCritical('PluginHandler.unload() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc())) self._emit_unload_completed()
def _restore_settings(self, plugin_settings, instance_settings): if hasattr(self._plugin, 'restore_settings'): plugin_settings_plugin = plugin_settings.get_settings('plugin') instance_settings_plugin = instance_settings.get_settings('plugin') try: self._plugin.restore_settings(plugin_settings_plugin, instance_settings_plugin) except Exception: qCritical( 'PluginHandlerDirect._restore_settings() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc())) self.emit_restore_settings_completed()
def discover(self, discovery_data): # discover plugins from all providers discovered_plugins = [] for plugin_provider in self._plugin_providers: try: plugin_descriptors = plugin_provider.discover(discovery_data) except Exception: qCritical('CompositePluginProvider.discover() could not discover plugins from provider "%s":\n%s' % (type(plugin_provider), traceback.format_exc())) else: self._discovered_plugins[plugin_provider] = plugin_descriptors discovered_plugins += plugin_descriptors return discovered_plugins
def restore_settings(self, plugin_settings, instance_settings, callback=None): """ Restore settings of the plugin (`Plugin.restore_settings()`) and all dock widget title bars. Completion is signaled asynchronously if a callback is passed. """ qDebug('PluginHandler.restore_settings()') self.__instance_settings = instance_settings self.__callback = callback try: self._restore_settings(plugin_settings, instance_settings) except Exception: qCritical('PluginHandler.restore_settings() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc())) self.emit_restore_settings_completed()
def discover(self, discovery_data): # discover plugins from all providers discovered_plugins = [] for plugin_provider in self._plugin_providers: try: plugin_descriptors = plugin_provider.discover(discovery_data) except Exception: qCritical( 'CompositePluginProvider.discover() could not discover plugins from ' 'provider "%s":\n%s' % (type(plugin_provider), traceback.format_exc())) else: self._discovered_plugins[plugin_provider] = plugin_descriptors discovered_plugins += plugin_descriptors return discovered_plugins
def _load_plugin_completed(self, handler, exception): instance_id = handler.instance_id() if exception is not None: if isinstance(exception, PluginLoadError): qWarning('PluginManager._load_plugin() could not load plugin "%s": %s' % (instance_id.plugin_id, exception)) else: qCritical('PluginManager._load_plugin() could not load plugin "%s"%s' % (instance_id.plugin_id, (':\n%s' % traceback.format_exc() if exception != True else ''))) self._remove_running_plugin(instance_id) # quit embed application if self._application_context.options.embed_plugin: exit(-1) return qDebug('PluginManager._load_plugin(%s) successful' % str(instance_id)) handler.close_signal.connect(self.unload_plugin) handler.reload_signal.connect(self.reload_plugin) handler.help_signal.connect(self._emit_plugin_help_signal)
def discover(self): # discover plugins, which are providers themselves plugin_descriptors = self._plugin_provider.discover() # instantiate plugins plugin_providers = [] for plugin_descriptor in plugin_descriptors: try: # pass None as PluginContext for PluginProviders instance = self._plugin_provider.load(plugin_descriptor.plugin_id(), None) except Exception: qCritical('RecursivePluginProvider.discover() loading plugin "%s" failed:\n%s' % (str(plugin_descriptor.plugin_id()), traceback.format_exc())) else: if instance is not None: plugin_providers.append(instance) # delegate discovery through instantiated plugin providers to base class self.set_plugin_providers(plugin_providers) return CompositePluginProvider.discover(self)
def discover(self, discovery_data): # discover plugins, which are providers themselves plugin_descriptors = self._plugin_provider.discover(discovery_data) # instantiate plugins plugin_providers = [] for plugin_descriptor in plugin_descriptors: try: # pass None as PluginContext for PluginProviders instance = self._plugin_provider.load(plugin_descriptor.plugin_id(), None) except Exception: qCritical('RecursivePluginProvider.discover() loading plugin "%s" failed:\n%s' % (str(plugin_descriptor.plugin_id()), traceback.format_exc())) else: if instance is not None: plugin_providers.append(instance) # delegate discovery through instantiated plugin providers to base class self.set_plugin_providers(plugin_providers) return CompositePluginProvider.discover(self, discovery_data)
def load(self, plugin_id, plugin_context): # get class reference from plugin descriptor attributes = self._plugin_descriptors[plugin_id].attributes() sys.path.append(os.path.join(attributes['plugin_path'], attributes['library_path'])) try: module = __builtin__.__import__( attributes['module_name'], fromlist=[attributes['class_from_class_type']], level=0) except NotImplementedError as e: qCritical('RosPluginProvider.load(%s): raised an exception:\n%s' % (plugin_id, e)) return None except Exception as e: qCritical('RosPluginProvider.load(%s) exception raised in ' '__builtin__.__import__(%s, [%s]):\n%s' % ( plugin_id, attributes['module_name'], attributes['class_from_class_type'], traceback.format_exc())) raise e class_ref = getattr(module, attributes['class_from_class_type'], None) if class_ref is None: qCritical('RosPluginProvider.load(%s): could not find class "%s" in module "%s"' % (plugin_id, attributes['class_from_class_type'], module)) return None # create plugin provider instance without context try: code = class_ref.__init__.func_code except AttributeError: code = class_ref.__init__.__code__ if code.co_argcount == 1 and plugin_context is None: return class_ref() # create plugin instance return class_ref(plugin_context)
def __init__(self, plugin_provider, settings, application_context, settings_prefix=''): super(PluginManager, self).__init__() self.setObjectName('PluginManager') self._plugin_provider = plugin_provider self._settings = Settings(SettingsProxy(settings), '/'.join( [x for x in ['plugin_manager', settings_prefix] if x != ''])) self._application_context = application_context self._main_window = None self._container_manager = None self._plugin_menu = None self._minimized_dock_widgets_toolbar = None self._global_settings = None self._perspective_settings = None self._plugin_descriptors = None self._running_plugins = {} self._number_of_ongoing_calls = None if self._application_context.options.multi_process or \ self._application_context.options.embed_plugin: try: from qt_gui.plugin_handler_xembed import PluginHandlerXEmbed # noqa: F401 except ImportError: qCritical('PluginManager.__init__() multiprocess-mode only available under linux') exit(-1) # force connection type to queued, to delay the 'reloading' giving the # 'unloading' time to finish self._deferred_reload_plugin_signal.connect( self._reload_plugin_load, type=Qt.QueuedConnection) if self._application_context.provide_app_dbus_interfaces: from qt_gui.plugin_manager_dbus_interface import PluginManagerDBusInterface self._dbus_service = PluginManagerDBusInterface(self, self._application_context)
def load_plugins(): """ Finds all rqt_bag plugins. @return: a list of plugins @rtype: list of functions which return tuples of (MessageView, TimelineRenderer, list of: message type or '*') """ plugins = [] rospack = rospkg.RosPack() to_check = rospack.get_depends_on('rqt_bag', implicit=False) for pkg in to_check: manifest = rospack.get_manifest(pkg) plugin_module_names = manifest.get_export('rqt_bag', 'plugin') if not plugin_module_names: continue elif len(plugin_module_names) != 1: qCritical("Cannot load plugin [%s]: invalid 'plugin' attribute" % (pkg)) continue plugin_module_name = plugin_module_names[0] try: # Load that package's namespace roslib.load_manifest(pkg) # Import specified plugin module plugin_module = __import__(plugin_module_name) for sub_module in plugin_module_name.split('.')[1:]: plugin_module = getattr(plugin_module, sub_module) # Retrieve the function plugins_func = None try: plugins_func = getattr(plugin_module, 'get_rqt_bag_plugins') except AttributeError: pass if plugins_func: plugins.extend(plugins_func()) else: qCritical( "Cannot load plugin [%s]: no 'get_rqt_bag_plugins' attribute" % (plugin_module_name)) except Exception: qCritical("Unable to load plugin [%s] from package [%s]: %s" % (plugin_module_name, pkg, traceback.format_exc())) return plugins
def load(self, plugin_id, plugin_context): # get class reference from plugin descriptor attributes = self._plugin_descriptors[plugin_id].attributes() sys.path.append(os.path.join(attributes['plugin_path'], attributes['library_path'])) try: module = __builtin__.__import__(attributes['module_name'], fromlist=[attributes['class_from_class_type']], level=0) except NotImplementedError as e: qCritical('RosPluginProvider.load(%s): raised an exception:\n%s' % (plugin_id, e)) return None except Exception as e: qCritical('RosPluginProvider.load(%s) exception raised in __builtin__.__import__(%s, [%s]):\n%s' % (plugin_id, attributes['module_name'], attributes['class_from_class_type'], traceback.format_exc())) raise e class_ref = getattr(module, attributes['class_from_class_type'], None) if class_ref is None: qCritical('RosPluginProvider.load(%s): could not find class "%s" in module "%s"' % (plugin_id, attributes['class_from_class_type'], module)) return None # create plugin provider instance without context if class_ref.__init__.func_code.co_argcount == 1 and plugin_context is None: return class_ref() # create plugin instance return class_ref(plugin_context)
def _parse_plugin_xml(self, package_name, plugin_xml): plugin_descriptors = [] if not os.path.isfile(plugin_xml): qCritical('RosPluginProvider._parse_plugin_xml() plugin file "%s" in package "%s" ' 'not found' % (plugin_xml, package_name)) return plugin_descriptors try: root = ElementTree.parse(plugin_xml) except Exception: qCritical('RosPluginProvider._parse_plugin_xml() could not parse "%s" in package "%s"' % (plugin_xml, package_name)) return plugin_descriptors for library_el in root.getiterator('library'): library_path = library_el.attrib['path'] for class_el in library_el.getiterator('class'): # collect common attributes attributes = { 'package_name': package_name, 'plugin_path': os.path.dirname(plugin_xml), 'library_path': library_path, } # add class attributes for key, value in class_el.items(): attributes['class_' + key] = value # skip classes with non-matching _base_class_type class_base_class_type = attributes.get('class_base_class_type', None) if class_base_class_type != self._base_class_type: continue # generate unique identifier plugin_id = package_name if 'class_name' in attributes: plugin_id = plugin_id + '/' + attributes['class_name'] attributes['plugin_id'] = plugin_id # separate module name and class name module_name, class_from_class_type = attributes['class_type'].rsplit('.', 1) attributes['module_name'] = module_name attributes['class_from_class_type'] = class_from_class_type # we can not check if the plugin is available without loading it attributes['not_available'] = '' plugin_descriptor = PluginDescriptor(plugin_id, attributes) # set action attributes (plugin providers might have none) action_attributes, groups = self._parse_plugin(class_el) if len(action_attributes) > 0: plugin_descriptor.set_action_attributes( action_attributes['label'], action_attributes.get('statustip', None), action_attributes.get('icon', None), action_attributes.get('icontype', None), ) # add group attributes for group in groups: plugin_descriptor.add_group_attributes( group['label'], group.get('statustip', None), group.get('icon', None), group.get('icontype', None), ) # add plugin_descriptor to list plugin_descriptors.append(plugin_descriptor) return plugin_descriptors
def _parse_plugin_xml(self, plugin_name, xml_file_name): plugin_descriptors = [] plugin_path = os.path.dirname(os.path.abspath(xml_file_name)) try: root = ElementTree.parse(xml_file_name) except Exception: qCritical( 'RosPluginProvider._parse_plugin_xml() could not parse "%s" of plugin "%s"' % (xml_file_name, plugin_name)) return plugin_descriptors for library_el in root.getiterator('library'): library_path = library_el.attrib['path'] for class_el in library_el.getiterator('class'): # collect common attributes attributes = { 'plugin_name': plugin_name, 'plugin_path': plugin_path, 'library_path': library_path, } # add class attributes for key, value in class_el.items(): attributes['class_' + key] = value # skip classes with non-matching _base_class_type class_base_class_type = attributes.get('class_base_class_type', None) if class_base_class_type != self._base_class_type: continue # generate unique identifier plugin_id = plugin_name if 'class_name' in attributes: plugin_id = plugin_id + '/' + attributes['class_name'] attributes['plugin_id'] = plugin_id # base path to look for module module_base_path = plugin_path if library_path != '': module_base_path = os.path.join(module_base_path, library_path) attributes['module_base_path'] = module_base_path # separate module name and class name module_name, class_from_class_type = os.path.split( attributes['class_type'].replace('.', os.sep)) attributes['module_name'] = module_name.replace(os.sep, '.') attributes['class_from_class_type'] = class_from_class_type # check if plugin is available module_abs_path = os.path.join(module_base_path, module_name) + '.py' attributes[ 'not_available'] = plugin_name if not os.path.exists( module_abs_path) else '' plugin_descriptor = PluginDescriptor(plugin_id, attributes) # set action attributes (plugin providers might have none) action_attributes, groups = self._parse_plugin(class_el) if len(action_attributes) > 0: plugin_descriptor.set_action_attributes( action_attributes['label'], action_attributes.get('statustip', None), action_attributes.get('icon', None), action_attributes.get('icontype', None), ) # add group attributes for group in groups: plugin_descriptor.add_group_attributes( group['label'], group.get('statustip', None), group.get('icon', None), group.get('icontype', None), ) # add plugin_descriptor to list plugin_descriptors.append(plugin_descriptor) return plugin_descriptors
def _parse_plugin_xml(self, package_name, plugin_xml): plugin_descriptors = [] if not os.path.isfile(plugin_xml): qCritical('RosPluginProvider._parse_plugin_xml() plugin file "%s" in package "%s" not found' % (plugin_xml, package_name)) return plugin_descriptors try: root = ElementTree.parse(plugin_xml) except Exception: qCritical('RosPluginProvider._parse_plugin_xml() could not parse "%s" in package "%s"' % (plugin_xml, package_name)) return plugin_descriptors for library_el in root.getiterator('library'): library_path = library_el.attrib['path'] for class_el in library_el.getiterator('class'): # collect common attributes attributes = { 'package_name': package_name, 'plugin_path': os.path.dirname(plugin_xml), 'library_path': library_path, } # add class attributes for key, value in class_el.items(): attributes['class_' + key] = value # skip classes with non-matching _base_class_type class_base_class_type = attributes.get('class_base_class_type', None) if class_base_class_type != self._base_class_type: continue # generate unique identifier plugin_id = package_name if 'class_name' in attributes: plugin_id = plugin_id + '/' + attributes['class_name'] attributes['plugin_id'] = plugin_id # separate module name and class name module_name, class_from_class_type = attributes['class_type'].rsplit('.', 1) attributes['module_name'] = module_name attributes['class_from_class_type'] = class_from_class_type # we can not check if the plugin is available without loading it attributes['not_available'] = '' plugin_descriptor = PluginDescriptor(plugin_id, attributes) # set action attributes (plugin providers might have none) action_attributes, groups = self._parse_plugin(class_el) if len(action_attributes) > 0: plugin_descriptor.set_action_attributes( action_attributes['label'], action_attributes.get('statustip', None), action_attributes.get('icon', None), action_attributes.get('icontype', None), ) # add group attributes for group in groups: plugin_descriptor.add_group_attributes( group['label'], group.get('statustip', None), group.get('icon', None), group.get('icontype', None), ) # add plugin_descriptor to list plugin_descriptors.append(plugin_descriptor) return plugin_descriptors