Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ set(target_dependencies
"${rosidl_generator_py_TEMPLATE_DIR}/_idl_pkg_typesupport_entry_point.c.em"
"${rosidl_generator_py_TEMPLATE_DIR}/_idl_support.c.em"
"${rosidl_generator_py_TEMPLATE_DIR}/_idl.py.em"
"${rosidl_generator_py_TEMPLATE_DIR}/_msg_check_fields.py.em"
"${rosidl_generator_py_TEMPLATE_DIR}/_msg_pkg_typesupport_entry_point.c.em"
"${rosidl_generator_py_TEMPLATE_DIR}/_msg_support.c.em"
"${rosidl_generator_py_TEMPLATE_DIR}/_msg.py.em"
Expand Down
173 changes: 26 additions & 147 deletions rosidl_generator_py/resource/_msg.py.em
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@# Included from rosidl_generator_py/resource/_idl.py.em
@{

from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
from rosidl_generator_py.generate_py_impl import constant_value_to_py
from rosidl_generator_py.generate_py_impl import get_python_type
Expand Down Expand Up @@ -484,177 +483,57 @@ if isinstance(member.type, (Array, AbstractSequence)):

@@@(member.name).setter@(noqa_string)
def @(member.name)(self, value: @(type_annotations_setter[member.name])) -> None:@(noqa_string)

@[ if isinstance(member.type, AbstractNestedType)]@
from collections.abc import Set
if isinstance(value, Set):
if isinstance(value, collections.abc.Set):
import warnings
warnings.warn(
'Using set or subclass of set is deprecated,'
' please use a subclass of collections.abc.Sequence like list',
DeprecationWarning)
@[ end if]@
if self._check_fields:
@[ if isinstance(member.type, AbstractNestedType) and isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES]@
@[ if isinstance(member.type, Array)]@
if isinstance(value, numpy.ndarray):
assert value.dtype == @(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype']), \
"The '@(member.name)' numpy.ndarray() must have the dtype of '@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype'])'"
assert value.size == @(member.type.size), \
"The '@(member.name)' numpy.ndarray() must have a size of @(member.type.size)"
self._@(member.name) = value
return
@[ elif isinstance(member.type, AbstractSequence)]@
if isinstance(value, array.array):
assert value.typecode == '@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['type_code'])', \
"The '@(member.name)' array.array() must have the type code of '@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['type_code'])'"
@[ if isinstance(member.type, BoundedSequence)]@
assert len(value) <= @(member.type.maximum_size), \
"The '@(member.name)' array.array() must have a size <= @(member.type.maximum_size)"
@[ end if]@
self._@(member.name) = value
return
@[ end if]@
@[ end if]@
@[ if isinstance(type_, NamespacedType)]@
@[ if (
type_.name.endswith(ACTION_GOAL_SUFFIX) or
type_.name.endswith(ACTION_RESULT_SUFFIX) or
type_.name.endswith(ACTION_FEEDBACK_SUFFIX)
)]@
from @('.'.join(type_.namespaces))._@(convert_camel_case_to_lower_case_underscore(type_.name.rsplit('_', 1)[0])) import @(type_.name)
from @('.'.join(type_.namespaces))._@(convert_camel_case_to_lower_case_underscore(type_.name.rsplit('_', 1)[0])) import @(type_.name)
@[ else]@
from @('.'.join(type_.namespaces)) import @(type_.name)
from @('.'.join(type_.namespaces)) import @(type_.name)
@[ end if]@
@[ end if]@
@[ if isinstance(member.type, AbstractNestedType)]@
from collections.abc import Sequence
from collections import UserString
@[ elif isinstance(type_, AbstractGenericString) and type_.has_maximum_size()]@
from collections import UserString
@[ elif isinstance(type_, BasicType) and type_.typename in CHARACTER_TYPES]@
from collections import UserString
@[ end if]@
assert \
@[ if isinstance(member.type, AbstractNestedType)]@
((isinstance(value, Sequence) or
isinstance(value, Set)) and
not isinstance(value, str) and
not isinstance(value, UserString) and
@{assert_msg_suffixes = ['sequence']}@
@[ if isinstance(type_, AbstractGenericString) and type_.has_maximum_size()]@
all(len(val) <= @(type_.maximum_size) for val in value) and
@{assert_msg_suffixes.append('and each string value not longer than %d' % type_.maximum_size)}@
@[ end if]@
@[ if isinstance(member.type, (Array, BoundedSequence))]@
@[ if isinstance(member.type, BoundedSequence)]@
len(value) <= @(member.type.maximum_size) and
@{assert_msg_suffixes.insert(1, 'with length <= %d' % member.type.maximum_size)}@
@[ else]@
len(value) == @(member.type.size) and
@{assert_msg_suffixes.insert(1, 'with length %d' % member.type.size)}@
@[ end if]@
@[ end if]@
all(isinstance(v, @(get_python_type(type_))) for v in value) and
@{assert_msg_suffixes.append("and each value of type '%s'" % get_python_type(type_))}@
@[ if isinstance(type_, BasicType) and type_.typename in SIGNED_INTEGER_TYPES]@
@{
nbits = int(type_.typename[3:])
bound = 2**(nbits - 1)
}@
all(val >= -@(bound) and val < @(bound) for val in value)), \
@{assert_msg_suffixes.append('and each integer in [%d, %d]' % (-bound, bound - 1))}@
@[ elif isinstance(type_, BasicType) and type_.typename in UNSIGNED_INTEGER_TYPES]@
@{
nbits = int(type_.typename[4:])
bound = 2**nbits
}@
all(val >= 0 and val < @(bound) for val in value)), \
@{assert_msg_suffixes.append('and each unsigned integer in [0, %d]' % (bound - 1))}@
@[ elif isinstance(type_, BasicType) and type_.typename == 'char']@
all(ord(val) >= 0 and ord(val) < 256 for val in value)), \
@{assert_msg_suffixes.append('and each char in [0, 255]')}@
@[ elif isinstance(type_, BasicType) and type_.typename in FLOATING_POINT_TYPES]@
@[ if type_.typename == "float"]@
@{
name = "float"
bound = 3.402823466e+38
}@
all(not (val < -@(bound) or val > @(bound)) or math.isinf(val) for val in value)), \
@{assert_msg_suffixes.append('and each float in [%f, %f]' % (-bound, bound))}@
@[ elif type_.typename == "double"]@

@{
name = "double"
bound = 1.7976931348623157e+308
TEMPLATE(
'_msg_check_fields.py.em',
member=member,
type_=type_,
)
}@
all(not (val < -@(bound) or val > @(bound)) or math.isinf(val) for val in value)), \
@{assert_msg_suffixes.append('and each double in [%f, %f]' % (-bound, bound))}@

@[ if isinstance(member.type, AbstractNestedType)]@
@[ if isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES]@
@[ if isinstance(member.type, Array)]@
if isinstance(value, numpy.ndarray):
@[ elif isinstance(member.type, AbstractSequence)]@
if isinstance(value, array.array):
@[ end if]@
@[ else]@
True), \
@[ end if]@
"The '@(member.name)' field must be @(' '.join(assert_msg_suffixes))"
@[ elif isinstance(member.type, AbstractGenericString) and member.type.has_maximum_size()]@
(isinstance(value, (str, UserString)) and
len(value) <= @(member.type.maximum_size)), \
"The '@(member.name)' field must be string value " \
'not longer than @(type_.maximum_size)'
@[ elif isinstance(type_, NamespacedType)]@
isinstance(value, @(type_.name)), \
"The '@(member.name)' field must be a sub message of type '@(type_.name)'"
@[ elif isinstance(type_, BasicType) and type_.typename == 'octet']@
(isinstance(value, (bytes, bytearray, memoryview)) and
len(value) == 1), \
"The '@(member.name)' field must be of type 'bytes' or 'ByteString' with length 1"
@[ elif isinstance(type_, BasicType) and type_.typename == 'char']@
(isinstance(value, (str, UserString)) and
len(value) == 1 and ord(value) >= -128 and ord(value) < 128), \
"The '@(member.name)' field must be of type 'str' or 'UserString' " \
'with length 1 and the character ord() in [-128, 127]'
@[ elif isinstance(type_, AbstractGenericString)]@
isinstance(value, str), \
"The '@(member.name)' field must be of type '@(get_python_type(type_))'"
@[ elif isinstance(type_, BasicType) and type_.typename in (BOOLEAN_TYPE, *FLOATING_POINT_TYPES, *INTEGER_TYPES)]@
isinstance(value, @(get_python_type(type_))), \
"The '@(member.name)' field must be of type '@(get_python_type(type_))'"
@[ if type_.typename in SIGNED_INTEGER_TYPES]@
@{
nbits = int(type_.typename[3:])
bound = 2**(nbits - 1)
}@
assert value >= -@(bound) and value < @(bound), \
"The '@(member.name)' field must be an integer in [@(-bound), @(bound - 1)]"
@[ elif type_.typename in UNSIGNED_INTEGER_TYPES]@
@{
nbits = int(type_.typename[4:])
bound = 2**nbits
}@
assert value >= 0 and value < @(bound), \
"The '@(member.name)' field must be an unsigned integer in [0, @(bound - 1)]"
@[ elif type_.typename in FLOATING_POINT_TYPES]@
@[ if type_.typename == "float"]@
@{
name = "float"
bound = 3.402823466e+38
}@
@[ elif type_.typename == "double"]@
@{
name = "double"
bound = 1.7976931348623157e+308
}@
@[ end if]@
assert not (value < -@(bound) or value > @(bound)) or math.isinf(value), \
"The '@(member.name)' field must be a @(name) in [@(-bound), @(bound)]"
if isinstance(value, list):
@[ end if]@
@[ else]@
False
self._@(member.name) = value
return
@[ end if]@
@[ if isinstance(member.type, AbstractNestedType) and isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES]@
@[ if isinstance(member.type, Array)]@
@[ if isinstance(member.type, AbstractNestedType)]@
@[ if isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES]@
@[ if isinstance(member.type, Array)]@
self._@(member.name) = numpy.array(value, dtype=@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype']))
@[ elif isinstance(member.type, AbstractSequence)]@
@[ elif isinstance(member.type, AbstractSequence)]@
# type ignore below fixed in mypy 1.17+ see mypy#19421
self._@(member.name) = array.array('@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['type_code'])', value) # type: ignore[assignment]
@[ end if]@
@[ else]@
self._@(member.name) = list(value)
@[ end if]@
@[ else]@
self._@(member.name) = value
Expand Down
157 changes: 157 additions & 0 deletions rosidl_generator_py/resource/_msg_check_fields.py.em
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
@{
from rosidl_parser.definition import AbstractGenericString
from rosidl_parser.definition import AbstractNestedType
from rosidl_parser.definition import AbstractSequence
from rosidl_parser.definition import Array
from rosidl_parser.definition import BasicType
from rosidl_parser.definition import BOOLEAN_TYPE
from rosidl_parser.definition import INTEGER_TYPES
from rosidl_parser.definition import BoundedSequence
from rosidl_parser.definition import FLOATING_POINT_TYPES
from rosidl_parser.definition import SIGNED_INTEGER_TYPES
from rosidl_parser.definition import UNSIGNED_INTEGER_TYPES
from rosidl_parser.definition import NamespacedType
from rosidl_generator_py.generate_py_impl import get_python_type
from rosidl_generator_py.generate_py_impl import SPECIAL_NESTED_BASIC_TYPES
}@
if self._check_fields:
@[ if isinstance(member.type, AbstractNestedType)]@
@[ if isinstance(member.type.value_type, BasicType) and member.type.value_type.typename in SPECIAL_NESTED_BASIC_TYPES]@
@[ if isinstance(member.type, Array)]@
if isinstance(value, numpy.ndarray):
assert value.dtype == @(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype']), \
"The '@(member.name)' numpy.ndarray() must have the dtype of '@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['dtype'])'"
assert value.size == @(member.type.size), \
"The '@(member.name)' numpy.ndarray() must have a size of @(member.type.size)"
@[ elif isinstance(member.type, AbstractSequence)]@
if isinstance(value, array.array):
assert value.typecode == '@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['type_code'])', \
"The '@(member.name)' array.array() must have the type code of '@(SPECIAL_NESTED_BASIC_TYPES[member.type.value_type.typename]['type_code'])'"
@[ if isinstance(member.type, BoundedSequence)]@
assert len(value) <= @(member.type.maximum_size), \
"The '@(member.name)' array.array() must have a size <= @(member.type.maximum_size)"
@[ end if]@
@[ end if]@
@[ else]@
if False: # Done for templating alignment
pass
@[ end if]@
@[ else]@
if False: # Done for templating alignment
pass
@[ end if]@
else:
assert \
@[ if isinstance(member.type, AbstractNestedType)]@
((isinstance(value, collections.abc.Sequence) or
isinstance(value, collections.abc.Set)) and
not isinstance(value, str) and
not isinstance(value, collections.UserString) and
@{assert_msg_suffixes = ['sequence']}@
@[ if isinstance(type_, AbstractGenericString) and type_.has_maximum_size()]@
all(len(val) <= @(type_.maximum_size) for val in value) and
@{assert_msg_suffixes.append('and each string value not longer than %d' % type_.maximum_size)}@
@[ end if]@
@[ if isinstance(member.type, (Array, BoundedSequence))]@
@[ if isinstance(member.type, BoundedSequence)]@
len(value) <= @(member.type.maximum_size) and
@{assert_msg_suffixes.insert(1, 'with length <= %d' % member.type.maximum_size)}@
@[ else]@
len(value) == @(member.type.size) and
@{assert_msg_suffixes.insert(1, 'with length %d' % member.type.size)}@
@[ end if]@
@[ end if]@
all(isinstance(v, @(get_python_type(type_))) for v in value) and
@{assert_msg_suffixes.append("and each value of type '%s'" % get_python_type(type_))}@
@[ if isinstance(type_, BasicType) and type_.typename in SIGNED_INTEGER_TYPES]@
@{
nbits = int(type_.typename[3:])
bound = 2**(nbits - 1)
}@
all(val >= -@(bound) and val < @(bound) for val in value)), \
@{assert_msg_suffixes.append('and each integer in [%d, %d]' % (-bound, bound - 1))}@
@[ elif isinstance(type_, BasicType) and type_.typename in UNSIGNED_INTEGER_TYPES]@
@{
nbits = int(type_.typename[4:])
bound = 2**nbits
}@
all(val >= 0 and val < @(bound) for val in value)), \
@{assert_msg_suffixes.append('and each unsigned integer in [0, %d]' % (bound - 1))}@
@[ elif isinstance(type_, BasicType) and type_.typename == 'char']@
all(ord(val) >= 0 and ord(val) < 256 for val in value)), \
@{assert_msg_suffixes.append('and each char in [0, 255]')}@
@[ elif isinstance(type_, BasicType) and type_.typename in FLOATING_POINT_TYPES]@
@[ if type_.typename == "float"]@
@{
name = "float"
bound = 3.402823466e+38
}@
all(not (val < -@(bound) or val > @(bound)) or math.isinf(val) for val in value)), \
@{assert_msg_suffixes.append('and each float in [%f, %f]' % (-bound, bound))}@
@[ elif type_.typename == "double"]@
@{
name = "double"
bound = 1.7976931348623157e+308
}@
all(not (val < -@(bound) or val > @(bound)) or math.isinf(val) for val in value)), \
@{assert_msg_suffixes.append('and each double in [%f, %f]' % (-bound, bound))}@
@[ end if]@
@[ else]@
True), \
@[ end if]@
"The '@(member.name)' field must be @(' '.join(assert_msg_suffixes))"
@[ elif isinstance(member.type, AbstractGenericString) and member.type.has_maximum_size()]@
(isinstance(value, (str, collections.UserString)) and
len(value) <= @(member.type.maximum_size)), \
"The '@(member.name)' field must be string value " \
'not longer than @(type_.maximum_size)'
@[ elif isinstance(type_, NamespacedType)]@
isinstance(value, @(type_.name)), \
"The '@(member.name)' field must be a sub message of type '@(type_.name)'"
@[ elif isinstance(type_, BasicType) and type_.typename == 'octet']@
(isinstance(value, (bytes, bytearray, memoryview)) and
len(value) == 1), \
"The '@(member.name)' field must be of type 'bytes' or 'ByteString' with length 1"
@[ elif isinstance(type_, BasicType) and type_.typename == 'char']@
(isinstance(value, (str, collections.UserString)) and
len(value) == 1 and ord(value) >= -128 and ord(value) < 128), \
"The '@(member.name)' field must be of type 'str' or 'collections.UserString' " \
'with length 1 and the character ord() in [-128, 127]'
@[ elif isinstance(type_, AbstractGenericString)]@
isinstance(value, str), \
"The '@(member.name)' field must be of type '@(get_python_type(type_))'"
@[ elif isinstance(type_, BasicType) and type_.typename in (BOOLEAN_TYPE, *FLOATING_POINT_TYPES, *INTEGER_TYPES)]@
isinstance(value, @(get_python_type(type_))), \
"The '@(member.name)' field must be of type '@(get_python_type(type_))'"
@[ if type_.typename in SIGNED_INTEGER_TYPES]@
@{
nbits = int(type_.typename[3:])
bound = 2**(nbits - 1)
}@
assert value >= -@(bound) and value < @(bound), \
"The '@(member.name)' field must be an integer in [@(-bound), @(bound - 1)]"
@[ elif type_.typename in UNSIGNED_INTEGER_TYPES]@
@{
nbits = int(type_.typename[4:])
bound = 2**nbits
}@
assert value >= 0 and value < @(bound), \
"The '@(member.name)' field must be an unsigned integer in [0, @(bound - 1)]"
@[ elif type_.typename in FLOATING_POINT_TYPES]@
@[ if type_.typename == "float"]@
@{
name = "float"
bound = 3.402823466e+38
}@
@[ elif type_.typename == "double"]@
@{
name = "double"
bound = 1.7976931348623157e+308
}@
@[ end if]@
assert not (value < -@(bound) or value > @(bound)) or math.isinf(value), \
"The '@(member.name)' field must be a @(name) in [@(-bound), @(bound)]"
@[ end if]@
@[ else]@
False
@[ end if]@
Loading