Ejemplo n.º 1
0
    def __init__(
        self,
        target_action,
        log_file,
        timeout=None,
        **kwargs
    ) -> None:
        """
        Construct a SystemMetricCollector action.

        Parameters
        ----------
        target_action : ExecuteProcess
            ExecuteProcess (or Node) instance to collect metrics on
        log_file : str or LaunchSubstitutionsType
            Path to where the collected metrics should be written to
        timeout : int or LaunchSubstitutionsType
            Maximum time to run the metrics collector if the target process does
            not exit

        """
        # These Node/ExecuteProcess arguments are invalid in this context
        # because we implicitly set them right here.
        assert 'arguments' not in kwargs
        assert 'package' not in kwargs
        assert 'executable' not in kwargs
        assert 'executable' not in kwargs

        self.__pid_var_name = '__PROCESS_ID_%d' % id(self)

        kwargs['package'] = 'buildfarm_perf_tests'
        kwargs['executable'] = 'system_metric_collector'
        kwargs['arguments'] = [
            '--log', log_file,
            '--process_pid', LocalSubstitution(self.__pid_var_name)]
        if timeout is not None:
            kwargs['arguments'] += [
                '--timeout',
                str(timeout) if isinstance(timeout, int) else timeout
            ]

        super().__init__(**kwargs)

        self.__target_start_handler = OnProcessStart(
            target_action=target_action, on_start=self.__on_target_start)
        self.__target_exit_handler = OnProcessExit(
            target_action=target_action, on_exit=EmitEvent(
                event=ShutdownProcess(
                    process_matcher=matches_action(self))))
Ejemplo n.º 2
0
    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__)
Ejemplo n.º 3
0
 def _perform_substitutions(self, context: LaunchContext) -> None:
     try:
         if self.__substitutions_performed:
             # This function may have already been called by a subclass' `execute`, for example.
             return
         self.__substitutions_performed = True
         if self.__node_name is not None:
             self.__expanded_node_name = perform_substitutions(
                 context,
                 normalize_to_list_of_substitutions(self.__node_name))
             validate_node_name(self.__expanded_node_name)
         self.__expanded_node_name.lstrip('/')
         self.__expanded_node_namespace = perform_substitutions(
             context,
             normalize_to_list_of_substitutions(self.__node_namespace))
         if not self.__expanded_node_namespace.startswith('/'):
             base_ns = context.launch_configurations.get(
                 'ros_namespace', '')
             self.__expanded_node_namespace = (
                 base_ns + '/' + self.__expanded_node_namespace).rstrip('/')
             if (self.__expanded_node_namespace != '' and
                     not self.__expanded_node_namespace.startswith('/')):
                 self.__expanded_node_namespace = '/' + self.__expanded_node_namespace
         if self.__expanded_node_namespace != '':
             cmd_extension = [
                 '-r',
                 LocalSubstitution("ros_specific_arguments['ns']")
             ]
             self.cmd.extend([
                 normalize_to_list_of_substitutions(x)
                 for x in cmd_extension
             ])
             validate_namespace(self.__expanded_node_namespace)
     except Exception:
         self.__logger.error(
             "Error while expanding or validating node name or namespace for '{}':"
             .format(
                 'package={}, node_executable={}, name={}, namespace={}'.
                 format(
                     self.__package,
                     self.__node_executable,
                     self.__node_name,
                     self.__node_namespace,
                 )))
         raise
     self.__final_node_name = ''
     if self.__expanded_node_namespace not in ['', '/']:
         self.__final_node_name += self.__expanded_node_namespace
     self.__final_node_name += '/' + self.__expanded_node_name
     # expand parameters too
     if self.__parameters is not None:
         self.__expanded_parameter_files = []
         evaluated_parameters = evaluate_parameters(context,
                                                    self.__parameters)
         for params in evaluated_parameters:
             if isinstance(params, dict):
                 param_file_path = self._create_params_file_from_dict(
                     params)
             elif isinstance(params, pathlib.Path):
                 param_file_path = str(params)
             else:
                 raise RuntimeError(
                     'invalid normalized parameters {}'.format(
                         repr(params)))
             if not os.path.isfile(param_file_path):
                 self.__logger.warning(
                     'Parameter file path is not a file: {}'.format(
                         param_file_path), )
                 # Don't skip adding the file to the parameter list since space has been
                 # reserved for it in the ros_specific_arguments.
             self.__expanded_parameter_files.append(param_file_path)
     # expand remappings too
     if self.__remappings is not None:
         self.__expanded_remappings = []
         for k, v in self.__remappings:
             key = perform_substitutions(
                 context, normalize_to_list_of_substitutions(k))
             value = perform_substitutions(
                 context, normalize_to_list_of_substitutions(v))
             self.__expanded_remappings.append((key, value))
Ejemplo n.º 4
0
 def _perform_substitutions(self, context: LaunchContext) -> None:
     # Here to avoid cyclic import
     from ..descriptions import Parameter
     try:
         if self.__substitutions_performed:
             # This function may have already been called by a subclass' `execute`, for example.
             return
         self.__substitutions_performed = True
         if self.__node_name is not None:
             self.__expanded_node_name = perform_substitutions(
                 context, normalize_to_list_of_substitutions(self.__node_name))
             validate_node_name(self.__expanded_node_name)
         self.__expanded_node_name.lstrip('/')
         expanded_node_namespace: Optional[Text] = None
         if self.__node_namespace is not None:
             expanded_node_namespace = perform_substitutions(
                 context, normalize_to_list_of_substitutions(self.__node_namespace))
         base_ns = context.launch_configurations.get('ros_namespace', None)
         expanded_node_namespace = make_namespace_absolute(
             prefix_namespace(base_ns, expanded_node_namespace))
         if expanded_node_namespace is not None:
             self.__expanded_node_namespace = expanded_node_namespace
             cmd_extension = ['-r', LocalSubstitution("ros_specific_arguments['ns']")]
             self.cmd.extend([normalize_to_list_of_substitutions(x) for x in cmd_extension])
             validate_namespace(self.__expanded_node_namespace)
     except Exception:
         self.__logger.error(
             "Error while expanding or validating node name or namespace for '{}':"
             .format('package={}, executable={}, name={}, namespace={}'.format(
                 self.__package,
                 self.__node_executable,
                 self.__node_name,
                 self.__node_namespace,
             ))
         )
         raise
     self.__final_node_name = prefix_namespace(
         self.__expanded_node_namespace, self.__expanded_node_name)
     # expand global parameters first,
     # so they can be overriden with specific parameters of this Node
     global_params = context.launch_configurations.get('ros_params', None)
     if global_params is not None or self.__parameters is not None:
         self.__expanded_parameter_arguments = []
     if global_params is not None:
         param_file_path = self._create_params_file_from_dict(global_params)
         self.__expanded_parameter_arguments.append((param_file_path, True))
         cmd_extension = ['--params-file', f'{param_file_path}']
         self.cmd.extend([normalize_to_list_of_substitutions(x) for x in cmd_extension])
         assert os.path.isfile(param_file_path)
     # expand parameters too
     if self.__parameters is not None:
         evaluated_parameters = evaluate_parameters(context, self.__parameters)
         for params in evaluated_parameters:
             is_file = False
             if isinstance(params, dict):
                 param_argument = self._create_params_file_from_dict(params)
                 is_file = True
                 assert os.path.isfile(param_argument)
             elif isinstance(params, pathlib.Path):
                 param_argument = str(params)
                 is_file = True
             elif isinstance(params, Parameter):
                 param_argument = self._get_parameter_rule(params, context)
             else:
                 raise RuntimeError('invalid normalized parameters {}'.format(repr(params)))
             if is_file and not os.path.isfile(param_argument):
                 self.__logger.warning(
                     'Parameter file path is not a file: {}'.format(param_argument),
                 )
                 continue
             self.__expanded_parameter_arguments.append((param_argument, is_file))
             cmd_extension = ['--params-file' if is_file else '-p', f'{param_argument}']
             self.cmd.extend([normalize_to_list_of_substitutions(x) for x in cmd_extension])
     # expand remappings too
     global_remaps = context.launch_configurations.get('ros_remaps', None)
     if global_remaps or self.__remappings:
         self.__expanded_remappings = []
     if global_remaps:
         self.__expanded_remappings.extend(global_remaps)
     if self.__remappings:
         self.__expanded_remappings.extend([
             (perform_substitutions(context, src), perform_substitutions(context, dst))
             for src, dst in self.__remappings
         ])
     if self.__expanded_remappings:
         cmd_extension = []
         for src, dst in self.__expanded_remappings:
             cmd_extension.extend(['-r', f'{src}:={dst}'])
         self.cmd.extend([normalize_to_list_of_substitutions(x) for x in cmd_extension])
Ejemplo n.º 5
0
    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__)
Ejemplo n.º 6
0
Archivo: node.py Proyecto: hfz-Nick/ROS
    def __init__(self,
                 *,
                 package: SomeSubstitutionsType,
                 node_executable: SomeSubstitutionsType,
                 node_name: Optional[SomeSubstitutionsType] = None,
                 node_namespace: Optional[SomeSubstitutionsType] = None,
                 remappings: Optional[Iterable[Tuple[
                     SomeSubstitutionsType, SomeSubstitutionsType]]] = 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.

        :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: 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.
        ros_args_index = 0
        if node_name is not None:
            cmd += [
                LocalSubstitution(
                    'ros_specific_arguments[{}]'.format(ros_args_index))
            ]
            ros_args_index += 1
        if node_namespace is not None:
            cmd += [
                LocalSubstitution(
                    'ros_specific_arguments[{}]'.format(ros_args_index))
            ]
            ros_args_index += 1
        if remappings is not None:
            for k, v in remappings:
                cmd += [
                    LocalSubstitution(
                        'ros_specific_arguments[{}]'.format(ros_args_index))
                ]
                ros_args_index += 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.__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_remappings = None  # type: Optional[Dict[Text, Text]]

        self.__substitutions_performed = False
Ejemplo n.º 7
0
 def _perform_substitutions(self, context: LaunchContext) -> None:
     try:
         if self.__substitutions_performed:
             # This function may have already been called by a subclass' `execute`, for example.
             return
         self.__substitutions_performed = True
         if self.__node_name is not None:
             self.__expanded_node_name = perform_substitutions(
                 context,
                 normalize_to_list_of_substitutions(self.__node_name))
             validate_node_name(self.__expanded_node_name)
         self.__expanded_node_name.lstrip('/')
         expanded_node_namespace = None
         if self.__node_namespace is not None:
             expanded_node_namespace = perform_substitutions(
                 context,
                 normalize_to_list_of_substitutions(self.__node_namespace))
         base_ns = context.launch_configurations.get('ros_namespace', None)
         if base_ns is not None or expanded_node_namespace is not None:
             if expanded_node_namespace is None:
                 expanded_node_namespace = ''
             if base_ns is None:
                 base_ns = ''
             if not expanded_node_namespace.startswith('/'):
                 expanded_node_namespace = (
                     base_ns + '/' + expanded_node_namespace).rstrip('/')
             if not expanded_node_namespace.startswith('/'):
                 expanded_node_namespace = '/' + expanded_node_namespace
             self.__expanded_node_namespace = expanded_node_namespace
         if expanded_node_namespace is not None:
             cmd_extension = [
                 '-r',
                 LocalSubstitution("ros_specific_arguments['ns']")
             ]
             self.cmd.extend([
                 normalize_to_list_of_substitutions(x)
                 for x in cmd_extension
             ])
             validate_namespace(self.__expanded_node_namespace)
     except Exception:
         self.__logger.error(
             "Error while expanding or validating node name or namespace for '{}':"
             .format(
                 'package={}, executable={}, name={}, namespace={}'.format(
                     self.__package,
                     self.__node_executable,
                     self.__node_name,
                     self.__node_namespace,
                 )))
         raise
     self.__final_node_name = ''
     if self.__expanded_node_namespace != '/':
         self.__final_node_name += self.__expanded_node_namespace
     self.__final_node_name += '/' + self.__expanded_node_name
     # expand global parameters first,
     # so they can be overriden with specific parameters of this Node
     global_params = context.launch_configurations.get('ros_params', None)
     if global_params is not None or self.__parameters is not None:
         self.__expanded_parameter_files = []
     if global_params is not None:
         param_file_path = self._create_params_file_from_dict(global_params)
         self.__expanded_parameter_files.append(param_file_path)
         cmd_extension = ['--params-file', f'{param_file_path}']
         self.cmd.extend(
             [normalize_to_list_of_substitutions(x) for x in cmd_extension])
         assert os.path.isfile(param_file_path)
     # expand parameters too
     if self.__parameters is not None:
         evaluated_parameters = evaluate_parameters(context,
                                                    self.__parameters)
         for i, params in enumerate(evaluated_parameters):
             if isinstance(params, dict):
                 param_file_path = self._create_params_file_from_dict(
                     params)
                 assert os.path.isfile(param_file_path)
             elif isinstance(params, pathlib.Path):
                 param_file_path = str(params)
             else:
                 raise RuntimeError(
                     'invalid normalized parameters {}'.format(
                         repr(params)))
             if not os.path.isfile(param_file_path):
                 self.__logger.warning(
                     'Parameter file path is not a file: {}'.format(
                         param_file_path), )
                 continue
             self.__expanded_parameter_files.append(param_file_path)
             cmd_extension = ['--params-file', f'{param_file_path}']
             self.cmd.extend([
                 normalize_to_list_of_substitutions(x)
                 for x in cmd_extension
             ])
     # expand remappings too
     if self.__remappings is not None:
         self.__expanded_remappings = []
         for k, v in self.__remappings:
             key = perform_substitutions(
                 context, normalize_to_list_of_substitutions(k))
             value = perform_substitutions(
                 context, normalize_to_list_of_substitutions(v))
             self.__expanded_remappings.append((key, value))