From 1b8d5128933dbb16e1652a43b62de7356237b5cc Mon Sep 17 00:00:00 2001 From: Mikael Arguedas Date: Wed, 13 Mar 2019 23:46:16 +0100 Subject: [PATCH 1/4] store types as constant and return ordered dict Signed-off-by: Mikael Arguedas update tests Signed-off-by: Mikael Arguedas simplify logic by printing member type directly Signed-off-by: Mikael Arguedas move dict construction to rosidl_runtime_py Signed-off-by: Mikael Arguedas add utility to import complex message and add support for nested array in set_message Signed-off-by: Mikael Arguedas update tests and remove coverage for dict to avoid circular dependency Signed-off-by: Mikael Arguedas more descriptive variable name Signed-off-by: Mikael Arguedas refactor import logic according to #35 Signed-off-by: Mikael Arguedas move imports to top of file Signed-off-by: Mikael Arguedas string maximum size doesn't need quoting or str conversion Signed-off-by: Mikael Arguedas update docblock Signed-off-by: Mikael Arguedas slot_types_dict_from_message -> get_message_slot_types Signed-off-by: Mikael Arguedas check Abstrct type instead of 'list' Signed-off-by: Mikael Arguedas use NestedType Signed-off-by: Mikael Arguedas add conditional is namespaces is an empty list Signed-off-by: Mikael Arguedas one liner Signed-off-by: Mikael Arguedas extend test suite to cover NesteTypes of NamespacedTypes Signed-off-by: Mikael Arguedas single message fixture to use Signed-off-by: Mikael Arguedas use NestedType Signed-off-by: Mikael Arguedas add coverage for static array of nested messages Signed-off-by: Mikael Arguedas restore old API Signed-off-by: Mikael Arguedas SLOT_TYPES improvement from dirk-thomas Signed-off-by: Mikael Arguedas resolve conflicts Signed-off-by: Mikael Arguedas --- rosidl_generator_py/resource/_msg.py.em | 37 ++++++ rosidl_generator_py/test/test_interfaces.py | 108 ++++++++++-------- rosidl_runtime_py/package.xml | 1 + .../rosidl_runtime_py/__init__.py | 4 + .../rosidl_runtime_py/convert.py | 10 ++ .../rosidl_runtime_py/import_message.py | 24 ++++ .../rosidl_runtime_py/set_message.py | 14 +++ .../rosidl_runtime_py/test_set_message.py | 40 +++++++ 8 files changed, 190 insertions(+), 48 deletions(-) create mode 100644 rosidl_runtime_py/rosidl_runtime_py/import_message.py diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 976aee32..4b815280 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -22,6 +22,7 @@ from rosidl_parser.definition import FLOATING_POINT_TYPES from rosidl_parser.definition import INTEGER_TYPES from rosidl_parser.definition import NamespacedType from rosidl_parser.definition import SIGNED_INTEGER_TYPES +from rosidl_parser.definition import UnboundedSequence from rosidl_parser.definition import UNSIGNED_INTEGER_TYPES }@ @#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -30,6 +31,9 @@ from rosidl_parser.definition import UNSIGNED_INTEGER_TYPES from collections import OrderedDict import numpy imports = OrderedDict() +if message.structure.members: + imports.setdefault( + 'import rosidl_parser.definition', []) # used for SLOT_TYPES for member in message.structure.members: if ( isinstance(member.type, AbstractNestedType) and @@ -227,6 +231,39 @@ string@ @[end for]@ } + SLOT_TYPES = ( +@[for member in message.structure.members]@ +@{ +type_ = member.type +if isinstance(type_, AbstractNestedType): + type_ = type_.value_type +}@ + @ +@[ if isinstance(member.type, AbstractNestedType)]@ +@(member.type.__class__.__module__).@(member.type.__class__.__name__)(@ +@[ end if]@ +@# the typename of the non-nested type or the nested value_type +@(type_.__class__.__module__).@(type_.__class__.__name__)(@ +@[ if isinstance(type_, BasicType)]@ +'@(type_.typename)'@ +@[ elif isinstance(type_, AbstractGenericString) and type_.has_maximum_size()]@ +@(type_.maximum_size)@ +@[ elif isinstance(type_, NamespacedType)]@ +[@(', '.join("'%s'" % n for n in type_.namespaces))], '@(type_.name)'@ +@[ end if]@ +)@ +@[ if isinstance(member.type, Array)]@ +, @(member.type.size)@ +@[ elif isinstance(member.type, BoundedSequence)]@ +, @(member.type.maximum_size)@ +@[ end if]@ +@[ if isinstance(member.type, AbstractNestedType)]@ +)@ +@[ end if]@ +, # noqa: E501 +@[end for]@ + ) + def __init__(self, **kwargs): assert all('_' + key in self.__slots__ for key in kwargs.keys()), \ 'Invalid arguments passed to constructor: %s' % \ diff --git a/rosidl_generator_py/test/test_interfaces.py b/rosidl_generator_py/test/test_interfaces.py index e4a7cf59..077b6cc6 100644 --- a/rosidl_generator_py/test/test_interfaces.py +++ b/rosidl_generator_py/test/test_interfaces.py @@ -16,6 +16,7 @@ import numpy import pytest + from rosidl_generator_py.msg import Constants from rosidl_generator_py.msg import Nested from rosidl_generator_py.msg import Primitives @@ -24,6 +25,12 @@ from rosidl_generator_py.msg import Various from rosidl_generator_py.msg import WStrings +from rosidl_parser.definition import Array +from rosidl_parser.definition import BoundedSequence +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import String +from rosidl_parser.definition import UnboundedSequence + def test_strings(): a = Strings() @@ -296,56 +303,61 @@ def test_out_of_range(): def test_slot_attributes(): a = Nested() - assert hasattr(a, 'get_fields_and_field_types') + assert hasattr(a, 'SLOT_TYPES') assert hasattr(a, '__slots__') - nested_slot_types_dict = getattr(a, 'get_fields_and_field_types')() + nested_slot_types = Nested.SLOT_TYPES nested_slots = getattr(a, '__slots__') - assert len(nested_slot_types_dict) == len(nested_slots) - expected_nested_slot_types_dict = { - 'primitives': 'rosidl_generator_py/Primitives', - 'two_primitives': 'rosidl_generator_py/Primitives[2]', - 'up_to_three_primitives': 'sequence', - 'unbounded_primitives': 'sequence', - } - assert len(nested_slot_types_dict) == len(expected_nested_slot_types_dict) - - for expected_field, expected_slot_type in expected_nested_slot_types_dict.items(): - assert expected_field in nested_slot_types_dict.keys() - assert expected_slot_type == nested_slot_types_dict[expected_field] - - -def test_primative_slot_attributes(): + assert len(nested_slot_types) == len(nested_slots) + assert isinstance(nested_slot_types[0], NamespacedType) + assert nested_slot_types[0].namespaces == ['rosidl_generator_py', 'msg'] + assert nested_slot_types[0].name == 'Primitives' + + assert isinstance(nested_slot_types[1], Array) + assert isinstance(nested_slot_types[1].basetype, NamespacedType) + assert nested_slot_types[1].basetype.namespaces == \ + ['rosidl_generator_py', 'msg'] + assert nested_slot_types[1].basetype.name == 'Primitives' + + assert isinstance(nested_slot_types[2], BoundedSequence) + assert isinstance(nested_slot_types[2].basetype, NamespacedType) + assert nested_slot_types[2].basetype.namespaces == \ + ['rosidl_generator_py', 'msg'] + assert nested_slot_types[2].basetype.name == 'Primitives' + + assert isinstance(nested_slot_types[3], UnboundedSequence) + assert isinstance(nested_slot_types[3].basetype, NamespacedType) + assert nested_slot_types[3].basetype.namespaces == \ + ['rosidl_generator_py', 'msg'] + assert nested_slot_types[3].basetype.name == 'Primitives' + + +def test_string_slot_attributes(): b = StringArrays() - assert hasattr(b, 'get_fields_and_field_types') + assert hasattr(b, 'SLOT_TYPES') assert hasattr(b, '__slots__') - string_slot_types_dict = getattr(b, 'get_fields_and_field_types')() + string_slot_types = StringArrays.SLOT_TYPES string_slots = getattr(b, '__slots__') - assert len(string_slot_types_dict) == len(string_slots) - expected_string_slot_types_dict = { - 'ub_string_static_array_value': 'string<5>[3]', - 'ub_string_ub_array_value': 'sequence, 10>', - 'ub_string_dynamic_array_value': 'sequence>', - 'string_dynamic_array_value': 'sequence', - 'string_static_array_value': 'string[3]', - 'string_bounded_array_value': 'sequence', - 'def_string_dynamic_array_value': 'sequence', - 'def_string_static_array_value': 'string[3]', - 'def_string_bounded_array_value': 'sequence', - 'def_various_quotes': 'sequence', - 'def_various_commas': 'sequence', - } - - assert len(string_slot_types_dict) == len(expected_string_slot_types_dict) - - for expected_field, expected_slot_type in expected_string_slot_types_dict.items(): - assert expected_field in string_slot_types_dict.keys() - assert expected_slot_type == string_slot_types_dict[expected_field] - - -def test_modifying_slot_fields_and_types(): - b = StringArrays() - assert hasattr(b, 'get_fields_and_field_types') - string_slot_types_dict = getattr(b, 'get_fields_and_field_types')() - string_slot_types_dict_len = len(string_slot_types_dict) - string_slot_types_dict[1] = 2 - assert len(getattr(b, 'get_fields_and_field_types')()) == string_slot_types_dict_len + assert len(string_slot_types) == len(string_slots) + + assert isinstance(string_slot_types[0], Array) + assert isinstance(string_slot_types[0].basetype, String) + assert string_slot_types[0].size == 3 + assert string_slot_types[0].basetype.maximum_size == 5 + + assert isinstance(string_slot_types[1], BoundedSequence) + assert isinstance(string_slot_types[1].basetype, String) + assert string_slot_types[1].upper_bound == 10 + assert string_slot_types[1].basetype.maximum_size == 5 + + assert isinstance(string_slot_types[2], UnboundedSequence) + assert isinstance(string_slot_types[2].basetype, String) + assert string_slot_types[2].basetype.maximum_size == 5 + + assert isinstance(string_slot_types[3], UnboundedSequence) + assert isinstance(string_slot_types[3].basetype, String) + assert string_slot_types[3].basetype.maximum_size is None + + assert isinstance(string_slot_types[4], Array) + assert isinstance(string_slot_types[4].basetype, String) + assert string_slot_types[4].size == 3 + assert string_slot_types[4].basetype.maximum_size is None diff --git a/rosidl_runtime_py/package.xml b/rosidl_runtime_py/package.xml index 9139c9a7..2de8eb66 100644 --- a/rosidl_runtime_py/package.xml +++ b/rosidl_runtime_py/package.xml @@ -11,6 +11,7 @@ python3-numpy python3-yaml + rosidl_parser ament_copyright ament_flake8 diff --git a/rosidl_runtime_py/rosidl_runtime_py/__init__.py b/rosidl_runtime_py/rosidl_runtime_py/__init__.py index 5f40b2ed..7a71aa92 100644 --- a/rosidl_runtime_py/rosidl_runtime_py/__init__.py +++ b/rosidl_runtime_py/rosidl_runtime_py/__init__.py @@ -12,13 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +from .convert import get_message_slot_types from .convert import message_to_csv from .convert import message_to_ordereddict from .convert import message_to_yaml +from .import_message import import_message_from_namespaced_type from .set_message import set_message_fields __all__ = [ + 'get_message_slot_types', + 'import_message_from_namespaced_type', 'message_to_csv', 'message_to_ordereddict', 'message_to_yaml', diff --git a/rosidl_runtime_py/rosidl_runtime_py/convert.py b/rosidl_runtime_py/rosidl_runtime_py/convert.py index fc783f13..1babe73c 100644 --- a/rosidl_runtime_py/rosidl_runtime_py/convert.py +++ b/rosidl_runtime_py/rosidl_runtime_py/convert.py @@ -154,3 +154,13 @@ def _convert_value(value, truncate_length=None): # Assuming value is a message since it is neither a collection nor a primitive type value = message_to_ordereddict(value, truncate_length=truncate_length) return value + + +def get_message_slot_types(msg: Any) -> OrderedDict: + """ + Return an OrderedDict of the slot types of a message. + + :param msg: The ROS message to get members types from. + :returns: An OrderedDict with message member names as keys and slot types as values. + """ + return OrderedDict(zip([s[1:] for s in msg.__slots__], msg.SLOT_TYPES)) diff --git a/rosidl_runtime_py/rosidl_runtime_py/import_message.py b/rosidl_runtime_py/rosidl_runtime_py/import_message.py new file mode 100644 index 00000000..22e4d293 --- /dev/null +++ b/rosidl_runtime_py/rosidl_runtime_py/import_message.py @@ -0,0 +1,24 @@ +# Copyright 2019 Mikael Arguedas. +# +# 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 +from typing import Any + +from rosidl_parser.definition import NamespacedType + + +def import_message_from_namespaced_type(message_type: NamespacedType) -> Any: + module = importlib.import_module( + '.'.join(message_type.basetype.namespaces)) + return getattr(module, message_type.basetype.name) diff --git a/rosidl_runtime_py/rosidl_runtime_py/set_message.py b/rosidl_runtime_py/rosidl_runtime_py/set_message.py index cfb36563..fd4e431b 100644 --- a/rosidl_runtime_py/rosidl_runtime_py/set_message.py +++ b/rosidl_runtime_py/rosidl_runtime_py/set_message.py @@ -15,6 +15,11 @@ from typing import Any from typing import Dict +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_runtime_py.convert import get_message_slot_types +from rosidl_runtime_py.import_message import import_message_from_namespaced_type + def set_message_fields(msg: Any, values: Dict[str, str]) -> None: """ @@ -33,4 +38,13 @@ def set_message_fields(msg: Any, values: Dict[str, str]) -> None: except TypeError: value = field_type() set_message_fields(value, field_value) + rosidl_type = get_message_slot_types(msg)[field_name] + # Check if field is an array of ROS messages + if isinstance(rosidl_type, NestedType): + if isinstance(rosidl_type.basetype, NamespacedType): + field_elem_type = import_message_from_namespaced_type(rosidl_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) diff --git a/rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py b/rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py index a74a6d92..c4e4ff69 100644 --- a/rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py +++ b/rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py @@ -91,3 +91,43 @@ 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(): + msg = message_fixtures.get_msg_dynamic_array_nested()[0] + test_values = { + 'primitive_values': [ + {'string_value': 'foo', 'int8_value': 42}, + {'string_value': 'bar', 'int8_value': 11} + ] + } + set_message_fields(msg, test_values) + assert msg.primitive_values[0].string_value == 'foo' + assert msg.primitive_values[0].int8_value == 42 + assert msg.primitive_values[0].uint8_value == 0 + assert msg.primitive_values[1].string_value == 'bar' + assert msg.primitive_values[1].int8_value == 11 + assert msg.primitive_values[1].uint8_value == 0 + + static_array_msg = message_fixtures.get_msg_static_array_nested()[0] + test_values = { + 'primitive_values': [ + {'string_value': 'foo', 'int8_value': 42}, + {'string_value': 'bar', 'int8_value': 11}, + {'string_value': 'baz', 'int8_value': 22}, + {'string_value': 'foobar', 'int8_value': 33} + ] + } + set_message_fields(static_array_msg, test_values) + assert static_array_msg.primitive_values[0].string_value == 'foo' + assert static_array_msg.primitive_values[0].int8_value == 42 + assert static_array_msg.primitive_values[0].uint8_value == 0 + assert static_array_msg.primitive_values[1].string_value == 'bar' + assert static_array_msg.primitive_values[1].int8_value == 11 + assert static_array_msg.primitive_values[1].uint8_value == 0 + assert static_array_msg.primitive_values[2].string_value == 'baz' + assert static_array_msg.primitive_values[2].int8_value == 22 + assert static_array_msg.primitive_values[2].uint8_value == 0 + assert static_array_msg.primitive_values[3].string_value == 'foobar' + assert static_array_msg.primitive_values[3].int8_value == 33 + assert static_array_msg.primitive_values[3].uint8_value == 0 From e2443adf6e677ba34310eeb645287291acdbd32d Mon Sep 17 00:00:00 2001 From: Mikael Arguedas Date: Fri, 3 May 2019 01:42:39 +0200 Subject: [PATCH 2/4] add back I100 ignore Signed-off-by: Mikael Arguedas --- rosidl_generator_py/resource/_msg.py.em | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 4b815280..f10ae370 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -69,7 +69,7 @@ for member in message.structure.members: @(import_statement)@ @[ if import_statement not in import_statements]@ @{import_statements.add(import_statement)}@ - # noqa: E402@ + # noqa: E402, I100@ @[ end if] @[ end for]@ @[end if]@ From d6589fd158a2ca40ece01903442ee83d05c66717 Mon Sep 17 00:00:00 2001 From: Mikael Arguedas Date: Fri, 3 May 2019 01:43:29 +0200 Subject: [PATCH 3/4] use new rosidl_parser.definition types and new test interfaces Signed-off-by: Mikael Arguedas --- rosidl_generator_py/test/test_interfaces.py | 41 +++++++------ .../rosidl_runtime_py/import_message.py | 4 +- .../rosidl_runtime_py/set_message.py | 6 +- .../rosidl_runtime_py/test_set_message.py | 58 +++++++++---------- 4 files changed, 52 insertions(+), 57 deletions(-) diff --git a/rosidl_generator_py/test/test_interfaces.py b/rosidl_generator_py/test/test_interfaces.py index 077b6cc6..47d84776 100644 --- a/rosidl_generator_py/test/test_interfaces.py +++ b/rosidl_generator_py/test/test_interfaces.py @@ -27,9 +27,10 @@ from rosidl_parser.definition import Array from rosidl_parser.definition import BoundedSequence +from rosidl_parser.definition import BoundedString from rosidl_parser.definition import NamespacedType -from rosidl_parser.definition import String from rosidl_parser.definition import UnboundedSequence +from rosidl_parser.definition import UnboundedString def test_strings(): @@ -313,22 +314,22 @@ def test_slot_attributes(): assert nested_slot_types[0].name == 'Primitives' assert isinstance(nested_slot_types[1], Array) - assert isinstance(nested_slot_types[1].basetype, NamespacedType) - assert nested_slot_types[1].basetype.namespaces == \ + assert isinstance(nested_slot_types[1].value_type, NamespacedType) + assert nested_slot_types[1].value_type.namespaces == \ ['rosidl_generator_py', 'msg'] - assert nested_slot_types[1].basetype.name == 'Primitives' + assert nested_slot_types[1].value_type.name == 'Primitives' assert isinstance(nested_slot_types[2], BoundedSequence) - assert isinstance(nested_slot_types[2].basetype, NamespacedType) - assert nested_slot_types[2].basetype.namespaces == \ + assert isinstance(nested_slot_types[2].value_type, NamespacedType) + assert nested_slot_types[2].value_type.namespaces == \ ['rosidl_generator_py', 'msg'] - assert nested_slot_types[2].basetype.name == 'Primitives' + assert nested_slot_types[2].value_type.name == 'Primitives' assert isinstance(nested_slot_types[3], UnboundedSequence) - assert isinstance(nested_slot_types[3].basetype, NamespacedType) - assert nested_slot_types[3].basetype.namespaces == \ + assert isinstance(nested_slot_types[3].value_type, NamespacedType) + assert nested_slot_types[3].value_type.namespaces == \ ['rosidl_generator_py', 'msg'] - assert nested_slot_types[3].basetype.name == 'Primitives' + assert nested_slot_types[3].value_type.name == 'Primitives' def test_string_slot_attributes(): @@ -340,24 +341,22 @@ def test_string_slot_attributes(): assert len(string_slot_types) == len(string_slots) assert isinstance(string_slot_types[0], Array) - assert isinstance(string_slot_types[0].basetype, String) + assert isinstance(string_slot_types[0].value_type, BoundedString) assert string_slot_types[0].size == 3 - assert string_slot_types[0].basetype.maximum_size == 5 + assert string_slot_types[0].value_type.maximum_size == 5 assert isinstance(string_slot_types[1], BoundedSequence) - assert isinstance(string_slot_types[1].basetype, String) - assert string_slot_types[1].upper_bound == 10 - assert string_slot_types[1].basetype.maximum_size == 5 + assert isinstance(string_slot_types[1].value_type, BoundedString) + assert string_slot_types[1].maximum_size == 10 + assert string_slot_types[1].value_type.maximum_size == 5 assert isinstance(string_slot_types[2], UnboundedSequence) - assert isinstance(string_slot_types[2].basetype, String) - assert string_slot_types[2].basetype.maximum_size == 5 + assert isinstance(string_slot_types[2].value_type, BoundedString) + assert string_slot_types[2].value_type.maximum_size == 5 assert isinstance(string_slot_types[3], UnboundedSequence) - assert isinstance(string_slot_types[3].basetype, String) - assert string_slot_types[3].basetype.maximum_size is None + assert isinstance(string_slot_types[3].value_type, UnboundedString) assert isinstance(string_slot_types[4], Array) - assert isinstance(string_slot_types[4].basetype, String) + assert isinstance(string_slot_types[4].value_type, UnboundedString) assert string_slot_types[4].size == 3 - assert string_slot_types[4].basetype.maximum_size is None diff --git a/rosidl_runtime_py/rosidl_runtime_py/import_message.py b/rosidl_runtime_py/rosidl_runtime_py/import_message.py index 22e4d293..ceb11ad8 100644 --- a/rosidl_runtime_py/rosidl_runtime_py/import_message.py +++ b/rosidl_runtime_py/rosidl_runtime_py/import_message.py @@ -20,5 +20,5 @@ def import_message_from_namespaced_type(message_type: NamespacedType) -> Any: module = importlib.import_module( - '.'.join(message_type.basetype.namespaces)) - return getattr(module, message_type.basetype.name) + '.'.join(message_type.value_type.namespaces)) + return getattr(module, message_type.value_type.name) diff --git a/rosidl_runtime_py/rosidl_runtime_py/set_message.py b/rosidl_runtime_py/rosidl_runtime_py/set_message.py index fd4e431b..d84a7a4d 100644 --- a/rosidl_runtime_py/rosidl_runtime_py/set_message.py +++ b/rosidl_runtime_py/rosidl_runtime_py/set_message.py @@ -15,8 +15,8 @@ from typing import Any from typing import Dict +from rosidl_parser.definition import AbstractNestedType from rosidl_parser.definition import NamespacedType -from rosidl_parser.definition import NestedType from rosidl_runtime_py.convert import get_message_slot_types from rosidl_runtime_py.import_message import import_message_from_namespaced_type @@ -40,8 +40,8 @@ def set_message_fields(msg: Any, values: Dict[str, str]) -> None: set_message_fields(value, field_value) rosidl_type = get_message_slot_types(msg)[field_name] # Check if field is an array of ROS messages - if isinstance(rosidl_type, NestedType): - if isinstance(rosidl_type.basetype, NamespacedType): + if isinstance(rosidl_type, AbstractNestedType): + if isinstance(rosidl_type.value_type, NamespacedType): field_elem_type = import_message_from_namespaced_type(rosidl_type) for n in range(len(value)): submsg = field_elem_type() diff --git a/rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py b/rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py index c4e4ff69..4f178d65 100644 --- a/rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py +++ b/rosidl_runtime_py/test/rosidl_runtime_py/test_set_message.py @@ -94,40 +94,36 @@ def test_set_message_fields_invalid(): def test_set_nested_namespaced_fields(): - msg = message_fixtures.get_msg_dynamic_array_nested()[0] + unbounded_sequence_msg = message_fixtures.get_msg_unbounded_sequences()[1] test_values = { - 'primitive_values': [ - {'string_value': 'foo', 'int8_value': 42}, - {'string_value': 'bar', 'int8_value': 11} + 'basic_types_values': [ + {'float64_value': 42.42, 'int8_value': 42}, + {'float64_value': 11.11, 'int8_value': 11} ] } - set_message_fields(msg, test_values) - assert msg.primitive_values[0].string_value == 'foo' - assert msg.primitive_values[0].int8_value == 42 - assert msg.primitive_values[0].uint8_value == 0 - assert msg.primitive_values[1].string_value == 'bar' - assert msg.primitive_values[1].int8_value == 11 - assert msg.primitive_values[1].uint8_value == 0 - - static_array_msg = message_fixtures.get_msg_static_array_nested()[0] + 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 = { - 'primitive_values': [ - {'string_value': 'foo', 'int8_value': 42}, - {'string_value': 'bar', 'int8_value': 11}, - {'string_value': 'baz', 'int8_value': 22}, - {'string_value': 'foobar', 'int8_value': 33} + '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(static_array_msg, test_values) - assert static_array_msg.primitive_values[0].string_value == 'foo' - assert static_array_msg.primitive_values[0].int8_value == 42 - assert static_array_msg.primitive_values[0].uint8_value == 0 - assert static_array_msg.primitive_values[1].string_value == 'bar' - assert static_array_msg.primitive_values[1].int8_value == 11 - assert static_array_msg.primitive_values[1].uint8_value == 0 - assert static_array_msg.primitive_values[2].string_value == 'baz' - assert static_array_msg.primitive_values[2].int8_value == 22 - assert static_array_msg.primitive_values[2].uint8_value == 0 - assert static_array_msg.primitive_values[3].string_value == 'foobar' - assert static_array_msg.primitive_values[3].int8_value == 33 - assert static_array_msg.primitive_values[3].uint8_value == 0 + 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 From 64003b61461ea473738f527d1715d1aa25a86c61 Mon Sep 17 00:00:00 2001 From: Mikael Arguedas Date: Fri, 3 May 2019 01:49:05 +0200 Subject: [PATCH 4/4] restore original test, add test for SLOT_TYPES Signed-off-by: Mikael Arguedas --- rosidl_generator_py/test/test_interfaces.py | 59 ++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/rosidl_generator_py/test/test_interfaces.py b/rosidl_generator_py/test/test_interfaces.py index 47d84776..6c4f23e0 100644 --- a/rosidl_generator_py/test/test_interfaces.py +++ b/rosidl_generator_py/test/test_interfaces.py @@ -303,6 +303,63 @@ def test_out_of_range(): def test_slot_attributes(): + a = Nested() + assert hasattr(a, 'get_fields_and_field_types') + assert hasattr(a, '__slots__') + nested_slot_types_dict = getattr(a, 'get_fields_and_field_types')() + nested_slots = getattr(a, '__slots__') + assert len(nested_slot_types_dict) == len(nested_slots) + expected_nested_slot_types_dict = { + 'primitives': 'rosidl_generator_py/Primitives', + 'two_primitives': 'rosidl_generator_py/Primitives[2]', + 'up_to_three_primitives': 'sequence', + 'unbounded_primitives': 'sequence', + } + assert len(nested_slot_types_dict) == len(expected_nested_slot_types_dict) + + for expected_field, expected_slot_type in expected_nested_slot_types_dict.items(): + assert expected_field in nested_slot_types_dict.keys() + assert expected_slot_type == nested_slot_types_dict[expected_field] + + +def test_string_slot_attributes(): + b = StringArrays() + assert hasattr(b, 'get_fields_and_field_types') + assert hasattr(b, '__slots__') + string_slot_types_dict = getattr(b, 'get_fields_and_field_types')() + string_slots = getattr(b, '__slots__') + assert len(string_slot_types_dict) == len(string_slots) + expected_string_slot_types_dict = { + 'ub_string_static_array_value': 'string<5>[3]', + 'ub_string_ub_array_value': 'sequence, 10>', + 'ub_string_dynamic_array_value': 'sequence>', + 'string_dynamic_array_value': 'sequence', + 'string_static_array_value': 'string[3]', + 'string_bounded_array_value': 'sequence', + 'def_string_dynamic_array_value': 'sequence', + 'def_string_static_array_value': 'string[3]', + 'def_string_bounded_array_value': 'sequence', + 'def_various_quotes': 'sequence', + 'def_various_commas': 'sequence', + } + + assert len(string_slot_types_dict) == len(expected_string_slot_types_dict) + + for expected_field, expected_slot_type in expected_string_slot_types_dict.items(): + assert expected_field in string_slot_types_dict.keys() + assert expected_slot_type == string_slot_types_dict[expected_field] + + +def test_modifying_slot_fields_and_types(): + b = StringArrays() + assert hasattr(b, 'get_fields_and_field_types') + string_slot_types_dict = getattr(b, 'get_fields_and_field_types')() + string_slot_types_dict_len = len(string_slot_types_dict) + string_slot_types_dict[1] = 2 + assert len(getattr(b, 'get_fields_and_field_types')()) == string_slot_types_dict_len + + +def test_slot_types(): a = Nested() assert hasattr(a, 'SLOT_TYPES') assert hasattr(a, '__slots__') @@ -332,7 +389,7 @@ def test_slot_attributes(): assert nested_slot_types[3].value_type.name == 'Primitives' -def test_string_slot_attributes(): +def test_string_slot_types(): b = StringArrays() assert hasattr(b, 'SLOT_TYPES') assert hasattr(b, '__slots__')