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
18 changes: 4 additions & 14 deletions rosidl_generator_py/resource/_msg_support.c.em
Original file line number Diff line number Diff line change
Expand Up @@ -678,25 +678,15 @@ if isinstance(type_, AbstractNestedType):
@(bi) Py_DECREF(field);
@(bi) return NULL;
@(bi) }
@(bi) // clear the array, poor approach to remove potential default values
@(bi) // clear the array to remove potential default values
@(bi) Py_ssize_t length = PyObject_Length(field);
@(bi) if (-1 == length) {
@(bi) Py_DECREF(field);
@(bi) return NULL;
@(bi) }
@(bi) if (length > 0) {
@(bi) PyObject * pop = PyObject_GetAttrString(field, "pop");
@(bi) assert(pop != NULL);
@(bi) for (Py_ssize_t i = 0; i < length; ++i) {
@(bi) PyObject * ret = PyObject_CallFunctionObjArgs(pop, NULL);
@(bi) if (!ret) {
@(bi) Py_DECREF(pop);
@(bi) Py_DECREF(field);
@(bi) return NULL;
@(bi) }
@(bi) Py_DECREF(ret);
@(bi) }
@(bi) Py_DECREF(pop);
@(bi) if (PySequence_DelSlice(field, 0, length) == -1) {
@(bi) Py_DECREF(field);
@(bi) return NULL;
@(bi) }
@(bi) if (ros_message->@(member.name).size > 0) {
@(bi) // populating the array.array using the frombytes method
Expand Down
71 changes: 71 additions & 0 deletions rosidl_generator_py/test/test_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
# limitations under the License.

import array
import ctypes
import math
import sys
from typing import Any

import numpy
import pytest
Expand All @@ -39,6 +41,48 @@
from rosidl_parser.definition import UnboundedString


_PY_CAPSULE_GET_POINTER = ctypes.pythonapi.PyCapsule_GetPointer
_PY_CAPSULE_GET_POINTER.argtypes = [ctypes.py_object, ctypes.c_char_p]
_PY_CAPSULE_GET_POINTER.restype = ctypes.c_void_p


def _get_capsule_pointer(capsule: object) -> int:
pointer = _PY_CAPSULE_GET_POINTER(capsule, None)
assert pointer is not None
return pointer


def _convert_through_type_support(message_type: Any, message: Any) -> Any:
message_type.__import_type_support__()
assert message_type._CREATE_ROS_MESSAGE is not None
assert message_type._CONVERT_FROM_PY is not None
assert message_type._CONVERT_TO_PY is not None
assert message_type._DESTROY_ROS_MESSAGE is not None

create_ros_message_type = ctypes.PYFUNCTYPE(ctypes.c_void_p)
convert_from_py_type = ctypes.PYFUNCTYPE(
ctypes.c_bool, ctypes.py_object, ctypes.c_void_p)
convert_to_py_type = ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)
destroy_ros_message_type = ctypes.PYFUNCTYPE(None, ctypes.c_void_p)

create_ros_message = create_ros_message_type(
_get_capsule_pointer(message_type._CREATE_ROS_MESSAGE))
convert_from_py = convert_from_py_type(
_get_capsule_pointer(message_type._CONVERT_FROM_PY))
convert_to_py = convert_to_py_type(
_get_capsule_pointer(message_type._CONVERT_TO_PY))
destroy_ros_message = destroy_ros_message_type(
_get_capsule_pointer(message_type._DESTROY_ROS_MESSAGE))

ros_message = create_ros_message()
assert ros_message is not None
try:
assert convert_from_py(message, ros_message)
return convert_to_py(ros_message)
finally:
destroy_ros_message(ros_message)


def test_basic_types() -> None:
msg = BasicTypes(check_fields=True)

Expand Down Expand Up @@ -765,6 +809,33 @@ def test_bounded_sequences() -> None:
assert msg.bool_values == [True, False]


@pytest.mark.parametrize(
('message_type', 'field_name', 'type_code', 'values'),
(
(BoundedSequences, 'char_values', 'B', [0, 1, 255]),
(BoundedSequences, 'float32_values', 'f', [0.0, 1.25, -2.5]),
(BoundedSequences, 'int16_values', 'h', [0, -32768, 32767]),
(UnboundedSequences, 'uint16_values', 'H', [0, 1, 65535]),
(UnboundedSequences, 'int32_values', 'l', [0, -2147483648, 2147483647]),
(UnboundedSequences, 'uint64_values', 'Q', [0, 1, 18446744073709551615]),
),
)
def test_primitive_sequences_convert_to_py(
message_type: Any,
field_name: str,
type_code: str,
values: list[Any],
) -> None:
msg = message_type(check_fields=True)
setattr(msg, field_name, values)

converted_msg = _convert_through_type_support(message_type, msg)
converted_field = getattr(converted_msg, field_name)

assert converted_field.typecode == type_code
assert converted_field == array.array(type_code, values)


def test_unbounded_sequences() -> None:
msg = UnboundedSequences(check_fields=True)

Expand Down