def test_multiple_rules(): lc = LaunchContext() rules = [('ping', 'pong'), (('baz', 'foo'), ['bar', TextSubstitution(text='baz')])] output_rules = list(normalize_remap_rules(rules)) assert len(rules) == len(output_rules) assert 'ping' == perform_substitutions(lc, output_rules[0][0]) assert 'pong' == perform_substitutions(lc, output_rules[0][1]) assert 'bazfoo' == perform_substitutions(lc, output_rules[1][0]) assert 'barbaz' == perform_substitutions(lc, output_rules[1][1])
def __init__( self, *, package: SomeSubstitutionsType, node_executable: SomeSubstitutionsType, node_name: Optional[SomeSubstitutionsType] = None, node_namespace: SomeSubstitutionsType = '', parameters: Optional[SomeParameters] = None, remappings: Optional[SomeRemapRules] = None, arguments: Optional[Iterable[SomeSubstitutionsType]] = None, ) -> None: """ Construct a SandboxedNode description. The actual node execution is delegated to the sandboxing environment defined by the policy. :param: package is the name of the node's package and is required for resolving the node. :param: node_executable is the name of the node's executable and is required for resolving the node. :param: node_name is an optional name attached to the node when it is launched. Defaults to NONE. :param: node_namespace is an optional namespace attached to the node when it is launched. Defaults to empty string. :param: parameters are the optional runtime configurations for the node, read from a YAML file. Defaults to NONE. :param: remappings are the ordered list of 'to' and 'from' string pairs to be passed to a node as ROS remapping rules. """ self.__package = \ normalize_to_list_of_substitutions(package) self.__node_executable = \ normalize_to_list_of_substitutions(node_executable) self.__node_name = None if node_name is not None: self.__node_name = normalize_to_list_of_substitutions(node_name) self.__node_namespace = None if node_namespace is not None: self.__node_namespace = \ normalize_to_list_of_substitutions(node_namespace) self.__parameters = None if parameters is not None: self.__parameters = normalize_parameters(parameters) self.__remappings = None if remappings is not None: self.__remappings = normalize_remap_rules(remappings)
def __init__( self, *, package: SomeSubstitutionsType, node_plugin: SomeSubstitutionsType, node_name: Optional[SomeSubstitutionsType] = None, node_namespace: Optional[SomeSubstitutionsType] = None, parameters: Optional[SomeParameters] = None, remappings: Optional[SomeRemapRules] = None, extra_arguments: Optional[SomeParameters] = None, ) -> None: """ Initialize a ComposableNode description. :param package: name of the ROS package the node plugin lives in :param node_plugin: name of the plugin to be loaded :param node_name: name the node should have :param node_namespace: namespace the node should create topics/services/etc in :param parameters: list of either paths to yaml files or dictionaries of parameters :param remappings: list of from/to pairs for remapping names :param extra_arguments: container specific arguments to be passed to the loaded node """ self.__package = normalize_to_list_of_substitutions(package) self.__node_plugin = normalize_to_list_of_substitutions(node_plugin) self.__node_name = None # type: Optional[List[Substitution]] if node_name is not None: self.__node_name = normalize_to_list_of_substitutions(node_name) self.__node_namespace = None # type: Optional[List[Substitution]] if node_namespace is not None: self.__node_namespace = normalize_to_list_of_substitutions( node_namespace) self.__parameters = None # type: Optional[Parameters] if parameters is not None: self.__parameters = normalize_parameters(parameters) self.__remappings = None # type: Optional[RemapRules] if remappings: self.__remappings = normalize_remap_rules(remappings) self.__extra_arguments = None # type: Optional[Parameters] if extra_arguments: self.__extra_arguments = normalize_parameters(extra_arguments)
def __init__(self, *, package: SomeSubstitutionsType, node_executable: SomeSubstitutionsType, node_name: Optional[SomeSubstitutionsType] = None, node_namespace: SomeSubstitutionsType = '', parameters: Optional[SomeParameters] = None, remappings: Optional[SomeRemapRules] = None, arguments: Optional[Iterable[SomeSubstitutionsType]] = None, **kwargs) -> None: """ Construct an Node action. Many arguments are passed eventually to :class:`launch.actions.ExecuteProcess`, so see the documentation of that class for additional details. However, the `cmd` is not meant to be used, instead use the `node_executable` and `arguments` keyword arguments to this function. This action, once executed, delegates most work to the :class:`launch.actions.ExecuteProcess`, but it also converts some ROS specific arguments into generic command line arguments. The launch_ros.substitutions.ExecutableInPackage substitution is used to find the executable at runtime, so this Action also raise the exceptions that substituion can raise when the package or executable are not found. If the node_name is not given (or is None) then no name is passed to the node on creation and instead the default name specified within the code of the node is used instead. The node_namespace can either be absolute (i.e. starts with /) or relative. If absolute, then nothing else is considered and this is passed directly to the node to set the namespace. If relative, the namespace in the 'ros_namespace' LaunchConfiguration will be prepended to the given relative node namespace. If no node_namespace is given, then the default namespace `/` is assumed. The parameters are passed as a list, with each element either a yaml file that contains parameter rules (string or pathlib.Path to the full path of the file), or a dictionary that specifies parameter rules. Keys of the dictionary can be strings or an iterable of Substitutions that will be expanded to a string. Values in the dictionary can be strings, integers, floats, or tuples of Substitutions that will be expanded to a string. Additionally, values in the dictionary can be lists of the aforementioned types, or another dictionary with the same properties. A yaml file with the resulting parameters from the dictionary will be written to a temporary file, the path to which will be passed to the node. Multiple dictionaries/files can be passed: each file path will be passed in in order to the node (where the last definition of a parameter takes effect). :param: package the package in which the node executable can be found :param: node_executable the name of the executable to find :param: node_name the name of the node :param: node_namespace the ros namespace for this Node :param: parameters list of names of yaml files with parameter rules, or dictionaries of parameters. :param: remappings ordered list of 'to' and 'from' string pairs to be passed to the node as ROS remapping rules :param: arguments list of extra arguments for the node """ cmd = [ ExecutableInPackage(package=package, executable=node_executable) ] cmd += [] if arguments is None else arguments # Reserve space for ros specific arguments. # The substitutions will get expanded when the action is executed. cmd += ['--ros-args' ] # Prepend ros specific arguments with --ros-args flag if node_name is not None: cmd += [ '-r', LocalSubstitution("ros_specific_arguments['name']", description='node name') ] if parameters is not None: ensure_argument_type(parameters, (list), 'parameters', 'Node') # All elements in the list are paths to files with parameters (or substitutions that # evaluate to paths), or dictionaries of parameters (fields can be substitutions). i = 0 for param in parameters: cmd += [ LocalSubstitution( "ros_specific_arguments['params'][{}]".format(i), description='parameter {}'.format(i)) ] i += 1 normalized_params = normalize_parameters(parameters) if remappings is not None: i = 0 for remapping in normalize_remap_rules(remappings): k, v = remapping cmd += [ '-r', LocalSubstitution( "ros_specific_arguments['remaps'][{}]".format(i), description='remapping {}'.format(i)) ] i += 1 super().__init__(cmd=cmd, **kwargs) self.__package = package self.__node_executable = node_executable self.__node_name = node_name self.__node_namespace = node_namespace self.__parameters = [] if parameters is None else normalized_params self.__remappings = [] if remappings is None else remappings self.__arguments = arguments self.__expanded_node_name = '<node_name_unspecified>' self.__expanded_node_namespace = '' self.__final_node_name = None # type: Optional[Text] self.__expanded_parameter_files = None # type: Optional[List[Text]] self.__expanded_remappings = None # type: Optional[List[Tuple[Text, Text]]] self.__substitutions_performed = False self.__logger = launch.logging.get_logger(__name__)
def __init__(self, *, executable: Optional[SomeSubstitutionsType] = None, node_executable: Optional[SomeSubstitutionsType] = None, package: Optional[SomeSubstitutionsType] = None, name: Optional[SomeSubstitutionsType] = None, namespace: Optional[SomeSubstitutionsType] = None, node_name: Optional[SomeSubstitutionsType] = None, node_namespace: SomeSubstitutionsType = None, exec_name: Optional[SomeSubstitutionsType] = None, parameters: Optional[SomeParameters] = None, remappings: Optional[SomeRemapRules] = None, arguments: Optional[Iterable[SomeSubstitutionsType]] = None, **kwargs) -> None: """ Construct an Node action. Many arguments are passed eventually to :class:`launch.actions.ExecuteProcess`, so see the documentation of that class for additional details. However, the `cmd` is not meant to be used, instead use the `executable` and `arguments` keyword arguments to this function. This action, once executed, delegates most work to the :class:`launch.actions.ExecuteProcess`, but it also converts some ROS specific arguments into generic command line arguments. The launch_ros.substitutions.ExecutableInPackage substitution is used to find the executable at runtime, so this Action also raise the exceptions that substituion can raise when the package or executable are not found. If the name is not given (or is None) then no name is passed to the node on creation and instead the default name specified within the code of the node is used instead. The namespace can either be absolute (i.e. starts with /) or relative. If absolute, then nothing else is considered and this is passed directly to the node to set the namespace. If relative, the namespace in the 'ros_namespace' LaunchConfiguration will be prepended to the given relative node namespace. If no namespace is given, then the default namespace `/` is assumed. The parameters are passed as a list, with each element either a yaml file that contains parameter rules (string or pathlib.Path to the full path of the file), or a dictionary that specifies parameter rules. Keys of the dictionary can be strings or an iterable of Substitutions that will be expanded to a string. Values in the dictionary can be strings, integers, floats, or tuples of Substitutions that will be expanded to a string. Additionally, values in the dictionary can be lists of the aforementioned types, or another dictionary with the same properties. A yaml file with the resulting parameters from the dictionary will be written to a temporary file, the path to which will be passed to the node. Multiple dictionaries/files can be passed: each file path will be passed in in order to the node (where the last definition of a parameter takes effect). .. deprecated:: Foxy Parameters `node_executable`, `node_name`, and `node_namespace` are deprecated. Use `executable`, `name`, and `namespace` instead. :param: executable the name of the executable to find if a package is provided or otherwise a path to the executable to run. :param: node_executable (DEPRECATED) the name of the executable to find if a package is provided or otherwise a path to the executable to run. :param: package the package in which the node executable can be found :param: name the name of the node :param: namespace the ROS namespace for this Node :param: exec_name the label used to represent the process. Defaults to the basename of node executable. :param: node_name (DEPRECATED) the name of the node :param: node_namespace (DEPRECATED) the ros namespace for this Node :param: parameters list of names of yaml files with parameter rules, or dictionaries of parameters. :param: remappings ordered list of 'to' and 'from' string pairs to be passed to the node as ROS remapping rules :param: arguments list of extra arguments for the node """ if node_executable is not None: warnings.warn( "The parameter 'node_executable' is deprecated, use 'executable' instead", stacklevel=2) if executable is not None: raise RuntimeError( "Passing both 'node_executable' and 'executable' parameters. " "Only use 'executable'") executable = node_executable if package is not None: cmd = [ExecutableInPackage(package=package, executable=executable)] else: cmd = [executable] cmd += [] if arguments is None else arguments # Reserve space for ros specific arguments. # The substitutions will get expanded when the action is executed. cmd += ['--ros-args' ] # Prepend ros specific arguments with --ros-args flag if node_name is not None: warnings.warn( "The parameter 'node_name' is deprecated, use 'name' instead", stacklevel=2) if name is not None: raise RuntimeError( "Passing both 'node_name' and 'name' parameters. Only use 'name'." ) cmd += [ '-r', LocalSubstitution("ros_specific_arguments['name']", description='node name') ] name = node_name if name is not None: cmd += [ '-r', LocalSubstitution("ros_specific_arguments['name']", description='node name') ] if node_namespace: warnings.warn( "The parameter 'node_namespace' is deprecated, use 'namespace' instead" ) if namespace: raise RuntimeError( "Passing both 'node_namespace' and 'namespace' parameters. " "Only use 'namespace'.") namespace = node_namespace if parameters is not None: ensure_argument_type(parameters, (list), 'parameters', 'Node') # All elements in the list are paths to files with parameters (or substitutions that # evaluate to paths), or dictionaries of parameters (fields can be substitutions). normalized_params = normalize_parameters(parameters) # Forward 'exec_name' as to ExecuteProcess constructor kwargs['name'] = exec_name super().__init__(cmd=cmd, **kwargs) self.__package = package self.__node_executable = executable self.__node_name = name self.__node_namespace = namespace self.__parameters = [] if parameters is None else normalized_params self.__remappings = [] if remappings is None else list( normalize_remap_rules(remappings)) self.__arguments = arguments self.__expanded_node_name = self.UNSPECIFIED_NODE_NAME self.__expanded_node_namespace = self.UNSPECIFIED_NODE_NAMESPACE self.__expanded_parameter_arguments = None # type: Optional[List[Tuple[Text, bool]]] self.__final_node_name = None # type: Optional[Text] self.__expanded_remappings = None # type: Optional[List[Tuple[Text, Text]]] self.__substitutions_performed = False self.__logger = launch.logging.get_logger(__name__)
def __init__( self, *, package: SomeSubstitutionsType, plugin: Optional[SomeSubstitutionsType] = None, name: Optional[SomeSubstitutionsType] = None, namespace: Optional[SomeSubstitutionsType] = None, node_plugin: Optional[SomeSubstitutionsType] = None, node_name: Optional[SomeSubstitutionsType] = None, node_namespace: Optional[SomeSubstitutionsType] = None, parameters: Optional[SomeParameters] = None, remappings: Optional[SomeRemapRules] = None, extra_arguments: Optional[SomeParameters] = None, ) -> None: """ Initialize a ComposableNode description. .. deprecated:: Foxy Parameters `node_plugin`, `node_name`, and `node_namespace` are deprecated. Use `plugin`, `name`, and `namespace` instead. :param package: name of the ROS package the node plugin lives in :param plugin: name of the plugin to be loaded :param name: name to give to the ROS node :param namespace: namespace to give to the ROS node :param node_plugin: (DEPRECATED) name of the plugin to be loaded :param node_name: (DEPRECATED) name the node should have :param node_namespace: (DEPRECATED) namespace the node should create topics/services/etc in :param parameters: list of either paths to yaml files or dictionaries of parameters :param remappings: list of from/to pairs for remapping names :param extra_arguments: container specific arguments to be passed to the loaded node """ if node_plugin is not None: warnings.warn("The parameter 'node_plugin' is deprecated, use 'plugin' instead") if plugin is not None: raise RuntimeError( "Passing both 'node_plugin' and 'plugin' parameters. Only use 'plugin'." ) plugin = node_plugin if plugin is None: raise RuntimeError("The 'plugin' parameter is required") if node_name is not None: warnings.warn("The parameter 'node_name' is deprecated, use 'name' instead") if name is not None: raise RuntimeError( "Passing both 'node_name' and 'name' parameters. Only use 'name'." ) name = node_name if node_namespace is not None: warnings.warn("The parameter 'node_namespace' is deprecated, use 'namespace' instead") if namespace is not None: raise RuntimeError( "Passing both 'node_namespace' and 'namespace' parameters. " "Only use 'namespace'." ) namespace = node_namespace self.__package = normalize_to_list_of_substitutions(package) self.__node_plugin = normalize_to_list_of_substitutions(plugin) self.__node_name = None # type: Optional[List[Substitution]] if name is not None: self.__node_name = normalize_to_list_of_substitutions(name) self.__node_namespace = None # type: Optional[List[Substitution]] if namespace is not None: self.__node_namespace = normalize_to_list_of_substitutions(namespace) self.__parameters = None # type: Optional[Parameters] if parameters is not None: self.__parameters = normalize_parameters(parameters) self.__remappings = None # type: Optional[RemapRules] if remappings: self.__remappings = normalize_remap_rules(remappings) self.__extra_arguments = None # type: Optional[Parameters] if extra_arguments: self.__extra_arguments = normalize_parameters(extra_arguments)