From a719377f618da129596d46eaba19de74c396951b Mon Sep 17 00:00:00 2001 From: Vikrant Shah Date: Wed, 17 Jun 2026 06:50:45 -0700 Subject: [PATCH] fix(generator): emit .msg syntax in _fields_and_field_types for bounded types _fields_and_field_types / get_fields_and_field_types() is documented as a Python introspection API for message field types. However it was emitting OMG IDL 4.2 syntax for bounded strings and sequences: sequence, 32> (IDL) instead of the canonical ROS 2 .msg syntax: string<=256[<=32] (.msg) This breaks any consumer that passes the output directly to the MCAP ros2msg schema encoder (e.g. mcap_utils _build_ros2_schema()), because the ros2msg schema encoding requires .msg syntax per the MCAP registry spec (https://mcap.dev/spec/registry#ros2msg). Foxglove and other ros2msg-aware tools reject the IDL form. Changes: - Remove IDL-style sequence<> prefix/suffix generation in the _fields_and_field_types dict template. - Emit bounded string bound with <= (string<=N) instead of . - Emit bounded sequence bound as [<=N], unbounded sequence as [], fixed-size array as [N] -- all matching .msg syntax. - Update test_interfaces.py expected values accordingly. The SLOT_TYPES tuple (rosidl_parser.definition objects) is unchanged and remains the correct API for programmatic type inspection. Signed-off-by: Vikrant Shah --- rosidl_generator_py/resource/_msg.py.em | 19 +++++++------------ rosidl_generator_py/test/test_interfaces.py | 20 ++++++++++---------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index a8682df0..2bf2a439 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -268,11 +268,7 @@ if isinstance(type_, AbstractNestedType): type_ = type_.value_type }@ '@(member.name)': '@ -@# the prefix for nested types -@[ if isinstance(member.type, AbstractSequence)]@ -sequence<@ -@[ end if]@ -@# the typename of the non-nested type or the nested basetype +@# the typename of the non-nested type or the nested basetype (.msg syntax) @[ if isinstance(type_, BasicType)]@ @(type_.typename)@ @[ elif isinstance(type_, AbstractGenericString)]@ @@ -282,17 +278,16 @@ w@ @[ end if]@ string@ @[ if type_.has_maximum_size()]@ -<@(type_.maximum_size)>@ +<=@(type_.maximum_size)@ @[ end if]@ @[ elif isinstance(type_, NamespacedType)]@ @('/'.join([type_.namespaces[0], type_.name]))@ @[ end if]@ -@# the suffix for nested types -@[ if isinstance(member.type, AbstractSequence)]@ -@[ if isinstance(member.type, BoundedSequence)]@ -, @(member.type.maximum_size)@ -@[ end if]@ ->@ +@# array/sequence suffix in .msg syntax +@[ if isinstance(member.type, BoundedSequence)]@ +[<=@(member.type.maximum_size)]@ +@[ elif isinstance(member.type, UnboundedSequence)]@ +[]@ @[ elif isinstance(member.type, Array)]@ [@(member.type.size)]@ @[ end if]@ diff --git a/rosidl_generator_py/test/test_interfaces.py b/rosidl_generator_py/test/test_interfaces.py index 64225d9c..bcd30e8f 100644 --- a/rosidl_generator_py/test/test_interfaces.py +++ b/rosidl_generator_py/test/test_interfaces.py @@ -939,17 +939,17 @@ def test_string_slot_attributes() -> None: assert hasattr(msg, '__slots__') string_slot_types_dict = getattr(msg, 'get_fields_and_field_types')() expected_string_slot_types_dict = { - 'ub_string_static_array_value': 'string<5>[3]', - 'ub_string_ub_array_value': 'sequence, 10>', - 'ub_string_dynamic_array_value': 'sequence>', - 'string_dynamic_array_value': 'sequence', + 'ub_string_static_array_value': 'string<=5[3]', + 'ub_string_ub_array_value': 'string<=5[<=10]', + 'ub_string_dynamic_array_value': 'string<=5[]', + 'string_dynamic_array_value': 'string[]', 'string_static_array_value': 'string[3]', - 'string_bounded_array_value': 'sequence', - 'def_string_dynamic_array_value': 'sequence', + 'string_bounded_array_value': 'string[<=10]', + 'def_string_dynamic_array_value': 'string[]', 'def_string_static_array_value': 'string[3]', - 'def_string_bounded_array_value': 'sequence', - 'def_various_quotes': 'sequence', - 'def_various_commas': 'sequence', + 'def_string_bounded_array_value': 'string[<=10]', + 'def_various_quotes': 'string[]', + 'def_various_commas': 'string[]', } assert len(string_slot_types_dict) == len(expected_string_slot_types_dict) @@ -1012,7 +1012,7 @@ def test_builtin_sequence_slot_attributes() -> None: assert hasattr(msg, '__slots__') builtin_sequence_slot_types_dict = getattr(msg, 'get_fields_and_field_types')() expected_builtin_sequence_slot_types_dict = { - 'char_sequence_unbounded': 'sequence', + 'char_sequence_unbounded': 'char[]', } assert len(builtin_sequence_slot_types_dict) == len(expected_builtin_sequence_slot_types_dict)