diff --git a/rosidl_parser/CMakeLists.txt b/rosidl_parser/CMakeLists.txt
index 9c282bca0..166758c2a 100644
--- a/rosidl_parser/CMakeLists.txt
+++ b/rosidl_parser/CMakeLists.txt
@@ -9,6 +9,7 @@ ament_python_install_package(${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
+ find_package(ament_cmake_mypy REQUIRED)
ament_lint_auto_find_test_dependencies()
endif()
diff --git a/rosidl_parser/package.xml b/rosidl_parser/package.xml
index 68222fa91..9f258cdcd 100644
--- a/rosidl_parser/package.xml
+++ b/rosidl_parser/package.xml
@@ -21,6 +21,7 @@
python3-lark-parser
rosidl_adapter
+ ament_cmake_mypy
ament_cmake_pytest
ament_lint_auto
ament_lint_common
diff --git a/rosidl_parser/rosidl_parser/definition.py b/rosidl_parser/rosidl_parser/definition.py
index 26587b9b3..5873ba470 100644
--- a/rosidl_parser/rosidl_parser/definition.py
+++ b/rosidl_parser/rosidl_parser/definition.py
@@ -17,6 +17,7 @@
from typing import Final
from typing import Iterable
from typing import List
+from typing import Literal
from typing import Optional
from typing import Set
from typing import Tuple
@@ -95,7 +96,7 @@
)
if TYPE_CHECKING:
- from typing import Literal, TypeAlias
+ from typing_extensions import TypeAlias
SignedNonexplicitIntegerTypeValues = Literal['short', 'long', 'long long']
UnsignedNonexplicitIntegerTypeValues = Literal['unsigned short', 'unsigned long',
'unsigned long long']
@@ -108,7 +109,7 @@
BooleanValue = Literal['boolean']
OctetValue = Literal['octet']
- SignedExplicitIntegerTypeValues = Literal['int8', 'int16', 'int32' 'int64']
+ SignedExplicitIntegerTypeValues = Literal['int8', 'int16', 'int32', 'int64']
UnsignedExplicitIntegerTypeValues = Literal['uint8', 'uint16', 'uint32', 'uint64']
ExplicitIntegerTypeValues = Union[SignedExplicitIntegerTypeValues,
@@ -299,7 +300,7 @@ class BoundedWString(AbstractWString):
__slots__ = ('maximum_size', )
- def __init__(self, maximum_size: int) -> None:
+ def __init__(self, maximum_size: Union[int, str]) -> None:
"""
Create a BoundedWString.
@@ -803,7 +804,7 @@ class IdlLocator:
__slots__ = ('basepath', 'relative_path')
- def __init__(self, basepath: str, relative_path: str) -> None:
+ def __init__(self, basepath: pathlib.Path, relative_path: pathlib.Path) -> None:
"""
Create an IdlLocator.
diff --git a/rosidl_parser/rosidl_parser/parser.py b/rosidl_parser/rosidl_parser/parser.py
index 8aceb02df..399ceee5d 100644
--- a/rosidl_parser/rosidl_parser/parser.py
+++ b/rosidl_parser/rosidl_parser/parser.py
@@ -16,12 +16,23 @@
import os
import re
import sys
+from typing import Any
+from typing import Callable
+from typing import Dict
+from typing import List
+from typing import Literal
+from typing import Match
+from typing import Optional
+from typing import Pattern
+from typing import TYPE_CHECKING
+from typing import Union
from lark import Lark
from lark.lexer import Token
from lark.tree import pydot__tree_to_png
from lark.tree import Tree
+from rosidl_parser.definition import AbstractNestableType
from rosidl_parser.definition import AbstractNestedType
from rosidl_parser.definition import AbstractType
from rosidl_parser.definition import Action
@@ -38,6 +49,7 @@
from rosidl_parser.definition import CONSTANT_MODULE_SUFFIX
from rosidl_parser.definition import IdlContent
from rosidl_parser.definition import IdlFile
+from rosidl_parser.definition import IdlLocator
from rosidl_parser.definition import Include
from rosidl_parser.definition import Member
from rosidl_parser.definition import Message
@@ -50,15 +62,30 @@
from rosidl_parser.definition import UnboundedSequence
from rosidl_parser.definition import UnboundedString
from rosidl_parser.definition import UnboundedWString
+from rosidl_parser.definition import ValueType
+
+if TYPE_CHECKING:
+ from typing_extensions import TypeAlias
+ from typing import TypeVar
+
+ from rosidl_parser.definition import BasicTypeValues
+
+ # Definitions taken from lark.tree
+ # Since lark version's used by Windows and rhel does not have Branch or ParseTree.
+ _Leaf_T = TypeVar('_Leaf_T')
+ Branch: TypeAlias = Union[_Leaf_T, Tree]
+ ParseTree: TypeAlias = Tree
+
+AbstractTypeAlias = Union[AbstractNestableType, BasicType, BoundedSequence, UnboundedSequence]
grammar_file = os.path.join(os.path.dirname(__file__), 'grammar.lark')
with open(grammar_file, mode='r', encoding='utf-8') as h:
grammar = h.read()
-_parser = None
+_parser: Optional[Lark] = None
-def parse_idl_file(locator, png_file=None):
+def parse_idl_file(locator: IdlLocator, png_file: Optional[str] = None) -> IdlFile:
string = locator.get_absolute_path().read_text(encoding='utf-8')
try:
content = parse_idl_string(string, png_file=png_file)
@@ -68,7 +95,7 @@ def parse_idl_file(locator, png_file=None):
return IdlFile(locator, content)
-def parse_idl_string(idl_string, png_file=None):
+def parse_idl_string(idl_string: str, png_file: Optional[str] = None) -> IdlContent:
tree = get_ast_from_idl_string(idl_string)
content = extract_content_from_ast(tree)
@@ -82,25 +109,27 @@ def parse_idl_string(idl_string, png_file=None):
return content
-def get_ast_from_idl_string(idl_string):
+def get_ast_from_idl_string(idl_string: str) -> 'ParseTree':
global _parser
if _parser is None:
_parser = Lark(grammar, start='specification', maybe_placeholders=False)
return _parser.parse(idl_string)
-def extract_content_from_ast(tree):
+def extract_content_from_ast(tree: 'ParseTree') -> IdlContent:
content = IdlContent()
include_directives = tree.find_data('include_directive')
for include_directive in include_directives:
assert len(include_directive.children) == 1
child = include_directive.children[0]
+ assert isinstance(child, Tree)
assert child.data in ('h_char_sequence', 'q_char_sequence')
include_token = next(child.scan_values(_find_tokens(None)))
- content.elements.append(Include(include_token.value))
+ # Type ignore around lark-parser typing bugging in old version
+ content.elements.append(Include(include_token.value)) # type: ignore[attr-defined]
- constants = {}
+ constants: Dict[str, List[Constant]] = {}
const_dcls = tree.find_data('const_dcl')
for const_dcl in const_dcls:
annotations = get_annotations(const_dcl)
@@ -116,25 +145,28 @@ def extract_content_from_ast(tree):
constant.annotations = annotations
module_comments.append(constant)
- typedefs = {}
+ typedefs: Dict[Any, Union[Array, AbstractTypeAlias]] = {}
typedef_dcls = tree.find_data('typedef_dcl')
for typedef_dcl in typedef_dcls:
assert len(typedef_dcl.children) == 1
child = typedef_dcl.children[0]
+ assert isinstance(child, Tree)
assert 'type_declarator' == child.data
assert len(child.children) == 2
abstract_type = get_abstract_type(child.children[0])
child = child.children[1]
+ assert isinstance(child, Tree)
assert 'any_declarators' == child.data
assert len(child.children) == 1, 'Only support single typedefs atm'
child = child.children[0]
+ assert isinstance(child, Tree)
identifier = get_first_identifier_value(child)
- abstract_type = get_abstract_type_optionally_as_array(
+ abstract_type_array = get_abstract_type_optionally_as_array(
abstract_type, child)
if identifier in typedefs:
- assert typedefs[identifier] == abstract_type
+ assert typedefs[identifier] == abstract_type_array
else:
- typedefs[identifier] = abstract_type
+ typedefs[identifier] = abstract_type_array
struct_defs = list(tree.find_data('struct_def'))
if len(struct_defs) == 1:
@@ -259,7 +291,8 @@ def extract_content_from_ast(tree):
return content
-def resolve_typedefed_names(structure, typedefs):
+def resolve_typedefed_names(structure: Structure,
+ typedefs: Dict[Any, Union[Array, AbstractTypeAlias]]) -> None:
for member in structure.members:
type_ = member.type
if isinstance(type_, AbstractNestedType):
@@ -274,22 +307,26 @@ def resolve_typedefed_names(structure, typedefs):
if isinstance(typedefed_type.value_type, NamedType):
assert typedefed_type.value_type.name in typedefs, \
'Unknown named type: ' + typedefed_type.value_type.name
- typedefed_type.value_type = \
- typedefs[typedefed_type.value_type.name]
+
+ typedef = typedefs[typedefed_type.value_type.name]
+ assert isinstance(typedef, AbstractNestableType)
+ typedefed_type.value_type = typedef
if isinstance(member.type, AbstractNestedType):
+ assert isinstance(typedefed_type, AbstractNestableType)
member.type.value_type = typedefed_type
else:
member.type = typedefed_type
-def get_first_identifier_value(tree):
+def get_first_identifier_value(tree: 'ParseTree') -> Any:
"""Get the value of the first identifier token for a node."""
identifier_token = next(tree.scan_values(_find_tokens('IDENTIFIER')))
- return identifier_token.value
+ # Type ignore around lark-parser typing bugging in old version
+ return identifier_token.value # type: ignore[attr-defined]
-def get_child_identifier_value(tree):
+def get_child_identifier_value(tree: 'ParseTree') -> Any:
"""Get the value of the first child identifier token for a node."""
for c in tree.children:
if not isinstance(c, Token):
@@ -299,15 +336,18 @@ def get_child_identifier_value(tree):
return None
-def _find_tokens(token_type):
- def find(t):
+def _find_tokens(
+ token_type: Optional[Literal['IDENTIFIER']]
+) -> Callable[['Branch[Union[str, Token]]'], bool]:
+ def find(t: 'Branch[Union[str, Token]]') -> bool:
if isinstance(t, Token):
if token_type is None or t.type == token_type:
- return t
+ return True
+ return False
return find
-def get_module_identifier_values(tree, target):
+def get_module_identifier_values(tree: 'ParseTree', target: 'ParseTree') -> List[Any]:
"""Get all module names between a tree node and a specific target node."""
path = _find_path(tree, target)
modules = [n for n in path if n.data == 'module_dcl']
@@ -315,23 +355,33 @@ def get_module_identifier_values(tree, target):
get_first_identifier_value(n) for n in modules]
-def _find_path(node, target):
+def _find_path(node: 'ParseTree', target: 'ParseTree') -> List['ParseTree']:
+ path = _find_path_recursive(node, target)
+ if path is None:
+ raise ValueError(f'No path found between {node} and {target}')
+ return path
+
+
+def _find_path_recursive(node: 'ParseTree', target: 'ParseTree') -> Optional[List['ParseTree']]:
if node == target:
return [node]
for c in node.children:
if not isinstance(c, Tree):
continue
- tail = _find_path(c, target)
+ tail = _find_path_recursive(c, target)
if tail is not None:
return [node] + tail
return None
-def get_abstract_type_from_const_expr(const_expr, value):
+def get_abstract_type_from_const_expr(const_expr: 'ParseTree', value: Union[str, int, float, bool]
+ ) -> Union[BoundedString, BoundedWString, BasicType]:
assert len(const_expr.children) == 1
child = const_expr.children[0]
+ assert isinstance(child, Tree)
if child.data in ('string_type', 'wide_string_type'):
+ assert isinstance(value, str)
if 'string_type' == child.data:
return BoundedString(len(value))
if 'wide_string_type' == child.data:
@@ -340,24 +390,32 @@ def get_abstract_type_from_const_expr(const_expr, value):
while len(child.children) == 1:
child = child.children[0]
+ assert isinstance(child, Tree)
return BasicType(BASE_TYPE_SPEC_TO_IDL_TYPE[child.data])
-def get_abstract_type_optionally_as_array(abstract_type, declarator):
+def get_abstract_type_optionally_as_array(
+ abstract_type: AbstractTypeAlias,
+ declarator: 'ParseTree'
+) -> Union[Array, AbstractTypeAlias]:
assert len(declarator.children) == 1
child = declarator.children[0]
+ assert isinstance(child, Tree)
if child.data == 'array_declarator':
+ assert isinstance(abstract_type, AbstractNestableType)
fixed_array_sizes = list(child.find_data('fixed_array_size'))
assert len(fixed_array_sizes) == 1, \
'Unsupported multidimensional array: ' + str(declarator)
positive_int_const = next(
fixed_array_sizes[0].find_data('positive_int_const'))
size = get_positive_int_const(positive_int_const)
- abstract_type = Array(abstract_type, size)
+ if isinstance(size, str):
+ raise ValueError('Arrays only support Literal Sizes not constants')
+ return Array(abstract_type, size)
return abstract_type
-def add_message_members(msg, tree):
+def add_message_members(msg: Message, tree: 'ParseTree') -> None:
members = tree.find_data('member')
for member in members:
# the find_data methods seems to traverse the tree in post order
@@ -370,20 +428,27 @@ def add_message_members(msg, tree):
for declarator in declarators:
assert len(declarator.children) == 1
child = declarator.children[0]
+ assert isinstance(child, Tree)
if child.data == 'array_declarator':
+ assert isinstance(abstract_type, AbstractNestableType)
fixed_array_sizes = list(child.find_data('fixed_array_size'))
assert len(fixed_array_sizes) == 1, \
'Unsupported multidimensional array: ' + str(member)
positive_int_const = next(
fixed_array_sizes[0].find_data('positive_int_const'))
size = get_positive_int_const(positive_int_const)
- abstract_type = Array(abstract_type, size)
- m = Member(abstract_type, get_first_identifier_value(declarator))
+ if isinstance(size, str):
+ raise ValueError('Arrays only support Literal Sizes not constants')
+ member_abstract_type: Union[Array, AbstractTypeAlias] = \
+ Array(abstract_type, size)
+ else:
+ member_abstract_type = abstract_type
+ m = Member(member_abstract_type, get_first_identifier_value(declarator))
m.annotations += annotations
msg.structure.members.append(m)
-BASE_TYPE_SPEC_TO_IDL_TYPE = {
+BASE_TYPE_SPEC_TO_IDL_TYPE: Dict[str, 'BasicTypeValues'] = {
'floating_pt_type_float': 'float',
'floating_pt_type_double': 'double',
'floating_pt_type_long_double': 'long double',
@@ -402,20 +467,23 @@ def add_message_members(msg, tree):
}
-def get_abstract_type_from_type_spec(type_spec):
+def get_abstract_type_from_type_spec(type_spec: 'ParseTree') -> AbstractTypeAlias:
assert len(type_spec.children) == 1
child = type_spec.children[0]
return get_abstract_type(child)
-def get_abstract_type(tree):
+def get_abstract_type(tree: 'Branch[Union[str, Token]]') -> AbstractTypeAlias:
+ assert isinstance(tree, Tree)
if 'simple_type_spec' == tree.data:
assert len(tree.children) == 1
child = tree.children[0]
+ assert isinstance(child, Tree)
if 'base_type_spec' == child.data:
while len(child.children) == 1:
child = child.children[0]
+ assert isinstance(child, Tree)
return BasicType(BASE_TYPE_SPEC_TO_IDL_TYPE[child.data])
if 'scoped_name' == child.data:
@@ -432,6 +500,7 @@ def get_abstract_type(tree):
if 'template_type_spec' == tree.data:
assert len(tree.children) == 1
child = tree.children[0]
+ assert isinstance(child, Tree)
if 'sequence_type' == child.data:
# the find_data methods seems to traverse the tree in post order
@@ -439,6 +508,7 @@ def get_abstract_type(tree):
type_specs = list(child.find_data('type_spec'))
type_spec = type_specs[-1]
basetype = get_abstract_type_from_type_spec(type_spec)
+ assert isinstance(basetype, AbstractNestableType)
positive_int_consts = list(child.find_data('positive_int_const'))
if positive_int_consts:
path = _find_path(child, positive_int_consts[0])
@@ -446,15 +516,21 @@ def get_abstract_type(tree):
positive_int_consts.pop(0)
if positive_int_consts:
maximum_size = get_positive_int_const(positive_int_consts[-1])
+ if isinstance(maximum_size, str):
+ raise ValueError('BoundedSequence only support Literal Sizes not constants')
return BoundedSequence(basetype, maximum_size)
else:
return UnboundedSequence(basetype)
if child.data in ('string_type', 'wide_string_type'):
if len(child.children) == 1:
- assert child.children[0].data == 'positive_int_const'
- maximum_size = get_positive_int_const(child.children[0])
+ child_child = child.children[0]
+ assert isinstance(child_child, Tree)
+ assert child_child.data == 'positive_int_const'
+ maximum_size = get_positive_int_const(child_child)
if 'string_type' == child.data:
+ if isinstance(maximum_size, str):
+ raise ValueError('BoundedString only support Literal Sizes not constants')
assert maximum_size > 0
return BoundedString(maximum_size=maximum_size)
if 'wide_string_type' == child.data:
@@ -473,7 +549,7 @@ def get_abstract_type(tree):
assert False, 'Unsupported tree: ' + str(tree)
-def get_positive_int_const(positive_int_const):
+def get_positive_int_const(positive_int_const: 'ParseTree') -> Union[int, str]:
assert positive_int_const.data == 'positive_int_const'
# TODO support arbitrary expressions
try:
@@ -483,6 +559,7 @@ def get_positive_int_const(positive_int_const):
else:
digits = ''
for child in decimal_literal.children:
+ assert isinstance(child, Token)
digits += child.value
return int(digits)
@@ -493,13 +570,14 @@ def get_positive_int_const(positive_int_const):
pass
else:
# TODO ensure that identifier resolves to a positive integer
- return identifier_token.value
+ # Type ignore around lark-parser typing bugging in old version
+ return str(identifier_token.value) # type: ignore[attr-defined]
assert False, 'Unsupported tree: ' + str(positive_int_const)
-def get_annotations(tree):
- annotations = []
+def get_annotations(tree: 'ParseTree') -> List[Annotation]:
+ annotations: List[Annotation] = []
for c in tree.children:
if not isinstance(c, Tree):
continue
@@ -508,11 +586,12 @@ def get_annotations(tree):
annotation_appl = c
params = list(annotation_appl.find_data('annotation_appl_param'))
if params:
- value = {}
+ value_dict: Dict[Any, Union[str, int, float, bool]] = {}
for param in params:
const_expr = next(param.find_data('const_expr'))
- value[get_first_identifier_value(param)] = \
+ value_dict[get_first_identifier_value(param)] = \
get_const_expr_value(const_expr)
+ value: ValueType = value_dict
elif len(annotation_appl.children) == 1:
value = None
else:
@@ -524,13 +603,15 @@ def get_annotations(tree):
return annotations
-def get_const_expr_value(const_expr):
+def get_const_expr_value(const_expr: 'Branch[Union[str, Token]]') -> Union[str, int, float, bool]:
+ assert isinstance(const_expr, Tree)
# TODO support arbitrary expressions
expr = list(const_expr.find_data('primary_expr'))
assert len(expr) == 1, str(expr)
primary_expr = expr[0]
assert len(primary_expr.children) == 1
child = primary_expr.children[0]
+ assert isinstance(child, Tree)
if 'scoped_name' == child.data:
return str(child.children[0])
elif 'literal' == child.data:
@@ -540,13 +621,15 @@ def get_const_expr_value(const_expr):
assert len(literal.children) == 1
child = literal.children[0]
+ assert isinstance(child, Tree)
if child.data == 'integer_literal':
assert len(child.children) == 1
child = child.children[0]
+ assert isinstance(child, Tree)
if child.data == 'decimal_literal':
- value = get_decimal_literal_value(child)
+ value: Union[int, float] = get_decimal_literal_value(child)
if negate_value:
value = -value
return value
@@ -568,6 +651,7 @@ def get_const_expr_value(const_expr):
if child.data == 'boolean_literal':
assert len(child.children) == 1
child = child.children[0]
+ assert isinstance(child, Tree)
assert child.data in ('boolean_literal_true', 'boolean_literal_false')
return child.data == 'boolean_literal_true'
@@ -584,14 +668,17 @@ def get_const_expr_value(const_expr):
assert False, 'Unsupported tree: ' + str(const_expr)
-def get_decimal_literal_value(decimal_literal):
+def get_decimal_literal_value(decimal_literal: 'ParseTree') -> int:
value = ''
for child in decimal_literal.children:
- value += child.value
+ if isinstance(child, Token):
+ value += child.value
+ else:
+ assert False, 'Unsupported tree: ' + str(decimal_literal)
return int(value)
-def get_floating_pt_literal_value(floating_pt_literal):
+def get_floating_pt_literal_value(floating_pt_literal: 'ParseTree') -> float:
value = ''
for child in floating_pt_literal.children:
if isinstance(child, Token):
@@ -601,7 +688,7 @@ def get_floating_pt_literal_value(floating_pt_literal):
return float(value)
-def get_fixed_pt_literal_value(fixed_pt_literal):
+def get_fixed_pt_literal_value(fixed_pt_literal: 'ParseTree') -> float:
value = ''
for child in fixed_pt_literal.children:
if isinstance(child, Token):
@@ -611,7 +698,8 @@ def get_fixed_pt_literal_value(fixed_pt_literal):
return float(value)
-def get_string_literals_value(string_literals, *, allow_unicode=False):
+def get_string_literals_value(string_literals: 'ParseTree', *,
+ allow_unicode: bool = False) -> str:
assert len(string_literals.children) > 0
value = ''
for string_literal in string_literals.children:
@@ -620,7 +708,9 @@ def get_string_literals_value(string_literals, *, allow_unicode=False):
return value
-def get_string_literal_value(string_literal, *, allow_unicode=False):
+def get_string_literal_value(string_literal: 'Branch[Union[str, Token]]', *,
+ allow_unicode: bool = False) -> str:
+ assert isinstance(string_literal, Tree)
if len(string_literal.children) == 0:
return ''
assert len(string_literal.children) == 1
@@ -639,18 +729,18 @@ def get_string_literal_value(string_literal, *, allow_unicode=False):
value = value[1:-1]
regex = _get_escape_sequences_regex(allow_unicode=allow_unicode)
- value = regex.sub(_decode_escape_sequence, value)
- # unescape double quote and backslash if preceeded by a backslash
+ str_value = regex.sub(_decode_escape_sequence, value)
+ # unescape double quote and backslash if preceded by a backslash
i = 0
- while i < len(value):
- if value[i] == '\\':
- if i + 1 < len(value) and value[i + 1] in ('"', '\\'):
- value = value[:i] + value[i + 1:]
+ while i < len(str_value):
+ if str_value[i] == '\\':
+ if i + 1 < len(str_value) and str_value[i + 1] in ('"', '\\'):
+ str_value = str_value[:i] + str_value[i + 1:]
i += 1
- return value
+ return str_value
-def _get_escape_sequences_regex(*, allow_unicode):
+def _get_escape_sequences_regex(*, allow_unicode: bool) -> Pattern[str]:
# IDL Table 7-9: Escape sequences
pattern = '('
# newline, horizontal tab, vertical tab, backspace, carriage return,
@@ -668,5 +758,5 @@ def _get_escape_sequences_regex(*, allow_unicode):
return re.compile(pattern)
-def _decode_escape_sequence(match):
- return codecs.decode(match.group(0), 'unicode-escape')
+def _decode_escape_sequence(match: Match[str]) -> str:
+ return codecs.decode(match.group(0), 'unicode-escape') # type: ignore
diff --git a/rosidl_parser/test/test_parser.py b/rosidl_parser/test/test_parser.py
index b58f55721..61b164742 100644
--- a/rosidl_parser/test/test_parser.py
+++ b/rosidl_parser/test/test_parser.py
@@ -21,6 +21,7 @@
from rosidl_parser.definition import BoundedSequence
from rosidl_parser.definition import BoundedString
from rosidl_parser.definition import BoundedWString
+from rosidl_parser.definition import IdlFile
from rosidl_parser.definition import IdlLocator
from rosidl_parser.definition import Include
from rosidl_parser.definition import Message
@@ -43,11 +44,11 @@
@pytest.fixture(scope='module')
-def message_idl_file():
+def message_idl_file() -> IdlFile:
return parse_idl_file(MESSAGE_IDL_LOCATOR)
-def test_whitespace_at_start_of_string():
+def test_whitespace_at_start_of_string() -> None:
# Repeat to check ros2/rosidl#676
for _ in range(10):
ast = get_ast_from_idl_string('const string foo = " e";')
@@ -55,7 +56,7 @@ def test_whitespace_at_start_of_string():
assert ' e' == get_string_literals_value(token)
-def test_whitespace_at_start_of_wide_string():
+def test_whitespace_at_start_of_wide_string() -> None:
# Repeat to check ros2/rosidl#676
for _ in range(10):
ast = get_ast_from_idl_string('const wstring foo = L" e";')
@@ -63,7 +64,7 @@ def test_whitespace_at_start_of_wide_string():
assert ' e' == get_string_literals_value(token, allow_unicode=True)
-def test_whitespace_at_end_of_string():
+def test_whitespace_at_end_of_string() -> None:
# Repeat to check ros2/rosidl#676
for _ in range(10):
ast = get_ast_from_idl_string('const string foo = "e ";')
@@ -71,7 +72,7 @@ def test_whitespace_at_end_of_string():
assert 'e ' == get_string_literals_value(token)
-def test_whitespace_at_end_of_wide_string():
+def test_whitespace_at_end_of_wide_string() -> None:
# Repeat to check ros2/rosidl#676
for _ in range(10):
ast = get_ast_from_idl_string('const wstring foo = L"e ";')
@@ -79,19 +80,19 @@ def test_whitespace_at_end_of_wide_string():
assert 'e ' == get_string_literals_value(token, allow_unicode=True)
-def test_message_parser(message_idl_file):
+def test_message_parser(message_idl_file: IdlFile) -> None:
messages = message_idl_file.content.get_elements_of_type(Message)
assert len(messages) == 1
-def test_message_parser_includes(message_idl_file):
+def test_message_parser_includes(message_idl_file: IdlFile) -> None:
includes = message_idl_file.content.get_elements_of_type(Include)
assert len(includes) == 2
assert includes[0].locator == 'OtherMessage.idl'
assert includes[1].locator == 'pkgname/msg/OtherMessage.idl'
-def test_message_parser_structure(message_idl_file):
+def test_message_parser_structure(message_idl_file: IdlFile) -> None:
messages = message_idl_file.content.get_elements_of_type(Message)
assert len(messages) == 1
@@ -185,19 +186,19 @@ def test_message_parser_structure(message_idl_file):
assert structure.members[31].name == 'array_short_values'
-def test_message_parser_annotations(message_idl_file):
+def test_message_parser_annotations(message_idl_file: IdlFile) -> None:
messages = message_idl_file.content.get_elements_of_type(Message)
assert len(messages) == 1
structure = messages[0].structure
assert len(structure.annotations) == 2
assert structure.annotations[0].name == 'verbatim'
- assert len(structure.annotations[0].value) == 2
- assert 'language' in structure.annotations[0].value
- assert structure.annotations[0].value['language'] == 'comment'
- assert 'text' in structure.annotations[0].value
- assert structure.annotations[0].value['text'] == \
- 'Documentation of MyMessage.Adjacent string literal.'
+ assert len(structure.annotations[0].value) == 2 # type: ignore[arg-type]
+ assert 'language' in structure.annotations[0].value # type: ignore[operator]
+ assert structure.annotations[0].value['language'] == 'comment' # type: ignore[index]
+ assert 'text' in structure.annotations[0].value # type: ignore[operator]
+ text = structure.annotations[0].value['text'] # type: ignore[index]
+ assert text == 'Documentation of MyMessage.Adjacent string literal.'
assert structure.annotations[1].name == 'transfer_mode'
assert structure.annotations[1].value == 'SHMEM_REF'
@@ -206,9 +207,9 @@ def test_message_parser_annotations(message_idl_file):
assert structure.has_any_member_with_annotation('autoid') is False
assert structure.members[2].annotations[0].name == 'default'
- assert len(structure.members[2].annotations[0].value) == 1
- assert 'value' in structure.members[2].annotations[0].value
- assert structure.members[2].annotations[0].value['value'] == 123
+ assert len(structure.members[2].annotations[0].value) == 1 # type: ignore[arg-type]
+ assert 'value' in structure.members[2].annotations[0].value # type: ignore[operator]
+ assert structure.members[2].annotations[0].value['value'] == 123 # type: ignore[index]
assert structure.has_any_member_with_annotation('default')
assert len(structure.members[3].annotations) == 2
@@ -218,11 +219,11 @@ def test_message_parser_annotations(message_idl_file):
assert structure.has_any_member_with_annotation('key')
assert structure.members[3].annotations[1].name == 'range'
- assert len(structure.members[3].annotations[1].value) == 2
- assert 'min' in structure.members[3].annotations[1].value
- assert structure.members[3].annotations[1].value['min'] == -10
- assert 'max' in structure.members[3].annotations[1].value
- assert structure.members[3].annotations[1].value['max'] == 10
+ assert len(structure.members[3].annotations[1].value) == 2 # type: ignore[arg-type]
+ assert 'min' in structure.members[3].annotations[1].value # type: ignore[operator]
+ assert structure.members[3].annotations[1].value['min'] == -10 # type: ignore[index]
+ assert 'max' in structure.members[3].annotations[1].value # type: ignore[operator]
+ assert structure.members[3].annotations[1].value['max'] == 10 # type: ignore[index]
assert structure.has_any_member_with_annotation('range')
assert isinstance(structure.members[32].type, BasicType)
@@ -305,11 +306,11 @@ def test_message_parser_annotations(message_idl_file):
@pytest.fixture(scope='module')
-def service_idl_file():
+def service_idl_file() -> IdlFile:
return parse_idl_file(SERVICE_IDL_LOCATOR)
-def test_service_parser(service_idl_file):
+def test_service_parser(service_idl_file: IdlFile) -> None:
services = service_idl_file.content.get_elements_of_type(Service)
assert len(services) == 1
@@ -345,11 +346,11 @@ def test_service_parser(service_idl_file):
@pytest.fixture(scope='module')
-def action_idl_file():
+def action_idl_file() -> IdlFile:
return parse_idl_file(ACTION_IDL_LOCATOR)
-def test_action_parser(action_idl_file):
+def test_action_parser(action_idl_file: IdlFile) -> None:
actions = action_idl_file.content.get_elements_of_type(Action)
assert len(actions) == 1