def _param_tag(self, tag, context, ros_config, force_local=False, verbose=True): """ @param force_local: if True, param must be added to context instead of ros_config @type force_local: bool """ try: self._check_attrs(tag, context, ros_config, XmlLoader.PARAM_ATTRS) # compute name and value ptype = (tag.getAttribute('type') or 'auto').lower().strip() vals = self.opt_attrs(tag, context, ('value', 'textfile', 'binfile', 'command')) if len([v for v in vals if v is not None]) != 1: raise XmlParseException( "<param> tag must have one and only one of value/textfile/binfile.") # compute name. if name is a tilde name, it is placed in # the context. otherwise it is placed in the ros config. name = self.resolve_args(tag.attributes['name'].value.strip(), context) value = self.param_value(verbose, name, ptype, *vals) if is_private(name) or force_local: p = Param(name, value) context.add_param(p) else: p = Param(ns_join(context.ns, name), value) ros_config.add_param(Param(ns_join(context.ns, name), value), filename=context.filename, verbose=verbose) return p except KeyError, e: raise XmlParseException( "<param> tag is missing required attribute: %s. \n\nParam xml is %s"%(e, tag.toxml()))
def print_params(params, ns): """ Print contents of param dictionary to screen """ if type(params) == dict: for k, v in params.iteritems(): if type(v) == dict: print_params(v, ns_join(ns, k)) else: print "%s=%s"%(ns_join(ns, k), v) else: print params
def print_params(params, ns): """ Print contents of param dictionary to screen """ if type(params) == dict: for k, v in params.iteritems(): if type(v) == dict: print_params(v, ns_join(ns, k)) else: print "%s=%s" % (ns_join(ns, k), v) else: print params
def _set_param(self, ctx, my_state, test_vals, param_server): ctx = make_global_ns(ctx) for type, vals in test_vals: try: caller_id = ns_join(ctx, "node") count = 0 for val in vals: key = ns_join(caller_id, "%s-%s" % (type, count)) param_server.set_param(key, val) self.assert_(param_server.has_param(key)) true_key = ns_join(ctx, key) my_state[true_key] = val count += 1 except Exception, e: assert "getParam failed on type[%s], val[%s]" % (type, val)
def _set_param(self, ctx, my_state, test_vals, param_server): ctx = make_global_ns(ctx) for type, vals in test_vals: try: caller_id = ns_join(ctx, "node") count = 0 for val in vals: key = ns_join(caller_id, "%s-%s"%(type,count)) param_server.set_param(key, val) self.assert_(param_server.has_param(key)) true_key = ns_join(ctx, key) my_state[true_key] = val count += 1 except Exception, e: assert "getParam failed on type[%s], val[%s]"%(type,val)
def add_param(self, ros_config, param_name, param_value, verbose=True): """ Add L{Param} instances to launch config. Dictionary values are unrolled into individual parameters. @param ros_config: launch configuration @type ros_config: L{ROSLaunchConfig} @param param_name: name of parameter namespace to load values into. If param_name is '/', param_value must be a dictionary @type param_name: str @param param_value: value to assign to param_name. If param_value is a dictionary, it's values will be unrolled into individual parameters. @type param_value: str @raise ValueError: if parameters cannot be processed into valid Params """ # shouldn't ever happen if not param_name: raise ValueError("no parameter name specified") if param_name == "/" and type(param_value) != dict: raise ValueError("Cannot load non-dictionary types into global namespace '/'") if type(param_value) == dict: # unroll params for k, v in param_value.iteritems(): self.add_param(ros_config, ns_join(param_name, k), v, verbose=verbose) else: ros_config.add_param(Param(param_name, param_value), verbose=verbose)
def child(self, ns): """ @param ns: sub-namespace of child context, or None if the child context shares the same namespace @type ns: str @return: A child xml context that inherits from this context @rtype: L{LoaderContext} """ if ns: if ns[0] == "/": # global (discouraged) child_ns = ns elif ns == PRIV_NAME: # ~name # private names can only be scoped privately or globally child_ns = PRIV_NAME else: child_ns = ns_join(self.ns, ns) else: child_ns = self.ns return LoaderContext( child_ns, self.filename, parent=self, params=self.params, env_args=self.env_args[:], resolve_dict=deepcopy(self.resolve_dict), arg_names=self.arg_names[:], include_resolve_dict=self.include_resolve_dict, )
def _setParam(self, ctx, myState, testVals, master): ctx = make_global_ns(ctx) for type, vals in testVals: try: callerId = ns_join(ctx, "node") count = 0 for val in vals: key = "%s-%s"%(type,count) #print "master.setParam(%s,%s)"%(callerId, key) master.setParam(callerId, key, val) self.assert_(self.apiSuccess(master.hasParam(callerId, key))) trueKey = ns_join(ctx, key) myState[trueKey] = val count += 1 except Exception, e: assert "getParam failed on type[%s], val[%s]"%(type,val)
def resolve_name(name, caller_id=None): """ Resolve a ROS name to its global, canonical form. Private ~names are resolved relative to the node name. @param name: name to resolve. @type name: str @param caller_id: node name to resolve relative to. To resolve to local namespace, omit this parameter (or use None) @type caller_id: str @return: Resolved name. If name is empty/None, resolve_name returns parent namespace. If namespace is empty/None, @rtype: str """ if not caller_id: caller_id = get_name() if not name: #empty string resolves to namespace return namespace(caller_id) name = canonicalize_name(name) if name[0] == SEP: #global name resolved_name = name elif is_private(name): #~name resolved_name = ns_join(caller_id, name[1:]) else: #relative resolved_name = namespace(caller_id) + name #Mappings override general namespace-based resolution # - do this before canonicalization as remappings are meant to # match the name as specified in the code if resolved_name in _resolved_mappings: return _resolved_mappings[resolved_name] else: return resolved_name
def resolve_name_without_node_name(name): """ The need for this function is complicated -- Topics and Services can be created before init_node is called. In general, this is okay, unless the name is a ~name, in which case we have to raise an ValueError @param name: ROS name to resolve @type name: str @raise ValueError: if name is a ~name @raise ROSInitException: if name is remapped to a ~name """ if is_private(name): raise ValueError("~name topics cannot be created before init_node() has been called") # we use the underlying roslib.names.resolve_name to avoid dependencies on nodename/remappings fake_caller_id = ns_join(get_namespace(), 'node') fake_resolved = roslib.names.resolve_name(name, fake_caller_id) for m, v in _mappings.items(): if roslib.names.resolve_name(m, fake_caller_id) == fake_resolved: if is_private(name): raise ROSInitException("due to the way this node is written, %s cannot be remapped to a ~name. \nThe declaration of topics/services must be moved after the call to init_node()"%name) else: return roslib.names.resolve_name(v, fake_caller_id) return fake_resolved
def add_param(self, ros_config, param_name, param_value, verbose=True): """ Add L{Param} instances to launch config. Dictionary values are unrolled into individual parameters. @param ros_config: launch configuration @type ros_config: L{ROSLaunchConfig} @param param_name: name of parameter namespace to load values into. If param_name is '/', param_value must be a dictionary @type param_name: str @param param_value: value to assign to param_name. If param_value is a dictionary, it's values will be unrolled into individual parameters. @type param_value: str @raise ValueError: if parameters cannot be processed into valid Params """ # shouldn't ever happen if not param_name: raise ValueError("no parameter name specified") if param_name == '/' and type(param_value) != dict: raise ValueError( "Cannot load non-dictionary types into global namespace '/'") if type(param_value) == dict: # unroll params for k, v in param_value.iteritems(): self.add_param(ros_config, ns_join(param_name, k), v, verbose=verbose) else: ros_config.add_param(Param(param_name, param_value), verbose=verbose)
def resolve_name_without_node_name(name): """ The need for this function is complicated -- Topics and Services can be created before init_node is called. In general, this is okay, unless the name is a ~name, in which case we have to raise an ValueError @param name: ROS name to resolve @type name: str @raise ValueError: if name is a ~name @raise ROSInitException: if name is remapped to a ~name """ if is_private(name): raise ValueError("~name topics cannot be created before init_node() has been called") # we use the underlying roslib.names.resolve_name to avoid dependencies on nodename/remappings fake_caller_id = ns_join(get_namespace(), 'node') fake_resolved = roslib.names.resolve_name(name, fake_caller_id) for m, v in _mappings.iteritems(): if roslib.names.resolve_name(m, fake_caller_id) == fake_resolved: if is_private(name): raise ROSInitException("due to the way this node is written, %s cannot be remapped to a ~name. \nThe declaration of topics/services must be moved after the call to init_node()"%name) else: return roslib.names.resolve_name(v, fake_caller_id) return fake_resolved
def _set_param(param, value, verbose=False): """ Set param on the Parameter Server. Unlike L{set_param()}, this takes in a Python value to set instead of YAML. @param param: parameter name @type param: str @param value XmlRpcLegalValue: value to upload @type value: XmlRpcLegalValue """ if type(value) == dict: # #1098 changing dictionary behavior to be an update, rather # than replace behavior. for k, v in value.iteritems(): # dictionary keys must be non-unicode strings if isinstance(k, str): _set_param(ns_join(param, k), v, verbose=verbose) else: raise ROSParamException("YAML dictionaries must have string keys. Invalid dictionary is:\n%s"%value) else: if type(value) == long: if value > sys.maxint: raise ROSParamException("Overflow: Parameter Server integers must be 32-bit signed integers:\n\t-%s <= value <= %s"%(sys.maxint-1, sys.maxint)) try: _succeed(get_param_server().setParam(_get_caller_id(), param, value)) except socket.error: raise ROSParamIOException("Unable to communicate with master!") if verbose: print "set parameter [%s] to [%s]"%(param, value)
def load_str(str, filename, default_namespace=None, verbose=False): """ Load the YAML document as a string @param filename: name of filename, only used for debugging @type filename: str @param default_namespace: namespace to load filename into @type default_namespace: str @param str: YAML text @type str: str @return: list of parameter dictionary and corresponding namespaces for each YAML document in the file @rtype: [(dict, str)...] """ paramlist = [] default_namespace = default_namespace or get_ros_namespace() for doc in yaml.load_all(str): if NS in doc: ns = ns_join(default_namespace, doc.get(NS, None)) if verbose: print "reading parameters into namespace [%s]" % ns del doc[NS] else: ns = default_namespace paramlist.append((doc, ns)) return paramlist
def load_str(str, filename, default_namespace=None, verbose=False): """ Load the YAML document as a string @param filename: name of filename, only used for debugging @type filename: str @param default_namespace: namespace to load filename into @type default_namespace: str @param str: YAML text @type str: str @return: list of parameter dictionary and corresponding namespaces for each YAML document in the file @rtype: [(dict, str)...] """ paramlist = [] default_namespace = default_namespace or get_ros_namespace() for doc in yaml.load_all(str): if NS in doc: ns = ns_join(default_namespace, doc.get(NS, None)) if verbose: print "reading parameters into namespace [%s]"%ns del doc[NS] else: ns = default_namespace paramlist.append((doc, ns)) return paramlist
def set_param_raw(param, value, verbose=False): """ Set param on the Parameter Server. Unlike L{set_param()}, this takes in a Python value to set instead of YAML. @param param: parameter name @type param: str @param value XmlRpcLegalValue: value to upload @type value: XmlRpcLegalValue """ if type(value) == dict: # #1098 changing dictionary behavior to be an update, rather # than replace behavior. for k, v in value.iteritems(): # dictionary keys must be non-unicode strings if isinstance(k, str): set_param_raw(ns_join(param, k), v, verbose=verbose) else: raise ROSParamException("YAML dictionaries must have string keys. Invalid dictionary is:\n%s" % value) else: if type(value) == long: if value > sys.maxint: raise ROSParamException( "Overflow: Parameter Server integers must be 32-bit signed integers:\n\t-%s <= value <= %s" % (sys.maxint - 1, sys.maxint) ) try: _succeed(get_param_server().setParam(_get_caller_id(), param, value)) except socket.error: raise ROSParamIOException("Unable to communicate with master!") if verbose: print "set parameter [%s] to [%s]" % (param, value)
def child(self, ns): """ @param ns: sub-namespace of child context, or None if the child context shares the same namespace @type ns: str @return: A child xml context that inherits from this context @rtype: L{LoaderContext} """ if ns: if ns[0] == '/': # global (discouraged) child_ns = ns elif ns == PRIV_NAME: # ~name # private names can only be scoped privately or globally child_ns = PRIV_NAME else: child_ns = ns_join(self.ns, ns) else: child_ns = self.ns return LoaderContext(child_ns, self.filename, parent=self, params=self.params, env_args=self.env_args[:], resolve_dict=deepcopy(self.resolve_dict), arg_names=self.arg_names[:], include_resolve_dict=self.include_resolve_dict)
def _setParam(self, ctx, myState, testVals, master): ctx = make_global_ns(ctx) for type, vals in testVals: try: callerId = ns_join(ctx, "node") count = 0 for val in vals: key = "%s-%s"%(type,count) #print("master.setParam(%s,%s)"%(callerId, key)) master.setParam(callerId, key, val) self.assert_(self.apiSuccess(master.hasParam(callerId, key))) trueKey = ns_join(ctx, key) myState[trueKey] = val count += 1 except Exception: assert "getParam failed on type[%s], val[%s]"%(type,val)
def load_rosparam(self, context, ros_config, cmd, param, file, text, verbose=True): """ Load rosparam setting @param context: Loader context @type context: L{LoaderContext} @param ros_config: launch configuration @type ros_config: L{ROSLaunchConfig} @param cmd: 'load', 'dump', or 'delete' @type cmd: str @param file: filename for rosparam to use or None @type file: str @param text: text for rosparam to load. Ignored if file is set. @type text: str @raise ValueError: if parameters cannot be processed into valid rosparam setting """ if not cmd in ("load", "dump", "delete"): raise ValueError("command must be 'load', 'dump', or 'delete'") if file is not None: if cmd == "load" and not os.path.isfile(file): raise ValueError("file does not exist [%s]" % file) if cmd == "delete": raise ValueError("'file' attribute is invalid with 'delete' command.") full_param = ns_join(context.ns, param) if param else context.ns if cmd == "dump": ros_config.add_executable(RosbinExecutable("rosparam", (cmd, file, full_param), PHASE_SETUP)) elif cmd == "delete": ros_config.add_executable(RosbinExecutable("rosparam", (cmd, full_param), PHASE_SETUP)) elif cmd == "load": # load YAML text if file: with open(file, "r") as f: text = f.read() if not text: if file: raise ValueError("no YAML in file %s" % file) else: raise ValueError("no YAML to load") # parse YAML text # - lazy import global yaml if yaml is None: import yaml try: data = yaml.load(text) except yaml.MarkedYAMLError, e: if not file: raise ValueError("Error within YAML block:\n\t%s\n\nYAML is:\n%s" % (str(e), text)) else: raise ValueError("file %s contains invalid YAML:\n%s" % (file, str(e))) except Exception, e: if not file: raise ValueError("invalid YAML: %s\n\nYAML is:\n%s" % (str(e), text)) else: raise ValueError("file %s contains invalid YAML:\n%s" % (file, str(e)))
def _get_param_names(names, key, d): """ helper recursive routine for getParamNames() @param names: list of param names to append to @type names: [str] @param d: parameter tree node @type d: dict @param key: parameter key for tree node d @type key: str """ #TODOXXX for k,v in d.iteritems(): if type(v) == dict: _get_param_names(names, ns_join(key, k), v) else: names.append(ns_join(key, k))
def _ns_clear_params_attr(self, tag_name, tag, context, ros_config, node_name=None, include_filename=None): """ Common processing routine for xml tags with NS and CLEAR_PARAMS attributes @param tag: DOM Node @type tag: Node @param context: current namespace context @type context: LoaderContext @param clear_params: list of params to clear @type clear_params: [str] @param node_name: name of node (for use when tag_name == 'node') @type node_name: str @param include_filename: <include> filename if this is an <include> tag. If specified, context will use include rules. @type include_filename: str @return: loader context @rtype: L{LoaderContext} """ if tag.hasAttribute(NS): ns = self.resolve_args(tag.getAttribute(NS), context) if not ns: raise XmlParseException( "<%s> tag has an empty '%s' attribute" % (tag_name, NS)) else: ns = None if include_filename is not None: child_ns = context.include_child(ns, include_filename) else: child_ns = context.child(ns) clear_p = self.resolve_args(tag.getAttribute(CLEAR_PARAMS), context) if clear_p: clear_p = _bool_attr(clear_p, False, 'clear_params') if clear_p: if tag_name == 'node': if not node_name: raise XmlParseException( "<%s> tag must have a 'name' attribute to use '%s' attribute" % (tag_name, CLEAR_PARAMS)) # use make_global_ns to give trailing slash in order to be consistent with XmlContext.ns ros_config.add_clear_param( make_global_ns(ns_join(child_ns.ns, node_name))) else: if not ns: raise XmlParseException( "'ns' attribute must be set in order to use 'clear_params'" ) ros_config.add_clear_param(child_ns.ns) return child_ns
def _testPrivateNames(self): master = self.master myState = {} self._checkParamState(myState) testContexts = ['', 'sub1', 'sub1/sub2', 'sub1/sub2/sub3'] for c in testContexts: c = make_global_ns(c) callerId = ns_join(c, "node") keyStub = "param1" testKey = "~%s" % keyStub testVal = random.randint(-1000000, 100000) master.setParam(callerId, testKey, testVal) trueKey = ns_join(callerId, keyStub) myState[trueKey] = testVal print("checking", trueKey) v1 = self.apiSuccess(master.getParam('/', trueKey)) v2 = self.apiSuccess(master.getParam(callerId, testKey)) assert v1 == v2, "[%s]: %s vs. [%s,%s]: %s" % ( trueKey, v1, callerId, testKey, v2) assert self.apiSuccess(master.hasParam(callerId, testKey)), testKey assert self.apiSuccess(master.hasParam('node', trueKey)), trueKey #test setting a local param on a different node testKey = ns_join("altnode", "param2") testVal = random.randint(-1000000, 100000) master.setParam(callerId, testKey, testVal) trueKey = ns_join(c, testKey) altCallerId = ns_join(c, "altnode") myState[trueKey] = testVal v1 = self.apiSuccess(master.getParam(altCallerId, "~param2")) v2 = self.apiSuccess(master.getParam(callerId, testKey)) assert v1 == v2 assert self.apiSuccess(master.hasParam(callerId, testKey)), testKey assert self.apiSuccess(master.hasParam(altCallerId, "~param2")) self._checkParamState(myState)
def _testPrivateNames(self): master = self.master myState = {} self._checkParamState(myState) testContexts = ['', 'sub1', 'sub1/sub2', 'sub1/sub2/sub3'] for c in testContexts: c = make_global_ns(c) callerId = ns_join(c, "node") keyStub = "param1" testKey = "~%s"%keyStub testVal = random.randint(-1000000, 100000) master.setParam(callerId, testKey, testVal) trueKey = ns_join(callerId, keyStub) myState[trueKey] = testVal print("checking", trueKey) v1 = self.apiSuccess(master.getParam('/', trueKey)) v2 = self.apiSuccess(master.getParam(callerId, testKey)) assert v1 == v2, "[%s]: %s vs. [%s,%s]: %s"%(trueKey, v1, callerId, testKey, v2) assert self.apiSuccess(master.hasParam(callerId, testKey)), testKey assert self.apiSuccess(master.hasParam('node', trueKey)), trueKey #test setting a local param on a different node testKey = ns_join("altnode","param2") testVal = random.randint(-1000000, 100000) master.setParam(callerId, testKey, testVal) trueKey = ns_join(c, testKey) altCallerId = ns_join(c, "altnode") myState[trueKey] = testVal v1 = self.apiSuccess(master.getParam(altCallerId, "~param2")) v2 = self.apiSuccess(master.getParam(callerId, testKey)) assert v1 == v2 assert self.apiSuccess(master.hasParam(callerId, testKey)), testKey assert self.apiSuccess(master.hasParam(altCallerId, "~param2")) self._checkParamState(myState)
def _rosparam_tag(self, tag, context, ros_config, verbose=True): try: self._check_attrs(tag, context, ros_config, XmlLoader.ROSPARAM_OPT_ATTRS) cmd, ns, file, param = self.opt_attrs(tag, context, (XmlLoader.ROSPARAM_OPT_ATTRS)) # ns atribute is a bit out-moded and is only left in for backwards compatibility param = ns_join(ns or '', param or '') # load is the default command cmd = cmd or 'load' self.load_rosparam(context, ros_config, cmd, param, file, _get_text(tag), verbose=verbose) except ValueError, e: raise roslaunch.loader.LoadException("error loading <rosparam> tag: \n\t"+str(e)+"\nXML is %s"%tag.toxml())
def _testEncapsulation(self): """testEncapsulation: test encapsulation: setting same parameter at different levels""" master = self.master myState = {} self._checkParamState(myState) testContexts = ['', 'en', 'en/sub1', 'en/sub2', 'en/sub1/sub2'] for c in testContexts: c = make_global_ns(c) testKey = 'param1' testVal = random.randint(-1000000, 100000) callerId = ns_join(c, "node") trueKey = ns_join(c, testKey) master.setParam(callerId, testKey, testVal) myState[trueKey] = testVal # make sure the master has the parameter under both keys and that they are equal v1 = self.apiSuccess(master.getParam('/', trueKey)) v2 = self.apiSuccess(master.getParam(callerId, testKey)) assert v1 == v2, "[%s]: %s vs. [%s,%s]: %s"%(trueKey, v1, callerId, testKey, v2) assert self.apiSuccess(master.hasParam(callerId, testKey)), testKey assert self.apiSuccess(master.hasParam('node', trueKey)), trueKey self._checkParamState(myState)
def _compute_all_keys(param_key, param_value, all_keys=None): """ Compute which subscribers should be notified based on the parameter update @param param_key: key of updated parameter @type param_key: str @param param_value: value of updated parameter @param all_keys: (internal use only) list of parameter keys to append to for recursive calls. @type all_keys: [str] @return: list of parameter keys. All keys will be canonicalized with trailing slash. @rtype: [str] """ if all_keys is None: all_keys = [] for k, v in param_value.iteritems(): new_k = ns_join(param_key, k) + SEP all_keys.append(new_k) if type(v) == dict: _compute_all_keys(new_k, v, all_keys) return all_keys
def _ns_clear_params_attr(self, tag_name, tag, context, ros_config, node_name=None, include_filename=None): """ Common processing routine for xml tags with NS and CLEAR_PARAMS attributes @param tag: DOM Node @type tag: Node @param context: current namespace context @type context: LoaderContext @param clear_params: list of params to clear @type clear_params: [str] @param node_name: name of node (for use when tag_name == 'node') @type node_name: str @param include_filename: <include> filename if this is an <include> tag. If specified, context will use include rules. @type include_filename: str @return: loader context @rtype: L{LoaderContext} """ if tag.hasAttribute(NS): ns = self.resolve_args(tag.getAttribute(NS), context) if not ns: raise XmlParseException("<%s> tag has an empty '%s' attribute"%(tag_name, NS)) else: ns = None if include_filename is not None: child_ns = context.include_child(ns, include_filename) else: child_ns = context.child(ns) clear_p = self.resolve_args(tag.getAttribute(CLEAR_PARAMS), context) if clear_p: clear_p = _bool_attr(clear_p, False, 'clear_params') if clear_p: if tag_name == 'node': if not node_name: raise XmlParseException("<%s> tag must have a 'name' attribute to use '%s' attribute"%(tag_name, CLEAR_PARAMS)) # use make_global_ns to give trailing slash in order to be consistent with XmlContext.ns ros_config.add_clear_param(make_global_ns(ns_join(child_ns.ns, node_name))) else: if not ns: raise XmlParseException("'ns' attribute must be set in order to use 'clear_params'") ros_config.add_clear_param(child_ns.ns) return child_ns
def test_nsjoin(self): from roslib.names import ns_join # private and global names cannot be joined self.assertEquals('~name', ns_join('/foo', '~name')) self.assertEquals('/name', ns_join('/foo', '/name')) self.assertEquals('~name', ns_join('~', '~name')) self.assertEquals('/name', ns_join('/', '/name')) # ns can be '~' or '/' self.assertEquals('~name', ns_join('~', 'name')) self.assertEquals('/name', ns_join('/', 'name')) self.assertEquals('/ns/name', ns_join('/ns', 'name')) self.assertEquals('/ns/name', ns_join('/ns/', 'name')) self.assertEquals('/ns/ns2/name', ns_join('/ns', 'ns2/name')) self.assertEquals('/ns/ns2/name', ns_join('/ns/', 'ns2/name')) # allow ns to be empty self.assertEquals('name', ns_join('', 'name'))
def load_rosparam(self, context, ros_config, cmd, param, file_, text, verbose=True): """ Load rosparam setting @param context: Loader context @type context: L{LoaderContext} @param ros_config: launch configuration @type ros_config: L{ROSLaunchConfig} @param cmd: 'load', 'dump', or 'delete' @type cmd: str @param file_: filename for rosparam to use or None @type file_: str @param text: text for rosparam to load. Ignored if file_ is set. @type text: str @raise ValueError: if parameters cannot be processed into valid rosparam setting """ if not cmd in ('load', 'dump', 'delete'): raise ValueError("command must be 'load', 'dump', or 'delete'") if file_ is not None: if cmd == 'load' and not os.path.isfile(file_): raise ValueError("file does not exist [%s]"%file_) if cmd == 'delete': raise ValueError("'file' attribute is invalid with 'delete' command.") full_param = ns_join(context.ns, param) if param else context.ns if cmd == 'dump': ros_config.add_executable(RosbinExecutable('rosparam', (cmd, file_, full_param), PHASE_SETUP)) elif cmd == 'delete': ros_config.add_executable(RosbinExecutable('rosparam', (cmd, full_param), PHASE_SETUP)) elif cmd == 'load': # load YAML text if file_: with open(file_, 'r') as f: text = f.read() # parse YAML text # - lazy import global yaml if yaml is None: import yaml # - lazy import: we have to import rosparam in oder to to configure the YAML constructors global rosparam if rosparam is None: import rosparam try: data = yaml.load(text) # #3162: if there is no YAML, load() will return an # empty string. We want an empty dictionary instead # for our representation of empty. if data is None: data = {} except yaml.MarkedYAMLError, e: if not file_: raise ValueError("Error within YAML block:\n\t%s\n\nYAML is:\n%s"%(str(e), text)) else: raise ValueError("file %s contains invalid YAML:\n%s"%(file_, str(e))) except Exception, e: if not file_: raise ValueError("invalid YAML: %s\n\nYAML is:\n%s"%(str(e), text)) else: raise ValueError("file %s contains invalid YAML:\n%s"%(file_, str(e)))
def load_rosparam(self, context, ros_config, cmd, param, file, text, verbose=True): """ Load rosparam setting @param context: Loader context @type context: L{LoaderContext} @param ros_config: launch configuration @type ros_config: L{ROSLaunchConfig} @param cmd: 'load', 'dump', or 'delete' @type cmd: str @param file: filename for rosparam to use or None @type file: str @param text: text for rosparam to load. Ignored if file is set. @type text: str @raise ValueError: if parameters cannot be processed into valid rosparam setting """ if not cmd in ('load', 'dump', 'delete'): raise ValueError("command must be 'load', 'dump', or 'delete'") if file is not None: if cmd == 'load' and not os.path.isfile(file): raise ValueError("file does not exist [%s]" % file) if cmd == 'delete': raise ValueError( "'file' attribute is invalid with 'delete' command.") full_param = ns_join(context.ns, param) if param else context.ns if cmd == 'dump': ros_config.add_executable( RosbinExecutable('rosparam', (cmd, file, full_param), PHASE_SETUP)) elif cmd == 'delete': ros_config.add_executable( RosbinExecutable('rosparam', (cmd, full_param), PHASE_SETUP)) elif cmd == 'load': # load YAML text if file: with open(file, 'r') as f: text = f.read() if not text: if file: raise ValueError("no YAML in file %s" % file) else: raise ValueError("no YAML to load") # parse YAML text # - lazy import global yaml if yaml is None: import yaml try: data = yaml.load(text) except yaml.MarkedYAMLError, e: if not file: raise ValueError( "Error within YAML block:\n\t%s\n\nYAML is:\n%s" % (str(e), text)) else: raise ValueError("file %s contains invalid YAML:\n%s" % (file, str(e))) except Exception, e: if not file: raise ValueError("invalid YAML: %s\n\nYAML is:\n%s" % (str(e), text)) else: raise ValueError("file %s contains invalid YAML:\n%s" % (file, str(e)))
def search_param(self, ns, key): """ Search for matching parameter key for search param key. Search for key starts at ns and proceeds upwards to the root. As such, search_param should only be called with a relative parameter name. search_param's behavior is to search for the first partial match. For example, imagine that there are two 'robot_description' parameters: - /robot_description - /robot_description/arm - /robot_description/base - /pr2/robot_description - /pr2/robot_description/base If I start in the namespace /pr2/foo and search for 'robot_description', search_param will match /pr2/robot_description. If I search for 'robot_description/arm' it will return /pr2/robot_description/arm, even though that parameter does not exist (yet). @param ns: namespace to begin search from. @type ns: str @param key: Parameter key. @type key: str @return: key of matching parameter or None if no matching parameter. @rtype: str """ if not key or is_private(key): raise ValueError("invalid key") if not is_global(ns): raise ValueError("namespace must be global") if is_global(key): if self.has_param(key): return key else: return None # there are more efficient implementations, but our hiearchy # is not very deep and this is fairly clean code to read. # - we only search for the first namespace in the key to check for a match key_namespaces = [x for x in key.split(SEP) if x] key_ns = key_namespaces[0] # - corner case: have to test initial namespace first as # negative indices won't work with 0 search_key = ns_join(ns, key_ns) if self.has_param(search_key): # resolve to full key return ns_join(ns, key) namespaces = [x for x in ns.split(SEP) if x] for i in xrange(1, len(namespaces)+1): search_key = SEP + SEP.join(namespaces[0:-i] + [key_ns]) if self.has_param(search_key): # we have a match on the namespace of the key, so # compose the full key and return it full_key = SEP + SEP.join(namespaces[0:-i] + [key]) return full_key return None