ros_plugin_provider.py
Go to the documentation of this file.
1 # Copyright (c) 2011, Dirk Thomas, Dorian Scholz, TU Darmstadt
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
6 # are met:
7 #
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following
12 # disclaimer in the documentation and/or other materials provided
13 # with the distribution.
14 # * Neither the name of the TU Darmstadt nor the names of its
15 # contributors may be used to endorse or promote products derived
16 # from this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 # POSSIBILITY OF SUCH DAMAGE.
30 
31 try:
32  import __builtin__
33 except ImportError:
34  import builtins as __builtin__
35 import os
36 import sys
37 import traceback
38 from xml.etree import ElementTree
39 
40 from python_qt_binding.QtCore import qCritical
41 
42 from qt_gui.plugin_descriptor import PluginDescriptor
43 from qt_gui.plugin_provider import PluginProvider
44 
45 
47  """Base class for providing plugins based on the ROS package system."""
48 
49  def __init__(self, export_tag, base_class_type):
50  super(RosPluginProvider, self).__init__()
51  self.setObjectName('RosPluginProvider')
52 
53  self._export_tag = export_tag
54  self._base_class_type = base_class_type
56 
57  def discover(self, discovery_data):
58  """
59  Discover the plugins.
60 
61  The information of the `PluginDescriptor`s are extracted from the plugin manifests.
62  """
63  # search for plugins
64  plugin_descriptors = []
65  plugin_file_list = self._find_plugins(self._export_tag, discovery_data)
66  for package_name, plugin_xml in plugin_file_list:
67  plugin_descriptors += self._parse_plugin_xml(package_name, plugin_xml)
68  # add list of discovered plugins to dictionary of known descriptors index by the plugin id
69  for plugin_descriptor in plugin_descriptors:
70  self._plugin_descriptors[plugin_descriptor.plugin_id()] = plugin_descriptor
71  return plugin_descriptors
72 
73  def load(self, plugin_id, plugin_context):
74  # get class reference from plugin descriptor
75  attributes = self._plugin_descriptors[plugin_id].attributes()
76  sys.path.append(os.path.join(attributes['plugin_path'], attributes['library_path']))
77 
78  try:
79  module = __builtin__.__import__(
80  attributes['module_name'], fromlist=[attributes['class_from_class_type']], level=0)
81  except NotImplementedError as e:
82  qCritical('RosPluginProvider.load(%s): raised an exception:\n%s' % (plugin_id, e))
83  return None
84  except Exception as e:
85  qCritical('RosPluginProvider.load(%s) exception raised in '
86  '__builtin__.__import__(%s, [%s]):\n%s' % (
87  plugin_id, attributes['module_name'],
88  attributes['class_from_class_type'],
89  traceback.format_exc()))
90  raise e
91 
92  class_ref = getattr(module, attributes['class_from_class_type'], None)
93  if class_ref is None:
94  qCritical('RosPluginProvider.load(%s): could not find class "%s" in module "%s"' %
95  (plugin_id, attributes['class_from_class_type'], module))
96  return None
97 
98  # create plugin provider instance without context
99  try:
100  code = class_ref.__init__.func_code
101  except AttributeError:
102  code = class_ref.__init__.__code__
103  if code.co_argcount == 1 and plugin_context is None:
104  return class_ref()
105  # create plugin instance
106  return class_ref(plugin_context)
107 
108  def unload(self, plugin_instance):
109  pass
110 
111  def _find_plugins(self, export_tag, discovery_data):
112  raise NotImplementedError
113 
114  def _parse_plugin_xml(self, package_name, plugin_xml):
115  plugin_descriptors = []
116 
117  if not os.path.isfile(plugin_xml):
118  qCritical('RosPluginProvider._parse_plugin_xml() plugin file "%s" in package "%s" '
119  'not found' % (plugin_xml, package_name))
120  return plugin_descriptors
121 
122  try:
123  root = ElementTree.parse(plugin_xml)
124  except Exception:
125  qCritical('RosPluginProvider._parse_plugin_xml() could not parse "%s" in package "%s"'
126  % (plugin_xml, package_name))
127  return plugin_descriptors
128  for library_el in root.iter('library'):
129  library_path = library_el.attrib['path']
130 
131  for class_el in library_el.iter('class'):
132  # collect common attributes
133  attributes = {
134  'package_name': package_name,
135  'plugin_path': os.path.dirname(plugin_xml),
136  'library_path': library_path,
137  }
138 
139  # add class attributes
140  for key, value in class_el.items():
141  attributes['class_' + key] = value
142 
143  # skip classes with non-matching _base_class_type
144  class_base_class_type = attributes.get('class_base_class_type', None)
145  if class_base_class_type != self._base_class_type:
146  continue
147 
148  # generate unique identifier
149  plugin_id = package_name
150  if 'class_name' in attributes:
151  plugin_id = plugin_id + '/' + attributes['class_name']
152  attributes['plugin_id'] = plugin_id
153 
154  # separate module name and class name
155  module_name, class_from_class_type = attributes['class_type'].rsplit('.', 1)
156  attributes['module_name'] = module_name
157  attributes['class_from_class_type'] = class_from_class_type
158 
159  # we can not check if the plugin is available without loading it
160  attributes['not_available'] = ''
161 
162  plugin_descriptor = PluginDescriptor(plugin_id, attributes)
163 
164  # set action attributes (plugin providers might have none)
165  action_attributes, groups = self._parse_plugin(class_el)
166  if len(action_attributes) > 0:
167  plugin_descriptor.set_action_attributes(
168  action_attributes['label'],
169  action_attributes.get('statustip', None),
170  action_attributes.get('icon', None),
171  action_attributes.get('icontype', None),
172  )
173  # add group attributes
174  for group in groups:
175  plugin_descriptor.add_group_attributes(
176  group['label'],
177  group.get('statustip', None),
178  group.get('icon', None),
179  group.get('icontype', None),
180  )
181 
182  # add plugin_descriptor to list
183  plugin_descriptors.append(plugin_descriptor)
184 
185  return plugin_descriptors
186 
187  def _parse_plugin(self, class_el):
188  # create default plugin descriptor and group
189  plugin_attributes = {}
190  groups = []
191 
192  # update descriptor and group from qtgui tag
193  guiplugin_el = class_el.find('qtgui')
194  if guiplugin_el is not None:
195  plugin_attributes.update(self._parse_action_group(guiplugin_el))
196  for group_el in guiplugin_el.iter('group'):
197  groups.append(self._parse_action_group(group_el))
198 
199  return plugin_attributes, groups
200 
201  def _parse_action_group(self, group_el):
202  attributes = {}
203  for tag in ['label', 'icon', 'statustip']:
204  text = group_el.findtext(tag)
205  if text:
206  attributes[tag] = str(text)
207 
208  icon_el = group_el.find('icon')
209  if icon_el is not None:
210  icon_type_attrib = icon_el.get('type')
211  if icon_type_attrib is not None:
212  attributes['icontype'] = str(icon_type_attrib)
213 
214  return attributes
def _parse_plugin_xml(self, package_name, plugin_xml)
def _find_plugins(self, export_tag, discovery_data)
def load(self, plugin_id, plugin_context)
def __init__(self, export_tag, base_class_type)


rqt_gui
Author(s): Dirk Thomas
autogenerated on Mon Mar 22 2021 02:13:21