rosaction.py
Go to the documentation of this file.
1 # Software License Agreement (BSD License)
2 #
3 # Copyright (c) 2012, Willow Garage, Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following
14 # disclaimer in the documentation and/or other materials provided
15 # with the distribution.
16 # * Neither the name of Willow Garage, Inc. nor the names of its
17 # contributors may be used to endorse or promote products derived
18 # from this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32 
33 # Author: Isaac Saito under the influence of rosmsg.__init__.py
34 
35 # TODO 3/11/2013 (Isaac) This is moved from rqt_action pkg due to circular
36 # dependency issue. This rosaction is supposed to be moved (pull requested) to
37 # actionlib in the future.
38 
39 """
40 Modifying rosaction.__init__.py to add functionality for ROS Action.
41 
42 Implements rosaction command-line tools.
43 
44 The code API of the rosaction module is unstable (inheriting the status of
45 rosmsg)
46 
47 (2/4/2013) Most of codes are not tested with actinlib. There's
48 "#NOT_TESTED_FROM_HERE" sign in the code below.
49 """
50 
51 from __future__ import print_function
52 
53 import collections
54 import inspect
55 import os
56 import sys
57 import yaml
58 from optparse import OptionParser
59 
60 import genmsg
61 # import genpy
62 import rosbag
63 import roslib
64 import roslib.message
65 import rospkg
66 import rospy
67 
68 
69 class ROSActionException(Exception):
70  pass
71 
72 
73 class ROSActionProtoException(Exception):
74  pass
75 
76 
77 class RosActionProtoArgsException(Exception):
78  pass
79 
80 # If flowtype chosen is default, instead use flow-style
81 # False except if meeting objects or arrays with more than
82 # this size of sub-elements
83 MAX_DEFAULT_NON_FLOW_ITEMS = 4
84 
85 MODE_ACTION = '.action'
86 
87 
88 def rosaction_cmd_list(mode, full, argv=None):
89  if argv is None:
90  argv = sys.argv[1:]
91  parser = OptionParser(usage="usage: ros%s list" % mode[1:])
92  options, args = parser.parse_args(argv[1:])
93  if mode == MODE_ACTION:
94  subdir = 'action'
95  else:
96  raise ValueError('Unknown mode for iterate_packages: %s' % mode)
97 
98  rospack = rospkg.RosPack()
99  packs = sorted([x for x in iterate_packages(rospack, mode)])
100  for (p, direc) in packs:
101  for file_ in _list_types(direc, subdir, mode):
102  rospy.loginfo("%s/%s" % (p, file_))
103 
104 
105 def _get_action_class_genpy(type_str, message_type, reload_on_error=False):
106  """
107  Taken from genpy.message._get_message_or_service_class
108 
109  Utility for retrieving message/service class instances. Used by
110  get_message_class and get_service_class.
111  :param type_str: 'msg' or 'srv', ``str``
112  :param message_type: type name of message/service, ``str``
113  :returns: Message/Service for message/service type or None, ``class``
114  :raises: :exc:`ValueError` If message_type is invalidly specified
115  """
116  # parse package and local type name for import
117  package, base_type = genmsg.package_resource_name(message_type)
118  if not package:
119  if base_type == 'Header':
120  package = 'std_msgs'
121  else:
122  raise ValueError("message type is missing package name: %s"
123  % str(message_type))
124  pypkg = val = None
125  try:
126  # import the package and return the class
127  pypkg = __import__('%s.%s' % (package, type_str))
128  val = getattr(getattr(pypkg, type_str), base_type)
129  except ImportError:
130  val = None
131  except AttributeError:
132  val = None
133 
134 """
135 Taken from genpy.message
136 cache for get_message_class
137 """
138 _message_class_cache_genpy = {}
139 
140 
141 def get_message_class_genpy(message_type, reload_on_error=False):
142  """
143  Taken from genpy.message.get_message_class
144 
145  Get the message class. NOTE: this function maintains a
146  local cache of results to improve performance.
147  :param message_type: type name of message, ``str``
148  :param reload_on_error: (optional). Attempt to reload the Python
149  module if unable to load message the first time. Defaults to
150  False. This is necessary if messages are built after the first load.
151  :returns: Message class for message/service type, ``Message class``
152  :raises :exc:`ValueError`: if message_type is invalidly specified
153  """
154  if message_type in _message_class_cache_genpy:
155  return _message_class_cache_genpy[message_type]
156  cls = _get_action_class_genpy('action', message_type,
157  reload_on_error=reload_on_error)
158  if cls:
159  _message_class_cache_genpy[message_type] = cls
160  return cls
161 
162 
163 def _get_action_class(type_str, message_type, reload_on_error=False):
164  """
165  Taken from roslib.message._get_message_or_service_class
166  """
167 
168  # parse package and local type name for import
169  package, base_type = genmsg.package_resource_name(message_type)
170  if not package:
171  if base_type == 'Header':
172  package = 'std_msgs'
173  else:
174  raise ValueError("message type is missing package name: %s" %
175  str(message_type))
176  pypkg = val = None
177  try:
178  # bootstrap our sys.path
179  roslib.launcher.load_manifest(package)
180 
181  rospy.loginfo('package={} type_str={} base_type={}'.format(
182  package, type_str, base_type))
183 
184  # import the package and return the class
185  pypkg = __import__('%s/%s' % (package, type_str))
186  # pypkg = __import__('%s.%s'%(package, type_str))
187  val = getattr(getattr(pypkg, type_str), base_type)
188 
189  except rospkg.ResourceNotFound:
190  val = None
191  rospy.loginfo('_get_action_class except 1')
192  except ImportError:
193  val = None
194  rospy.loginfo('_get_action_class except 2')
195  except AttributeError:
196  val = None
197  rospy.loginfo('_get_action_class except 3')
198 
199  # this logic is mainly to support rosh, so that a user doesn't
200  # have to exit a shell just because a message wasn't built yet
201  if val is None and reload_on_error:
202  try:
203  if pypkg:
204  reload(pypkg)
205  val = getattr(getattr(pypkg, type_str), base_type)
206  except:
207  val = None
208  return val
209 
210 """
211 Taken from roslib.message
212 """
213 # cache for get_message_class
214 _action_class_cache = {}
215 
216 
217 def get_action_class(action_type, reload_on_error=False):
218  """
219  Taken from roslib.message.get_action_class
220  """
221 
222  if action_type in _action_class_cache:
223  return _action_class_cache[action_type]
224  # try w/o bootstrapping
225  cls = get_message_class_genpy(action_type, reload_on_error=reload_on_error)
226  if cls is None:
227  # try old loader w/ bootstrapping
228  cls = _get_action_class('action', action_type,
229  reload_on_error=reload_on_error)
230  if cls:
231  _action_class_cache[action_type] = cls
232  return cls
233 
234 
235 def iterate_packages(rospack, mode):
236  """
237  Iterator for packages that contain actions
238  :param mode: .action, ``str``
239  """
240  if mode == MODE_ACTION:
241  subdir = 'action'
242  else:
243  raise ValueError('Unknown mode for iterate_packages: %s' % mode)
244  pkgs = rospack.list()
245  for p in pkgs:
246  d = os.path.join(rospack.get_path(p), subdir)
247  if os.path.isdir(d):
248  yield p, d
249 
250 
251 def _msg_filter(ext):
252  def mfilter(f):
253  """
254  Predicate for filtering directory list. matches message files
255  :param f: filename, ``str``
256  """
257  return os.path.isfile(f) and f.endswith(ext)
258  return mfilter
259 
260 
261 def _list_resources(path, rfilter=os.path.isfile):
262  """
263  List resources in a package directory within a particular
264  subdirectory. This is useful for listing messages, services, etc...
265  :param rfilter: resource filter function that returns true if filename is
266  the desired resource type, ``fn(filename)->bool``
267  """
268  resources = []
269  if os.path.isdir(path):
270  resources = [f for f in os.listdir(path) if rfilter(os.path.join(path, f))]
271  else:
272  resources = []
273  return resources
274 
275 
276 def _list_types(path, subdir, ext):
277  """
278  List all messages in the specified package
279  :param package str: name of package to search
280  :param include_depends bool: if True, will also list messages in package
281  dependencies
282  :returns [str]: message type names
283  """
284  types = _list_resources(path, _msg_filter(ext))
285  result = [x[:-len(ext)] for x in types]
286  result.sort()
287 
288  rospy.loginfo('_list_types result={}'.format(result))
289 
290  return result
291 
292 
293 def list_types(package, mode=MODE_ACTION):
294  """
295  Lists msg/srvs contained in package
296  :param package: package name, ``str``
297  :param mode: MODE_ACTION. Defaults to msgs, ``str``
298  :returns: list of msgs/srv in package, ``[str]``
299  """
300 
301  rospack = rospkg.RosPack()
302  if mode == MODE_ACTION:
303  subdir = 'action'
304  else:
305  raise ValueError('Unknown mode for list_types: %s' % mode)
306  path = os.path.join(rospack.get_path(package), subdir)
307 
308  rospy.loginfo('list_types package={} mode={} path={}'.format(package, mode,
309  path))
310 
311  return [genmsg.resource_name(package, t)
312  for t in _list_types(path, subdir, mode)]
313 
314 
315 def list_actions(package):
316  """
317  List actions contained in package
318  :param package: package name, ``str``
319  :returns: list of actions in package, ``[str]``
320  """
321  return list_types(package, mode=MODE_ACTION)
322 
323 
324 def rosactionmain(mode=MODE_ACTION):
325  """
326  Main entry point for command-line tools (rosaction).
327 
328  rosaction can interact with either ros messages or ros services. The mode
329  param indicates which
330  :param mode: MODE_ACTION or MODE_SRV, ``str``
331  """
332  try:
333  if mode == MODE_ACTION:
334  ext, full = mode, "message type"
335  else:
336  raise ROSActionException("Invalid mode: %s" % mode)
337 
338  if len(sys.argv) == 1:
339  rospy.loginfo(fullusage('ros' + mode[1:]))
340  sys.exit(0)
341 
342  command = sys.argv[1]
343 # if command == 'show':
344 # rosaction_cmd_show(ext, full)
345 # elif command == 'package':
346 # rosaction_cmd_package(ext, full)
347 # elif command == 'packages':
348 # rosaction_cmd_packages(ext, full)
349  if command == 'list':
350  rosaction_cmd_list(ext, full)
351 # elif command == 'md5':
352 # rosaction_cmd_md5(ext, full)
353  elif command == '--help':
354  print(fullusage('ros' + mode[1:]))
355  sys.exit(0)
356  else:
357  print(fullusage('ros' + mode[1:]))
358  sys.exit(getattr(os, 'EX_USAGE', 1))
359  except KeyError as e:
360  print("Unknown message type: %s" % e, file=sys.stderr)
361  sys.exit(getattr(os, 'EX_USAGE', 1))
362  except rospkg.ResourceNotFound as e:
363  print("Invalid package: %s" % e, file=sys.stderr)
364  sys.exit(getattr(os, 'EX_USAGE', 1))
365  except ValueError as e:
366  print("Invalid type: '%s'" % e, file=sys.stderr)
367  sys.exit(getattr(os, 'EX_USAGE', 1))
368  except ROSActionException as e:
369  print(str(e), file=sys.stderr)
370  sys.exit(1)
371  except KeyboardInterrupt:
372  pass
373 
374 """
375 "#NOT_TESTED_FROM_HERE"----------------------------------------
376 From here are what are copied from __init__.py that I don't know yet
377 if they are necessary/useful.
378 """
379  # copied from the web, recipe for ordered yaml output ######
380 
381 
382 def construct_ordered_mapping(self, node, deep=False):
383  if not isinstance(node, yaml.MappingNode):
384  raise yaml.constructor.ConstructorError(None, None,
385  "expected a mapping node, but found %s" % node.id,
386  node.start_mark)
387  mapping = collections.OrderedDict()
388  for key_node, value_node in node.value:
389  key = self.construct_object(key_node, deep=deep)
390  if not isinstance(key, collections.Hashable):
391  raise yaml.constructor.ConstructorError("while constructing a mapping",
392  node.start_mark,
393  "found unhashable key", key_node.start_mark)
394  value = self.construct_object(value_node, deep=deep)
395  mapping[key] = value
396  return mapping
397 
398 
400  data = collections.OrderedDict()
401  yield data
402  value = self.construct_mapping(node)
403  data.update(value)
404 
405 
406 def represent_ordered_mapping(self, tag, mapping, flow_style=None):
407  value = []
408  node = yaml.MappingNode(tag, value, flow_style=flow_style)
409  if self.alias_key is not None:
410  self.represented_objects[self.alias_key] = node
411  best_style = True
412  if hasattr(mapping, 'items'):
413  mapping = list(mapping.items())
414  for item_key, item_value in mapping:
415  node_key = self.represent_data(item_key)
416  node_value = self.represent_data(item_value)
417  if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style):
418  best_style = False
419  if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style):
420  best_style = False
421  value.append((node_key, node_value))
422  if flow_style is None:
423  if self.default_flow_style is not None:
424  node.flow_style = self.default_flow_style
425  else:
426  node.flow_style = best_style
427  return node
428 
429 # ==================================
430 # end recipe for ordered yaml output
431 # ==================================
432 
433 
434 def get_array_type_instance(field_type, default_package=None):
435  """
436  returns a single instance of field_type, where field_type can be a
437  message or ros primitive or an flexible size array.
438  """
439  field_type = field_type.strip().rstrip("[]")
440  if field_type == "empty":
441  return None
442  if not "/" in field_type:
443  # is either built-in, Header, or in same package
444  # it seems built-in types get a priority
445  if field_type in ['byte', 'int8', 'int16', 'int32', 'int64',
446  'char', 'uint8', 'uint16', 'uint32', 'uint64']:
447  return 0
448  elif field_type in ['float32', 'float64']:
449  return 0
450  elif field_type in ['string']:
451  return ""
452  elif field_type == 'bool':
453  return False
454  elif field_type == 'time':
455  field_type = "std_msgs/Time"
456  elif field_type == 'duration':
457  field_type = "std_msgs/Duration"
458  elif field_type == 'Header':
459  field_type = "std_msgs/Header"
460  else:
461  if default_package is None:
462  return None
463  field_type = default_package + "/" + field_type
464  msg_class = roslib.message.get_message_class(field_type)
465  if (msg_class == None):
466  # not important enough to raise exception?
467  return None
468  instance = msg_class()
469  return instance
470 
471 
472 def get_yaml_for_msg(msg, prefix='', time_offset=None, current_time=None,
473  field_filter=None, flow_style_=None, fill_arrays_=False):
474  """
475  Builds a YAML string of message.
476  @param msg: A object, dict or array
477  @param flow_style_: if True, produces one line with brackets, if false uses multiple lines with indentation, if None uses both using heuristics
478  @param prefix: prefixes all lines with this string
479  @param fill_arrays_: if True, for all flexible size arrays an element will be generated
480  @param current_time: currently not used. Only provided for API compatibility. current_time passes in the current time with respect to the message.
481  @type current_time: Time
482  @param field_filter: filter the fields that are strified for Messages.
483  @type field_filter: fn(Message)->iter(str)
484  @type flow_style_: bool
485  @return: a string
486  """
487  def object_representer(dumper, obj):
488  ndict = collections.OrderedDict()
489  index = 0
490  # allow caller to select which fields of message are strified
491  if field_filter != None:
492  fields = list(field_filter(obj))
493  else:
494  fields = obj.__slots__
495  for key in fields:
496  if not key.startswith('_'):
497  val = getattr(obj, key)
498  if type(val) == list and len(val) > MAX_DEFAULT_NON_FLOW_ITEMS:
499  dumper.default_flow_style = flow_style_
500  if time_offset is not None and isinstance(val, rospy.Time):
501  ndict[key] = val - time_offset
502  # create initial array element (e.g. for code completion)
503  elif fill_arrays_ == True and val == []:
504  message_type = obj._slot_types[index]
505  if (obj._type != None) and "/" in obj._type:
506  def_pack = obj._type.split("/")[0]
507  instance = get_array_type_instance(message_type, default_package=def_pack)
508  if instance == None:
509  # not important enough to raise exception?
510  ndict[key] = val
511  else:
512  ndict[key] = [instance]
513  elif not inspect.ismethod(val) and not inspect.isfunction(val):
514  ndict[key] = val
515  index += 1
516  # as a hack, we improve the heuristics of pyyaml and say with less than 5
517  # objects, no need for brackets
518  if len(ndict) > MAX_DEFAULT_NON_FLOW_ITEMS:
519  dumper.default_flow_style = flow_style_
520  return dumper.represent_dict(ndict)
521  yaml.representer.SafeRepresenter.add_representer(None, object_representer)
522 
523  # we force False over None here and set the style in dumper, to
524  # avoid unecessary outer brackets pyyaml chooses e.g. to
525  # represent msg Int32 as "{data: 0}"
526  initial_flow_style = False
527  if flow_style_ == True:
528  initial_flow_style = True
529 
530  # need to set default flow style True for bash prototype
531  # means will generate one line with [] and {} brackets
532  # bash needs bracket notation for rostopic pub
533  txt = yaml.safe_dump(msg,
534  # None, True, False (None chooses a compromise)
535  default_flow_style=initial_flow_style,
536  # Can be None, '', '\'', '"', '|', '>'.
537  default_style='',
538  # indent=2, #>=2, indentation depth
539  # line_break=?,
540  # allow_unicode=?,
541  # if true writes plenty of tags
542  # canonical = False,
543  # version={}?,
544  # width=40,
545  # encoding=?,
546  # tags={}?,
547  # when True, produces --- at start
548  # explicit_start=False,
549  # when True, produces ... at end
550  # explicit_end=False
551  )
552  if prefix != None and prefix != '':
553  result = prefix + ("\n" + prefix).join(txt.splitlines())
554  else:
555  result = txt.rstrip('\n')
556  return result
557 
558 
560  """
561  returns a function to use as filter that returns all objects slots except those with names in list.
562  """
563  return lambda obj: filter(lambda slotname: not slotname in names, obj.__slots__)
564 
565 
567  if "OrderedDict" in collections.__dict__:
568  yaml.constructor.BaseConstructor.construct_mapping = construct_ordered_mapping
569  yaml.constructor.Constructor.add_constructor(
570  'tag:yaml.org,2002:map',
571  construct_yaml_map_with_ordered_dict)
572 
573  yaml.representer.BaseRepresenter.represent_mapping = represent_ordered_mapping
574  yaml.representer.Representer.add_representer(collections.OrderedDict,
575  yaml.representer.SafeRepresenter.represent_dict)
576 
577 
580  parser = OptionParser(usage="usage: rosactionproto msg/srv [options]",
581  description="Produces output or a msg or service request, intended for tab completion support.")
582  parser.add_option("-f", "--flow_style",
583  dest="flow_style", type="int", default=None, action="store",
584  help="if 1 always use brackets, if 0 never use brackets. Default is a heuristic mix.")
585  parser.add_option("-e", "--empty-arrays",
586  dest="empty_arrays", default=False, action="store_true",
587  help="if true flexible size arrays are not filled with default instance")
588  parser.add_option("-s", "--silent",
589  dest="silent", default=False, action="store_true",
590  help="if true supresses all error messages")
591  parser.add_option("-p", "--prefix", metavar="prefix", default="",
592  help="prefix to print before each line, can be used for indent")
593  parser.add_option("-H", "--no-hyphens",
594  dest="no_hyphens", default="", action="store_true",
595  help="if true output has no outer hyphens")
596  parser.add_option("-x", "--exclude-slots", metavar="exclude_slots", default="",
597  help="comma separated list of slot names not to print")
598 
599  options, args = parser.parse_args(args)
600 
601  try:
602  if len(args) < 2:
603  raise RosActionProtoArgsException("Insufficient arguments")
604  mode = ".%s" % args[0]
605  message_type = args[1]
606  field_filter = None
607  if options.exclude_slots != None and options.exclude_slots.strip() != "":
608  field_filter = create_names_filter(options.exclude_slots.split(','))
609 
610  # possible extentions: options for
611  # - target language
612  # - initial values for standard types
613  # - get partial message (subtree)
614 
615  # try to catch the user specifying code-style types and error
616  if '::' in message_type:
617  if not options.silent:
618  parser.error(
619  "rosactionproto does not understand C++-style namespaces (i.e. '::').\nPlease refer to msg/srv types as 'package_name/Type'.")
620  elif '.' in message_type:
621  if not options.silent:
622  parser.error(
623  "invalid message type '%s'.\nPlease refer to msg/srv types as 'package_name/Type'." % message_type)
624  if not '/' in message_type:
625  # if only one such msg or srv exists, use it
626  results = []
627  for found in rosaction_search(rospkg.RosPack(), mode, message_type):
628  results.append(found)
629  if len(results) > 1:
630  raise ROSActionProtoException("Ambiguous message name %s" % message_type)
631  elif len(results) < 1:
632  raise ROSActionProtoException("Unknown message name %s" % message_type)
633  else:
634  message_type = results[0]
635 
636  if mode == MODE_ACTION:
637  msg_class = roslib.message.get_message_class(message_type)
638  if (msg_class == None):
639  raise ROSActionProtoException("Unknown message class: %s" % message_type)
640  instance = msg_class()
641  else:
642  raise ROSActionProtoException("Invalid mode: %s" % mode)
643  txt = get_yaml_for_msg(instance,
644  prefix=options.prefix,
645  flow_style_=options.flow_style,
646  fill_arrays_=not options.empty_arrays,
647  field_filter=field_filter)
648 
649  if options.no_hyphens == True:
650  return txt
651  else:
652  return '"' + txt + '"'
653 
654  except KeyError as e:
655  if not options.silent:
656  sys.stderr.write("Unknown message type: %s" % e, file=sys.stderr)
657  sys.exit(getattr(os, 'EX_USAGE', 1))
658  # except rospkg.InvalidROSPkgException as e:
659  # if not options.silent:
660  # print(file=sys.stderr, "Invalid package: '%s'"%e)
661  # sys.exit(getattr(os, 'EX_USAGE', 1))
662  except ValueError as e:
663  if not options.silent:
664  sys.stderr.write("Invalid type: '%s'" % e)
665  sys.exit(getattr(os, 'EX_USAGE', 1))
666  except ROSActionProtoException as e:
667  if not options.silent:
668  sys.stderr.write(str(e))
669  sys.exit(1)
670  except RosActionProtoArgsException as e:
671  if not options.silent:
672  sys.stderr.write("%s" % e)
673  sys.exit(getattr(os, 'EX_USAGE', 1))
674  except KeyboardInterrupt:
675  pass
676 
677 # ===============
678 # Start of rosmsg
679 # ===============
680 
681 try:
682  from cStringIO import StringIO # Python 2.x
683 except ImportError:
684  from io import StringIO # Python 3.x
685 
686 
687 def spec_to_str(action_context, spec, buff=None, indent=''):
688  """
689  Convert spec into a string representation. Helper routine for MsgSpec.
690  :param indent: internal use only, ``str``
691  :param buff: internal use only, ``StringIO``
692  :returns: string representation of spec, ``str``
693  """
694  if buff is None:
695  buff = StringIO()
696  for c in spec.constants:
697  buff.write("%s%s %s=%s\n" % (indent, c.type, c.name, c.val_text))
698  for type_, name in zip(spec.types, spec.names):
699  buff.write("%s%s %s\n" % (indent, type_, name))
700  base_type = genmsg.msgs.bare_msg_type(type_)
701  if not base_type in genmsg.msgs.BUILTIN_TYPES:
702  subspec = msg_context.get_registered(base_type)
703  spec_to_str(msg_context, subspec, buff, indent + ' ')
704  return buff.getvalue()
705 
706 
707 def get_msg_text(type_, raw=False, rospack=None):
708  """
709  Get .msg file for type_ as text
710  :param type_: message type, ``str``
711  :param raw: if True, include comments and whitespace (default False), ``bool``
712  :returns: text of .msg file, ``str``
713  :raises :exc:`ROSActionException` If type_ is unknown
714  """
715  if rospack is None:
716  rospack = rospkg.RosPack()
717  search_path = {}
718  for p in rospack.list():
719  search_path[p] = [os.path.join(rospack.get_path(p), 'msg')]
720 
721  context = genmsg.MsgContext.create_default()
722  try:
723  spec = genmsg.load_msg_by_type(context, type_, search_path)
724  genmsg.load_depends(context, spec, search_path)
725  except Exception as e:
726  raise ROSActionException("Unable to load msg [%s]: %s" % (type_, e))
727 
728  if raw:
729  return spec.text
730  else:
731  return spec_to_str(context, spec)
732 
733 
734 def _msg_filter(ext):
735  def mfilter(f):
736  """
737  Predicate for filtering directory list. matches message files
738  :param f: filename, ``str``
739  """
740  return os.path.isfile(f) and f.endswith(ext)
741  return mfilter
742 
743 
744 def rosaction_search(rospack, mode, base_type):
745  """
746  Iterator for all packages that contain a message matching base_type
747 
748  :param base_type: message base type to match, e.g. 'String' would match std_msgs/String, ``str``
749  """
750  for p, path in iterate_packages(rospack, mode):
751  if os.path.isfile(os.path.join(path, "%s%s" % (base_type, mode))):
752  yield genmsg.resource_name(p, base_type)
753 
754 
755 def _stdin_arg(parser, full):
756  options, args = parser.parse_args(sys.argv[2:])
757  # read in args from stdin pipe if not present
758  if not args:
759  arg = None
760  while not arg:
761  arg = sys.stdin.readline().strip()
762  return options, arg
763  else:
764  if len(args) > 1:
765  parser.error("you may only specify one %s" % full)
766  return options, args[0]
767 
768 
769 def rosaction_cmd_show(mode, full):
770  cmd = "ros%s" % (mode[1:])
771  parser = OptionParser(usage="usage: %s show [options] <%s>" % (cmd, full))
772  parser.add_option("-r", "--raw",
773  dest="raw", default=False, action="store_true",
774  help="show raw message text, including comments")
775  parser.add_option("-b", "--bag",
776  dest="bag", default=None,
777  help="show message from .bag file", metavar="BAGFILE")
778  options, arg = _stdin_arg(parser, full)
779  if arg.endswith(mode):
780  arg = arg[:-(len(mode))]
781 
782  # try to catch the user specifying code-style types and error
783  if '::' in arg:
784  parser.error(
785  cmd +
786  " does not understand C++-style namespaces (i.e. '::').\n " +
787  "Please refer to msg/srv types as 'package_name/Type'.")
788  elif '.' in arg:
789  parser.error(
790  "invalid message type '%s'.\nPlease refer to msg/srv types as 'package_name/Type'." % arg)
791  if options.bag:
792  bag_file = options.bag
793  if not os.path.exists(bag_file):
794  raise ROSActionException("ERROR: bag file [%s] does not exist" % bag_file)
795  for topic, msg, t in rosbag.Bag(bag_file).read_messages(raw=True):
796  datatype, _, _, _, pytype = msg
797  if datatype == arg:
798  print(get_msg_text(datatype, options.raw, pytype._full_text))
799  break
800  else:
801  rospack = rospkg.RosPack()
802  if '/' in arg: # package specified
803  rosaction_debug(rospack, mode, arg, options.raw)
804  else:
805  for found in rosaction_search(rospack, mode, arg):
806  print("[%s]:" % found)
807  rosaction_debug(rospack, mode, found, options.raw)
808 
809 
810 def rosaction_md5(mode, type_):
811  try:
812  if mode == MODE_ACTION:
813  msg_class = roslib.message.get_message_class(type_)
814  else:
815  msg_class = roslib.message.get_service_class(type_)
816  except ImportError:
817  raise IOError("cannot load [%s]" % (type_))
818  if msg_class is not None:
819  return msg_class._md5sum
820  else:
821  raise IOError("cannot load [%s]" % (type_))
822 
823 
824 def rosaction_cmd_md5(mode, full):
825  parser = OptionParser(usage="usage: ros%s md5 <%s>" % (mode[1:], full))
826  options, arg = _stdin_arg(parser, full)
827 
828  if '/' in arg: # package specified
829  try:
830  md5 = rosaction_md5(mode, arg)
831  print(md5)
832  except IOError:
833  print("Cannot locate [%s]" % arg, file=sys.stderr)
834  else:
835  rospack = rospkg.RosPack()
836  matches = [m for m in rosaction_search(rospack, mode, arg)]
837  for found in matches:
838  try:
839  md5 = rosaction_md5(mode, found)
840  print("[%s]: %s" % (found, md5))
841  except IOError:
842  print("Cannot locate [%s]" % found, file=sys.stderr)
843  if not matches:
844  print("No messages matching the name [%s]" % arg, file=sys.stderr)
845 
846 
847 def rosaction_cmd_package(mode, full):
848  parser = OptionParser(usage="usage: ros%s package <package>" % mode[1:])
849  parser.add_option("-s",
850  dest="single_line", default=False, action="store_true",
851  help="list all msgs on a single line")
852  options, arg = _stdin_arg(parser, full)
853  joinstring = '\n'
854  if options.single_line:
855  joinstring = ' '
856  print(joinstring.join(list_types(arg, mode=mode)))
857 
858 
859 def rosaction_cmd_packages(mode, full, argv=None):
860  if argv is None:
861  argv = sys.argv[1:]
862  parser = OptionParser(usage="usage: ros%s packages" % mode[1:])
863  parser.add_option("-s",
864  dest="single_line", default=False, action="store_true",
865  help="list all packages on a single line")
866  options, args = parser.parse_args(argv[1:])
867  rospack = rospkg.RosPack()
868  joinstring = '\n'
869  if options.single_line:
870  joinstring = ' '
871  p1 = [p for p, _ in iterate_packages(rospack, mode)]
872  p1.sort()
873  print(joinstring.join(p1))
874 
875 
876 def rosaction_debug(rospack, mode, type_, raw=False):
877  """
878  Prints contents of msg/srv file
879  :param mode: MODE_ACTION or MODE_SRV, ``str``
880  """
881  if mode == MODE_ACTION:
882  print(get_msg_text(type_, raw=raw, rospack=rospack))
883  else:
884  raise ROSActionException("Invalid mode for debug: %s" % mode)
def get_yaml_for_msg(msg, prefix='', time_offset=None, current_time=None, field_filter=None, flow_style_=None, fill_arrays_=False)
Definition: rosaction.py:473
def _list_resources(path, rfilter=os.path.isfile)
Definition: rosaction.py:261
def rosaction_cmd_show(mode, full)
Definition: rosaction.py:769
def create_names_filter(names)
Definition: rosaction.py:559
def construct_ordered_mapping(self, node, deep=False)
Definition: rosaction.py:382
def _get_action_class(type_str, message_type, reload_on_error=False)
Definition: rosaction.py:163
def rosactionmain(mode=MODE_ACTION)
Definition: rosaction.py:324
def _get_action_class_genpy(type_str, message_type, reload_on_error=False)
Definition: rosaction.py:105
def construct_yaml_map_with_ordered_dict(self, node)
Definition: rosaction.py:399
def rosaction_cmd_list(mode, full, argv=None)
Definition: rosaction.py:88
def rosaction_cmd_prototype(args)
Definition: rosaction.py:578
def get_action_class(action_type, reload_on_error=False)
Definition: rosaction.py:217
def get_array_type_instance(field_type, default_package=None)
Definition: rosaction.py:434
def rosaction_cmd_packages(mode, full, argv=None)
Definition: rosaction.py:859
def rosaction_cmd_package(mode, full)
Definition: rosaction.py:847
def list_types(package, mode=MODE_ACTION)
Definition: rosaction.py:293
def get_msg_text(type_, raw=False, rospack=None)
Definition: rosaction.py:707
def rosaction_cmd_md5(mode, full)
Definition: rosaction.py:824
def rosaction_md5(mode, type_)
Definition: rosaction.py:810
def _list_types(path, subdir, ext)
Definition: rosaction.py:276
def rosaction_search(rospack, mode, base_type)
Definition: rosaction.py:744
def list_actions(package)
Definition: rosaction.py:315
def represent_ordered_mapping(self, tag, mapping, flow_style=None)
Definition: rosaction.py:406
def spec_to_str(action_context, spec, buff=None, indent='')
Definition: rosaction.py:687
def rosaction_debug(rospack, mode, type_, raw=False)
Definition: rosaction.py:876
def get_message_class_genpy(message_type, reload_on_error=False)
Definition: rosaction.py:141
def iterate_packages(rospack, mode)
Definition: rosaction.py:235
def _stdin_arg(parser, full)
Definition: rosaction.py:755


rqt_py_common
Author(s): Dorian Scholz, Isaac Saito, Dirk Thomas
autogenerated on Mon Mar 22 2021 02:13:26