rosbridge_suite icon indicating copy to clipboard operation
rosbridge_suite copied to clipboard

rosapi tries to parse `IDL` files as `msg` files and errors

Open russkel opened this issue 11 months ago • 4 comments

Description

If there is no msg files get_interface_path will return an idl path. This is then fed into the parse_message_string function for msg files. This ends up with a lot of errors spamming in the log.

https://github.com/RobotWebTools/rosbridge_suite/blob/ros2/rosapi/src/rosapi/stringify_field_types.py#L20

https://github.com/RobotWebTools/rosbridge_suite/blob/ros2/rosapi/src/rosapi/stringify_field_types.py#L24

  • Library Version: main
  • ROS Version: Iron release
  • Platform / OS: Linux

Steps To Reproduce

Expected Behavior

Either parses IDL using the rosidl parser or errors once it detects the IDL extension and doesn't try to load it again.

Actual Behavior

[rosapi_node-19] Error processing '// generated from nmea0183_adapter/resource/msg_definition.idl.em' of 'nmea0183_msgs/UtcDateTime': '//'

russkel avatar Mar 13 '24 07:03 russkel

I think this happens for custom-built messages. I managed to implement a workaround to be able to parse them:

def extract_msg_path_from_idl(idl_path):
    with open(idl_path, 'r', encoding='utf-8') as idl_file:
        idl_content = idl_file.read()
    
    # Try to extract the original .msg file path from content. Usually in the first lines
    # there is a part that says "// with input from <path>" and path is related to the original .msg file
    msg_file_info = [line for line in idl_content.split('\n') if '// with input from' in line]
    if msg_file_info:
        msg_path = msg_file_info[0].split('// with input from')[-1].strip()
        # Remove "msg/" from the path, since the actual path doesn't have it
        msg_path = msg_path.replace('msg/', '')
        # Find parent directory of the idl just before the share folder
        share_dir = idl_path.split('share')[0]
        # Construct the full path to the .msg file
        return os.path.join(share_dir, 'share', msg_path)
    
    return idl_path

def stringify_field_types(root_type):
    definition = ""
    seen_types = set()
    deps = [root_type]
    is_root = True
    while deps:
        ty = deps.pop()
        parts = ty.split("/")
        if not is_root:
            definition += "\n================================================================================\n"
            definition += f"MSG: {ty}\n"
        is_root = False

        msg_name = parts[2] if len(parts) == 3 else parts[1]
        interface_name = ty if len(parts) == 3 else f"{parts[0]}/msg/{parts[1]}"

        # Try to get the .msg file first
        msg_path = get_interface_path(interface_name)

        # If custom we get instead the .idl implementation
        if msg_path.endswith('.idl'):
            msg_path = extract_msg_path_from_idl(msg_path)

        with open(msg_path, encoding="utf-8") as msg_file:
            msg_definition = msg_file.read()
        definition += msg_definition

        spec = parse_message_string(parts[0], msg_name, msg_definition)
        for field in spec.fields:
            is_builtin = field.type.pkg_name is None
            if not is_builtin:
                field_ty = f"{field.type.pkg_name}/{field.type.type}"
                if field_ty not in seen_types:
                    deps.append(field_ty)
                    seen_types.add(field_ty)

    return definition

Hope it helps

charlielito avatar Jun 21 '24 03:06 charlielito

I have a PR on rosidl_parser which adds a parser for IDL files, but as per tradition it just sits there unreviewed.

Thanks for your patch, but we stopped using rosbridge and changed to foxbridge due to performance increases.

russkel avatar Jun 22 '24 04:06 russkel

@russkel can you point me to the PR url? Thanks!

charlielito avatar Jun 24 '24 15:06 charlielito

https://github.com/ros2/rosidl/pull/697

@russkel can you point me to the PR url? Thanks!

russkel avatar Jun 24 '24 23:06 russkel