Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions proto2ros/proto2ros/output/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ def dump_message_specification(message_spec: MessageSpecification) -> str:
any_type = Type(str(field.type).replace(BaseType.__str__(field.type), "proto2ros/Any"))
field = Field(any_type, field.name)
line = str(field)
# ROS IDL does not allow a package to fully qualify its own type
# references: `proto2ros/Value` must be written as `Value` when
# the field appears in a message that itself belongs to `proto2ros`.
# rosidl's type-description generator fails with a KeyError when it
# encounters a self-qualified reference. Strip the prefix here so
# the emitted .msg files conform to the rosidl convention used by
# every other ROS package.
self_pkg = message_spec.base_type.pkg_name
if field.type.pkg_name == self_pkg:
line = line.replace(f"{self_pkg}/", "", 1)
if qualifiers:
line += " # " + ", ".join(qualifiers)
output.append(line)
Expand Down
44 changes: 44 additions & 0 deletions proto2ros/proto2ros/output/test_interfaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright (c) 2024 Robotics and AI Institute LLC dba RAI Institute. All rights reserved.

"""Unit tests for proto2ros.output.interfaces."""

from rosidl_adapter.parser import Field, MessageSpecification, Type

from proto2ros.output.interfaces import dump_message_specification


def _make_spec(pkg: str, msg: str, fields: list) -> MessageSpecification:
return MessageSpecification(pkg, msg, fields, [])


def test_dump_strips_self_package_qualifier() -> None:
"""Same-package type references must not be fully qualified in .msg output.

rosidl's type-description generator fails with KeyError when a package
fully qualifies its own type references (e.g. ``proto2ros/Value`` inside
a ``proto2ros`` package message). The emitted line must use the bare
type name instead.
"""
fields = [Field(Type("proto2ros/Value[]"), "values")]
spec = _make_spec("proto2ros", "List", fields)
output = dump_message_specification(spec)
assert "proto2ros/Value" not in output, (
"self-package qualifier must be stripped from same-package field types"
)
assert "Value[] values" in output


def test_dump_preserves_cross_package_qualifier() -> None:
"""Cross-package type references must keep their fully qualified form."""
fields = [Field(Type("builtin_interfaces/Time"), "stamp")]
spec = _make_spec("my_msgs", "Header", fields)
output = dump_message_specification(spec)
assert "builtin_interfaces/Time stamp" in output


def test_dump_preserves_primitive_fields() -> None:
"""Messages with only primitive fields must be unaffected."""
spec = _make_spec("my_msgs", "Counts", [])
output = dump_message_specification(spec)
assert isinstance(output, str)