Skip to content
Closed
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
2 changes: 2 additions & 0 deletions rosidl_runtime_py/rosidl_runtime_py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
from .convert import message_to_csv
from .convert import message_to_ordereddict
from .convert import message_to_yaml
from .import_message import import_message_type
from .set_message import set_message_fields


__all__ = [
'import_message_type',
'message_to_csv',
'message_to_ordereddict',
'message_to_yaml',
Expand Down
33 changes: 33 additions & 0 deletions rosidl_runtime_py/rosidl_runtime_py/import_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2017-2019 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import importlib


def import_message_type(topic_name: str, message_type: str):
# TODO(dirk-thomas) this logic should come from a rosidl related package
try:
package_name, message_name = message_type.split('/', 2)
if not package_name or not message_name:
raise ValueError()
except ValueError:
raise RuntimeError('The passed message type is invalid')

# TODO(sloretz) node API to get topic types should indicate if action or msg
middle_module = 'msg'
if topic_name.endswith('/_action/feedback'):
middle_module = 'action'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once this problem has been addressed the API would not need to take topic_name anymore which would break users. Therefore I don't think this API should added as-is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect in the future the import function to be something like https://github.com/ros2/rosidl_python/pull/33/files#diff-2283820db2117771f9254b0ff5ac87f0 using the abstract types.

What would be an acceptable API in the meantime? a keyword argument for the topic_name that would default to an empty string? (note that it would still break API the day that keyword argument is removed).

Or would you rather keep the original function in ros2topic and make a duplicated function here without this argument at all ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather not add API here which is known that it needs to change as soon as something else gets fixed. So for now the API can stay were it is and once a stable API can be created it can land in the rosidl_runtime_py package.

Also I just created #54 which adds the SLOT_TYPES to each message. Maybe that is sufficient for what you want to achieve?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, just to clarify my understanding:
The suggestion is to use the SLOT_TYPES from #54
introduce here the new import_message_from_namespaced_type from #33
and modify set_message to use these 2 new bits in order to fill Nested ROS messages

Is that right ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that should work.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright I integrated the changes from #54 and updated #33 accordingly.


module = importlib.import_module(package_name + '.' + middle_module)
return getattr(module, message_name)
15 changes: 15 additions & 0 deletions rosidl_runtime_py/rosidl_runtime_py/set_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from typing import Any
from typing import Dict

from rosidl_runtime_py.import_message import import_message_type


def set_message_fields(msg: Any, values: Dict[str, str]) -> None:
"""
Expand All @@ -33,4 +35,17 @@ def set_message_fields(msg: Any, values: Dict[str, str]) -> None:
except TypeError:
value = field_type()
set_message_fields(value, field_value)
f_type = msg.get_fields_and_field_types()[field_name]
# Check if field is an array of ROS message types
if f_type.find('/') != -1:
if isinstance(field_type(), list):
# strip the 'sequence<' prefix if it is a sequence
if f_type.startswith('sequence'):
f_type = f_type[len('sequence') + 1:]
f_type = f_type[:f_type.rfind('[')]
field_elem_type = import_message_type('', f_type)
for n in range(len(value)):
submsg = field_elem_type()
set_message_fields(submsg, value[n])
value[n] = submsg
setattr(msg, field_name, value)
36 changes: 36 additions & 0 deletions rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,39 @@ def test_set_message_fields_invalid():
invalid_type['int32_value'] = 'this is not an integer'
with pytest.raises(ValueError):
set_message_fields(msg, invalid_type)


def test_set_nested_namespaced_fields():
unbounded_sequence_msg = message_fixtures.get_msg_unbounded_sequences()[1]
test_values = {
'basic_types_values': [
{'float64_value': 42.42, 'int8_value': 42},
{'float64_value': 11.11, 'int8_value': 11}
]
}
set_message_fields(unbounded_sequence_msg, test_values)
assert unbounded_sequence_msg.basic_types_values[0].float64_value == 42.42
assert unbounded_sequence_msg.basic_types_values[0].int8_value == 42
assert unbounded_sequence_msg.basic_types_values[0].uint8_value == 0
assert unbounded_sequence_msg.basic_types_values[1].float64_value == 11.11
assert unbounded_sequence_msg.basic_types_values[1].int8_value == 11
assert unbounded_sequence_msg.basic_types_values[1].uint8_value == 0

arrays_msg = message_fixtures.get_msg_arrays()[0]
test_values = {
'basic_types_values': [
{'float64_value': 42.42, 'int8_value': 42},
{'float64_value': 11.11, 'int8_value': 11},
{'float64_value': 22.22, 'int8_value': 22},
]
}
set_message_fields(arrays_msg, test_values)
assert arrays_msg.basic_types_values[0].float64_value == 42.42
assert arrays_msg.basic_types_values[0].int8_value == 42
assert arrays_msg.basic_types_values[0].uint8_value == 0
assert arrays_msg.basic_types_values[1].float64_value == 11.11
assert arrays_msg.basic_types_values[1].int8_value == 11
assert arrays_msg.basic_types_values[1].uint8_value == 0
assert arrays_msg.basic_types_values[2].float64_value == 22.22
assert arrays_msg.basic_types_values[2].int8_value == 22
assert arrays_msg.basic_types_values[2].uint8_value == 0