From 34105a33586a5ff6cc370d3435ef36fa9523cefa Mon Sep 17 00:00:00 2001 From: Old-Ding <35417409+Old-Ding@users.noreply.github.com> Date: Sat, 11 Jul 2026 01:41:12 +0800 Subject: [PATCH] Reject invalid GroupAction boolean attributes The XML and YAML frontends can preserve values that fail boolean conversion as strings. Require GroupAction scoped and forwarding attributes to convert to bool so invalid values raise TypeError instead of being treated as truthy. Signed-off-by: Old-Ding <35417409+Old-Ding@users.noreply.github.com> --- launch/launch/actions/group_action.py | 6 ++++-- launch_xml/test/launch_xml/test_group.py | 11 ++++++++++- launch_yaml/test/launch_yaml/test_group.py | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/launch/launch/actions/group_action.py b/launch/launch/actions/group_action.py index e67ac0876..b81a8b4d5 100644 --- a/launch/launch/actions/group_action.py +++ b/launch/launch/actions/group_action.py @@ -93,8 +93,10 @@ def parse(cls, entity: Entity, parser: Parser ) -> Tuple[Type['GroupAction'], Dict[str, Any]]: """Return `GroupAction` action and kwargs for constructing it.""" _, kwargs = super().parse(entity, parser) - scoped = entity.get_attr('scoped', data_type=bool, optional=True) - forwarding = entity.get_attr('forwarding', data_type=bool, optional=True) + scoped = entity.get_attr( + 'scoped', data_type=bool, optional=True, can_be_str=False) + forwarding = entity.get_attr( + 'forwarding', data_type=bool, optional=True, can_be_str=False) keeps = entity.get_attr('keep', data_type=List[Entity], optional=True) if scoped is not None: kwargs['scoped'] = scoped diff --git a/launch_xml/test/launch_xml/test_group.py b/launch_xml/test/launch_xml/test_group.py index 1a7217847..d281f3bc5 100644 --- a/launch_xml/test/launch_xml/test_group.py +++ b/launch_xml/test/launch_xml/test_group.py @@ -26,8 +26,8 @@ from launch.actions import ResetLaunchConfigurations from launch.actions import SetLaunchConfiguration from launch.launch_context import LaunchContext - from parser_no_extensions import load_no_extensions +import pytest def test_group(): @@ -86,5 +86,14 @@ def test_group(): actions[7].visit(lc) +@pytest.mark.parametrize('attribute', ('scoped', 'forwarding')) +def test_group_rejects_invalid_boolean_attributes(attribute): + xml_file = f'' + root_entity, parser = load_no_extensions(io.StringIO(xml_file)) + + with pytest.raises(TypeError, match=f"Attribute '{attribute}'"): + parser.parse_description(root_entity) + + if __name__ == '__main__': test_group() diff --git a/launch_yaml/test/launch_yaml/test_group.py b/launch_yaml/test/launch_yaml/test_group.py index 76c087ab7..14a926ba6 100644 --- a/launch_yaml/test/launch_yaml/test_group.py +++ b/launch_yaml/test/launch_yaml/test_group.py @@ -28,6 +28,7 @@ from launch.launch_context import LaunchContext from parser_no_extensions import load_no_extensions +import pytest def test_group(): @@ -98,5 +99,19 @@ def test_group(): actions[7].visit(lc) +@pytest.mark.parametrize('attribute', ('scoped', 'forwarding')) +def test_group_rejects_invalid_boolean_attributes(attribute): + yaml_file = f"""\ + launch: + - group: + {attribute}: invalid + """ + yaml_file = textwrap.dedent(yaml_file) + root_entity, parser = load_no_extensions(io.StringIO(yaml_file)) + + with pytest.raises(TypeError, match=f"Attribute '{attribute}'"): + parser.parse_description(root_entity) + + if __name__ == '__main__': test_group()