Skip to content

Handling a byte with message_to_yaml and set_message_fields #14

@squizz617

Description

@squizz617

Hi,
I came across an issue of set_message_fields not handling the Byte type correctly. Please take a look at the cases below.

Cases

  1. Directly via ros2cli
$ ros2 topic pub --once /dummy_topic std_msgs/Byte '{data: "\x00"}'
Failed to populate field: Value '' is expected to be a dictionary but is a str
$ ros2 topic pub --once /dummy_topic std_msgs/Byte "{data: '\x00'}"
Failed to populate field: Value '\x00' is expected to be a dictionary but is a str
  1. Invoking message_to_yaml and then set_message_fields
#!/usr/bin/python3

from rosidl_runtime_py import set_message_fields, message_to_yaml
import yaml
from std_msgs.msg import Byte

msg = Byte()
print(msg) # std_msgs.msg.Byte(data=b'\x00')
msg_yaml = message_to_yaml(msg)
print(msg_yaml) # data: "\0"

# mimic the behavior of ros2 topic pub
values_dictionary = yaml.safe_load(msg_yaml)
print(values_dictionary) # {'data': '\x00'}
set_message_fields(msg, values_dictionary) # fails

I end up getting the following error:

Traceback (most recent call last):
  File "/opt/ros/foxy/lib/python3.8/site-packages/rosidl_runtime_py/set_message.py", line 55, in set_message_fields
    value = field_type(field_value)
TypeError: string argument without an encoding

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/ros/foxy/lib/python3.8/site-packages/rosidl_runtime_py/set_message.py", line 39, in set_message_fields
    items = values.items()
AttributeError: 'str' object has no attribute 'items'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "p.py", line 8, in <module>
    set_message_fields(msg, values_dictionary)
  File "/opt/ros/foxy/lib/python3.8/site-packages/rosidl_runtime_py/set_message.py", line 58, in set_message_fields
    set_message_fields(value, field_value)
  File "/opt/ros/foxy/lib/python3.8/site-packages/rosidl_runtime_py/set_message.py", line 41, in set_message_fields
    raise TypeError(
TypeError: Value '' is expected to be a dictionary but is a str

Reason

When message_to_yaml processes a message and returns a YAML string, the byte string is no longer of type 'byte' because _convert_value coverts the byte to a string. When this YAML string is loaded as a dictionary through yaml.safe_load(values) and set_message_fields is invoked with this dictionary, the data e.g., "\x00", is regarded as a string, while the type information claims it's a byte.

Thoughts / suggestions

I am aware that a byte-typed data can be published via the following command:

$ ros2 topic pub --once /dummy std_msgs/Byte "{data: {0}}" 

However, as per the docstring, message_to_yaml "Converts a ROS message to a YAML string", and ros2 topic pub takes args as a YAML string (doc), an attempt to publish a byte message converted with message_to_yaml should not fail.

In addition, ros2interface proto, which relies on message_to_yaml to show the prototype of a message, prints the following result, which can mislead the users into trying to publish a byte as advised and fail.

$ ros2 interface proto std_msgs/msg/Byte
"data: "\0"
"

$ ros2 topic pub --once /dummy std_msgs/Byte "{data: '\0'}"
Failed to populate field: Value '\0' is expected to be a dictionary but is a str

So, I think either

  • message_to_yaml should return "data: {value}" if datatype is byte, or
  • set_message_fields should be modified to be able to tell a string from an escaped byte..

What do you think?
Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions