From 891b303c62f4ae7de033b62451f563ab7d07e862 Mon Sep 17 00:00:00 2001 From: Lidang Jiang Date: Tue, 28 Apr 2026 15:52:43 +0800 Subject: [PATCH] fix: parse respawn_max_retries YAML strings Signed-off-by: Lidang Jiang --- launch/launch/actions/execute_process.py | 13 +++++ .../test/launch_yaml/test_executable.py | 49 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/launch/launch/actions/execute_process.py b/launch/launch/actions/execute_process.py index c74d062d8..588b66462 100644 --- a/launch/launch/actions/execute_process.py +++ b/launch/launch/actions/execute_process.py @@ -365,6 +365,19 @@ def parse( respawn_max_retries = entity.get_attr('respawn_max_retries', data_type=int, optional=True) if respawn_max_retries is not None: + if isinstance(respawn_max_retries, bool): + raise ValueError( + 'Attribute respawn_max_retries of Entity `{}` expected to be ' + 'an integer but got `{}`'.format(entity.type_name, respawn_max_retries) + ) + if isinstance(respawn_max_retries, str): + try: + respawn_max_retries = int(respawn_max_retries) + except ValueError: + raise ValueError( + 'Attribute respawn_max_retries of Entity `{}` expected to be ' + 'an integer but got `{}`'.format(entity.type_name, respawn_max_retries) + ) from None kwargs['respawn_max_retries'] = respawn_max_retries if 'respawn_delay' not in ignore: diff --git a/launch_yaml/test/launch_yaml/test_executable.py b/launch_yaml/test/launch_yaml/test_executable.py index 84bac7183..0f44ab8ca 100644 --- a/launch_yaml/test/launch_yaml/test_executable.py +++ b/launch_yaml/test/launch_yaml/test_executable.py @@ -19,6 +19,9 @@ from launch import LaunchService from launch.actions import Shutdown +from launch.actions.execute_process import ExecuteProcess + +import pytest from parser_no_extensions import load_no_extensions @@ -82,5 +85,51 @@ def test_executable_on_exit(): assert isinstance(sub_entities[0], Shutdown) +def test_executable_respawn_max_retries_string_zero(): + yaml_file = \ + """\ + launch: + - executable: + cmd: echo test + respawn_max_retries: '0' + """ + yaml_file = textwrap.dedent(yaml_file) + root_entity, parser = load_no_extensions(io.StringIO(yaml_file)) + _, kwargs = ExecuteProcess.parse(root_entity.children[0], parser) + + assert kwargs['respawn_max_retries'] == 0 + assert isinstance(kwargs['respawn_max_retries'], int) + + +def test_executable_respawn_max_retries_empty_string_error(): + yaml_file = \ + """\ + launch: + - executable: + cmd: echo test + respawn_max_retries: '' + """ + yaml_file = textwrap.dedent(yaml_file) + root_entity, parser = load_no_extensions(io.StringIO(yaml_file)) + + with pytest.raises(ValueError, match='respawn_max_retries'): + ExecuteProcess.parse(root_entity.children[0], parser) + + +def test_executable_respawn_max_retries_bool_error(): + yaml_file = \ + """\ + launch: + - executable: + cmd: echo test + respawn_max_retries: true + """ + yaml_file = textwrap.dedent(yaml_file) + root_entity, parser = load_no_extensions(io.StringIO(yaml_file)) + + with pytest.raises(ValueError, match='respawn_max_retries'): + ExecuteProcess.parse(root_entity.children[0], parser) + + if __name__ == '__main__': test_executable()