Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Types for rosidl_adapter #828

Merged
merged 6 commits into from
Nov 1, 2024
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
1 change: 1 addition & 0 deletions rosidl_adapter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ament_python_install_package(${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_cmake_pytest REQUIRED)
find_package(ament_lint_auto REQUIRED)
find_package(ament_cmake_mypy REQUIRED)
ament_lint_auto_find_test_dependencies()
ament_add_pytest_test(pytest test)
endif()
Expand Down
1 change: 1 addition & 0 deletions rosidl_adapter/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<exec_depend>python3-empy</exec_depend>
<exec_depend>rosidl_cli</exec_depend>

<test_depend>ament_cmake_mypy</test_depend>
<test_depend>ament_cmake_pytest</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>ament_lint_auto</test_depend>
Expand Down
5 changes: 4 additions & 1 deletion rosidl_adapter/rosidl_adapter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from pathlib import Path

def convert_to_idl(package_dir, package_name, interface_file, output_dir):

def convert_to_idl(package_dir: Path, package_name: str, interface_file: Path,
output_dir: Path) -> Path:
if interface_file.suffix == '.msg':
from rosidl_adapter.msg import convert_msg_to_idl
return convert_msg_to_idl(
Expand Down
3 changes: 2 additions & 1 deletion rosidl_adapter/rosidl_adapter/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@

from rosidl_adapter.main import main

sys.exit(main())
main()
sys.exit()
9 changes: 6 additions & 3 deletions rosidl_adapter/rosidl_adapter/action/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from pathlib import Path

from rosidl_adapter.parser import parse_action_string
from rosidl_adapter.resource import expand_template
from rosidl_adapter.resource import ActionData, expand_template


def convert_action_to_idl(package_dir, package_name, input_file, output_dir):
def convert_action_to_idl(package_dir: Path, package_name: str, input_file: Path,
output_dir: Path) -> Path:
assert package_dir.is_absolute()
assert not input_file.is_absolute()
assert input_file.suffix == '.action'
Expand All @@ -30,7 +33,7 @@ def convert_action_to_idl(package_dir, package_name, input_file, output_dir):
output_file = output_dir / input_file.with_suffix('.idl').name
abs_output_file = output_file.absolute()
print(f'Writing output file: {abs_output_file}')
data = {
data: ActionData = {
'pkg_name': package_name,
'relative_input_file': input_file.as_posix(),
'action': action,
Expand Down
41 changes: 26 additions & 15 deletions rosidl_adapter/rosidl_adapter/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
# limitations under the License.

import argparse
import pathlib
from pathlib import Path
import sys
from typing import Callable, List, Literal, TYPE_CHECKING

from catkin_pkg.package import package_exists_at
from catkin_pkg.package import parse_package
Expand All @@ -27,7 +28,18 @@
from rosidl_cli.command.translate.extensions import TranslateCommandExtension


def convert_files_to_idl(extension, conversion_function, argv=sys.argv[1:]):
if TYPE_CHECKING:
from typing_extensions import TypeAlias

ConversionFunctionType: TypeAlias = Callable[[Path, str, Path, Path], Path]


def convert_files_to_idl(
extension: Literal['.msg', '.srv', '.action'],
conversion_function: 'ConversionFunctionType',
argv: List[str] = sys.argv[1:]
) -> None:

parser = argparse.ArgumentParser(
description=f'Convert {extension} files to .idl')
parser.add_argument(
Expand All @@ -36,7 +48,7 @@ def convert_files_to_idl(extension, conversion_function, argv=sys.argv[1:]):
args = parser.parse_args(argv)

for interface_file in args.interface_files:
interface_file = pathlib.Path(interface_file)
interface_file = Path(interface_file)
package_dir = interface_file.parent.absolute()
while (
len(package_dir.parents) and
Expand All @@ -48,8 +60,7 @@ def convert_files_to_idl(extension, conversion_function, argv=sys.argv[1:]):
f"Could not find package for '{interface_file}'",
file=sys.stderr)
continue
warnings = []
pkg = parse_package(package_dir, warnings=warnings)
pkg = parse_package(package_dir, warnings=[])

conversion_function(
package_dir, pkg.name,
Expand All @@ -63,14 +74,14 @@ class TranslateToIDL(TranslateCommandExtension):

def translate(
self,
package_name,
interface_files,
include_paths,
output_path
):
package_name: str,
interface_files: List[str],
include_paths: List[str],
output_path: Path
) -> List[str]:
translated_interface_files = []
for interface_file in interface_files:
prefix, interface_file = interface_path_as_tuple(interface_file)
for interface_file_str in interface_files:
prefix, interface_file = interface_path_as_tuple(interface_file_str)
output_dir = output_path / interface_file.parent
translated_interface_file = self.conversion_function(
prefix, package_name, interface_file, output_dir)
Expand All @@ -87,7 +98,7 @@ class TranslateMsgToIDL(TranslateToIDL):
input_format = 'msg'

@property
def conversion_function(self):
def conversion_function(self) -> 'ConversionFunctionType':
return convert_msg_to_idl


Expand All @@ -96,13 +107,13 @@ class TranslateSrvToIDL(TranslateToIDL):
input_format = 'srv'

@property
def conversion_function(self):
def conversion_function(self) -> 'ConversionFunctionType':
return convert_srv_to_idl


class TranslateActionToIDL(TranslateToIDL):
input_format = 'action'

@property
def conversion_function(self):
def conversion_function(self) -> 'ConversionFunctionType':
return convert_action_to_idl
3 changes: 2 additions & 1 deletion rosidl_adapter/rosidl_adapter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
import os
import pathlib
import sys
from typing import List


from rosidl_adapter import convert_to_idl


def main(argv=sys.argv[1:]):
def main(argv: List[str] = sys.argv[1:]) -> None:
parser = argparse.ArgumentParser(
description='Convert interface files to .idl')
parser.add_argument(
Expand Down
24 changes: 14 additions & 10 deletions rosidl_adapter/rosidl_adapter/msg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from rosidl_adapter.parser import parse_message_string
from rosidl_adapter.resource import expand_template
from pathlib import Path
from typing import Final, Optional, Union

from rosidl_adapter.parser import BaseType, parse_message_string, Type
from rosidl_adapter.resource import expand_template, MsgData

def convert_msg_to_idl(package_dir, package_name, input_file, output_dir):

def convert_msg_to_idl(package_dir: Path, package_name: str, input_file: Path,
output_dir: Path) -> Path:
assert package_dir.is_absolute()
assert not input_file.is_absolute()
assert input_file.suffix == '.msg'
Expand All @@ -30,7 +34,7 @@ def convert_msg_to_idl(package_dir, package_name, input_file, output_dir):
output_file = output_dir / input_file.with_suffix('.idl').name
abs_output_file = output_file.absolute()
print(f'Writing output file: {abs_output_file}')
data = {
data: MsgData = {
'pkg_name': package_name,
'relative_input_file': input_file.as_posix(),
'msg': msg,
Expand All @@ -40,7 +44,7 @@ def convert_msg_to_idl(package_dir, package_name, input_file, output_dir):
return output_file


MSG_TYPE_TO_IDL = {
MSG_TYPE_TO_IDL: Final = {
'bool': 'boolean',
'byte': 'octet',
'char': 'uint8',
Expand All @@ -59,7 +63,7 @@ def convert_msg_to_idl(package_dir, package_name, input_file, output_dir):
}


def to_idl_literal(idl_type, value):
def to_idl_literal(idl_type: str, value: str) -> str:
if idl_type[-1] == ']' or idl_type.startswith('sequence<'):
content = repr(tuple(value)).replace('\\', r'\\').replace('"', r'\"')
return f'"{content}"'
Expand All @@ -73,24 +77,24 @@ def to_idl_literal(idl_type, value):
return value


def string_to_idl_string_literal(string):
def string_to_idl_string_literal(string: str) -> str:
"""Convert string to character literal as described in IDL 4.2 section 7.2.6.3 ."""
estr = string.encode().decode('unicode_escape')
estr = estr.replace('"', r'\"')
return '"{0}"'.format(estr)


def string_to_idl_wstring_literal(string):
def string_to_idl_wstring_literal(string: str) -> str:
return string_to_idl_string_literal(string)


def get_include_file(base_type):
def get_include_file(base_type: BaseType) -> Optional[str]:
if base_type.is_primitive_type():
return None
return f'{base_type.pkg_name}/msg/{base_type.type}.idl'


def get_idl_type(type_):
def get_idl_type(type_: Union[str, Type]) -> str:
if isinstance(type_, str):
identifier = MSG_TYPE_TO_IDL[type_]
elif type_.is_primitive_type():
Expand Down
Loading
Loading