40 Modifying rosaction.__init__.py to add functionality for ROS Action.
42 Implements rosaction command-line tools.
44 The code API of the rosaction module is unstable (inheriting the status of
47 (2/4/2013) Most of codes are not tested with actinlib. There's
48 "#NOT_TESTED_FROM_HERE" sign in the code below.
51 from __future__
import print_function
58 from optparse
import OptionParser
83 MAX_DEFAULT_NON_FLOW_ITEMS = 4
85 MODE_ACTION =
'.action'
91 parser = OptionParser(usage=
"usage: ros%s list" % mode[1:])
92 options, args = parser.parse_args(argv[1:])
93 if mode == MODE_ACTION:
96 raise ValueError(
'Unknown mode for iterate_packages: %s' % mode)
98 rospack = rospkg.RosPack()
100 for (p, direc)
in packs:
102 rospy.loginfo(
"%s/%s" % (p, file_))
107 Taken from genpy.message._get_message_or_service_class
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
117 package, base_type = genmsg.package_resource_name(message_type)
119 if base_type ==
'Header':
122 raise ValueError(
"message type is missing package name: %s"
127 pypkg = __import__(
'%s.%s' % (package, type_str))
128 val = getattr(getattr(pypkg, type_str), base_type)
131 except AttributeError:
135 Taken from genpy.message
136 cache for get_message_class
138 _message_class_cache_genpy = {}
143 Taken from genpy.message.get_message_class
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
154 if message_type
in _message_class_cache_genpy:
155 return _message_class_cache_genpy[message_type]
157 reload_on_error=reload_on_error)
159 _message_class_cache_genpy[message_type] = cls
165 Taken from roslib.message._get_message_or_service_class
169 package, base_type = genmsg.package_resource_name(message_type)
171 if base_type ==
'Header':
174 raise ValueError(
"message type is missing package name: %s" %
179 roslib.launcher.load_manifest(package)
181 rospy.loginfo(
'package={} type_str={} base_type={}'.format(
182 package, type_str, base_type))
185 pypkg = __import__(
'%s/%s' % (package, type_str))
187 val = getattr(getattr(pypkg, type_str), base_type)
189 except rospkg.ResourceNotFound:
191 rospy.loginfo(
'_get_action_class except 1')
194 rospy.loginfo(
'_get_action_class except 2')
195 except AttributeError:
197 rospy.loginfo(
'_get_action_class except 3')
201 if val
is None and reload_on_error:
205 val = getattr(getattr(pypkg, type_str), base_type)
211 Taken from roslib.message
214 _action_class_cache = {}
219 Taken from roslib.message.get_action_class
222 if action_type
in _action_class_cache:
223 return _action_class_cache[action_type]
229 reload_on_error=reload_on_error)
231 _action_class_cache[action_type] = cls
237 Iterator for packages that contain actions
238 :param mode: .action, ``str``
240 if mode == MODE_ACTION:
243 raise ValueError(
'Unknown mode for iterate_packages: %s' % mode)
244 pkgs = rospack.list()
246 d = os.path.join(rospack.get_path(p), subdir)
254 Predicate for filtering directory list. matches message files
255 :param f: filename, ``str``
257 return os.path.isfile(f)
and f.endswith(ext)
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``
269 if os.path.isdir(path):
270 resources = [f
for f
in os.listdir(path)
if rfilter(os.path.join(path, f))]
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
282 :returns [str]: message type names
285 result = [x[:-len(ext)]
for x
in types]
288 rospy.loginfo(
'_list_types result={}'.format(result))
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]``
301 rospack = rospkg.RosPack()
302 if mode == MODE_ACTION:
305 raise ValueError(
'Unknown mode for list_types: %s' % mode)
306 path = os.path.join(rospack.get_path(package), subdir)
308 rospy.loginfo(
'list_types package={} mode={} path={}'.format(package, mode,
311 return [genmsg.resource_name(package, t)
317 List actions contained in package
318 :param package: package name, ``str``
319 :returns: list of actions in package, ``[str]``
326 Main entry point for command-line tools (rosaction).
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``
333 if mode == MODE_ACTION:
334 ext, full = mode,
"message type"
338 if len(sys.argv) == 1:
339 rospy.loginfo(fullusage(
'ros' + mode[1:]))
342 command = sys.argv[1]
349 if command ==
'list':
353 elif command ==
'--help':
354 print(fullusage(
'ros' + mode[1:]))
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)
371 except KeyboardInterrupt:
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.
383 if not isinstance(node, yaml.MappingNode):
384 raise yaml.constructor.ConstructorError(
None,
None,
385 "expected a mapping node, but found %s" % node.id,
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",
393 "found unhashable key", key_node.start_mark)
394 value = self.construct_object(value_node, deep=deep)
400 data = collections.OrderedDict()
402 value = self.construct_mapping(node)
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
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):
419 if not (isinstance(node_value, yaml.ScalarNode)
and not node_value.style):
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
426 node.flow_style = best_style
436 returns a single instance of field_type, where field_type can be a
437 message or ros primitive or an flexible size array.
439 field_type = field_type.strip().rstrip(
"[]")
440 if field_type ==
"empty":
442 if not "/" in field_type:
445 if field_type
in [
'byte',
'int8',
'int16',
'int32',
'int64',
446 'char',
'uint8',
'uint16',
'uint32',
'uint64']:
448 elif field_type
in [
'float32',
'float64']:
450 elif field_type
in [
'string']:
452 elif field_type ==
'bool':
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"
461 if default_package
is None:
463 field_type = default_package +
"/" + field_type
464 msg_class = roslib.message.get_message_class(field_type)
465 if (msg_class ==
None):
468 instance = msg_class()
473 field_filter=None, flow_style_=None, fill_arrays_=False):
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
487 def object_representer(dumper, obj):
488 ndict = collections.OrderedDict()
491 if field_filter !=
None:
492 fields = list(field_filter(obj))
494 fields = obj.__slots__
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
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]
512 ndict[key] = [instance]
513 elif not inspect.ismethod(val)
and not inspect.isfunction(val):
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)
526 initial_flow_style =
False
527 if flow_style_ ==
True:
528 initial_flow_style =
True
533 txt = yaml.safe_dump(msg,
535 default_flow_style=initial_flow_style,
552 if prefix !=
None and prefix !=
'':
553 result = prefix + (
"\n" + prefix).join(txt.splitlines())
555 result = txt.rstrip(
'\n')
561 returns a function to use as filter that returns all objects slots except those with names in list.
563 return lambda obj: filter(
lambda slotname:
not slotname
in names, obj.__slots__)
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)
573 yaml.representer.BaseRepresenter.represent_mapping = represent_ordered_mapping
574 yaml.representer.Representer.add_representer(collections.OrderedDict,
575 yaml.representer.SafeRepresenter.represent_dict)
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")
599 options, args = parser.parse_args(args)
604 mode =
".%s" % args[0]
605 message_type = args[1]
607 if options.exclude_slots !=
None and options.exclude_slots.strip() !=
"":
616 if '::' in message_type:
617 if not options.silent:
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:
623 "invalid message type '%s'.\nPlease refer to msg/srv types as 'package_name/Type'." % message_type)
624 if not '/' in message_type:
628 results.append(found)
631 elif len(results) < 1:
634 message_type = results[0]
636 if mode == MODE_ACTION:
637 msg_class = roslib.message.get_message_class(message_type)
638 if (msg_class ==
None):
640 instance = msg_class()
644 prefix=options.prefix,
645 flow_style_=options.flow_style,
646 fill_arrays_=
not options.empty_arrays,
647 field_filter=field_filter)
649 if options.no_hyphens ==
True:
652 return '"' + txt +
'"'
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))
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))
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:
682 from cStringIO
import StringIO
684 from io
import StringIO
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``
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()
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
716 rospack = rospkg.RosPack()
718 for p
in rospack.list():
719 search_path[p] = [os.path.join(rospack.get_path(p),
'msg')]
721 context = genmsg.MsgContext.create_default()
723 spec = genmsg.load_msg_by_type(context, type_, search_path)
724 genmsg.load_depends(context, spec, search_path)
725 except Exception
as e:
737 Predicate for filtering directory list. matches message files
738 :param f: filename, ``str``
740 return os.path.isfile(f)
and f.endswith(ext)
746 Iterator for all packages that contain a message matching base_type
748 :param base_type: message base type to match, e.g. 'String' would match std_msgs/String, ``str``
751 if os.path.isfile(os.path.join(path,
"%s%s" % (base_type, mode))):
752 yield genmsg.resource_name(p, base_type)
756 options, args = parser.parse_args(sys.argv[2:])
761 arg = sys.stdin.readline().strip()
765 parser.error(
"you may only specify one %s" % full)
766 return options, args[0]
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")
779 if arg.endswith(mode):
780 arg = arg[:-(len(mode))]
786 " does not understand C++-style namespaces (i.e. '::').\n " +
787 "Please refer to msg/srv types as 'package_name/Type'.")
790 "invalid message type '%s'.\nPlease refer to msg/srv types as 'package_name/Type'." % arg)
792 bag_file = options.bag
793 if not os.path.exists(bag_file):
795 for topic, msg, t
in rosbag.Bag(bag_file).read_messages(raw=
True):
796 datatype, _, _, _, pytype = msg
798 print(
get_msg_text(datatype, options.raw, pytype._full_text))
801 rospack = rospkg.RosPack()
806 print(
"[%s]:" % found)
812 if mode == MODE_ACTION:
813 msg_class = roslib.message.get_message_class(type_)
815 msg_class = roslib.message.get_service_class(type_)
817 raise IOError(
"cannot load [%s]" % (type_))
818 if msg_class
is not None:
819 return msg_class._md5sum
821 raise IOError(
"cannot load [%s]" % (type_))
825 parser = OptionParser(usage=
"usage: ros%s md5 <%s>" % (mode[1:], full))
833 print(
"Cannot locate [%s]" % arg, file=sys.stderr)
835 rospack = rospkg.RosPack()
837 for found
in matches:
840 print(
"[%s]: %s" % (found, md5))
842 print(
"Cannot locate [%s]" % found, file=sys.stderr)
844 print(
"No messages matching the name [%s]" % arg, file=sys.stderr)
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")
854 if options.single_line:
856 print(joinstring.join(
list_types(arg, mode=mode)))
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()
869 if options.single_line:
873 print(joinstring.join(p1))
878 Prints contents of msg/srv file
879 :param mode: MODE_ACTION or MODE_SRV, ``str``
881 if mode == MODE_ACTION: