From c20b0600d4d7522379cdc6e75eeda534d77b3c5b Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Wed, 21 Nov 2018 15:23:01 -0800 Subject: [PATCH 01/26] update includes and type mapping --- .../_msg_pkg_typesupport_entry_point.c.em | 12 ++++++++++ .../resource/_msg_support.c.em | 17 ++++++++++++-- .../rosidl_generator_py/generate_py_impl.py | 22 ++++++++++++++++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em index 37ecb9d7..8f0159f5 100644 --- a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em @@ -35,10 +35,21 @@ if action_specs: @(value) @[end for]@ @{ +def strip_suffix(name): + if name.endswith('__request'): + name = name[:-9] + elif name.endswith('__response'): + name = name[:-10] + if name.endswith('__goal'): + name = name[:-6] + elif name.endswith('__result'): + name = name[:-8] + return name includes = {} for spec, subfolder in message_specs: type_name = spec.base_type.type module_name = convert_camel_case_to_lower_case_underscore(type_name) + module_name = strip_suffix(module_name) key = '%s/%s/%s' % (spec.base_type.pkg_name, subfolder, module_name) includes[key + '_support'] = '#include <%s__type_support.h>' % key includes[key + '_struct'] = '#include <%s__struct.h>' % key @@ -47,6 +58,7 @@ for spec, subfolder in message_specs: for spec, subfolder in service_specs: type_name = convert_camel_case_to_lower_case_underscore(spec.srv_name) module_name = convert_camel_case_to_lower_case_underscore(type_name) + module_name = strip_suffix(module_name) key = '%s/%s/%s' % (spec.pkg_name, subfolder, module_name) includes[key] = '#include <%s.h>' % key }@ diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index c8833dd6..b2b9fd81 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -17,8 +17,21 @@ #include -#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__struct.h> -#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__functions.h> +@{ +header_filename = module_name +if header_filename.endswith('__request'): + header_filename = header_filename[:-9] +elif header_filename.endswith('__response'): + header_filename = header_filename[:-10] +if header_filename.endswith('__goal'): + header_filename = header_filename[:-6] +elif header_filename.endswith('__result'): + header_filename = header_filename[:-8] +elif header_filename.endswith('__feedback'): + header_filename = header_filename[:-10] +}@ +#include <@(spec.base_type.pkg_name)/@(subfolder)/@(header_filename)__struct.h> +#include <@(spec.base_type.pkg_name)/@(subfolder)/@(header_filename)__functions.h> @{ have_not_included_primitive_arrays = True diff --git a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py index e44a80a2..e68e189b 100644 --- a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py +++ b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py @@ -26,6 +26,26 @@ from rosidl_parser import parse_service_file +def _primitive_msg_type_to_c(type_): + msg_type_to_c = { + 'bool': 'bool', + 'byte': 'uint8_t', + 'char': 'signed char', + 'float32': 'float', + 'float64': 'double', + 'uint8': 'uint8_t', + 'int8': 'int8_t', + 'uint16': 'uint16_t', + 'int16': 'int16_t', + 'uint32': 'uint32_t', + 'int32': 'int32_t', + 'uint64': 'uint64_t', + 'int64': 'int64_t', + 'string': 'rosidl_generator_c__String', + } + return msg_type_to_c[type_] + + def generate_py(generator_arguments_file, typesupport_impls): args = read_generator_arguments(generator_arguments_file) @@ -62,7 +82,7 @@ def generate_py(generator_arguments_file, typesupport_impls): functions = { 'constant_value_to_py': constant_value_to_py, 'get_python_type': get_python_type, - 'primitive_msg_type_to_c': primitive_msg_type_to_c, + 'primitive_msg_type_to_c': _primitive_msg_type_to_c, 'value_to_py': value_to_py, 'convert_camel_case_to_lower_case_underscore': convert_camel_case_to_lower_case_underscore, } From d413fe98e73a0105223b8d26721c636cf871d532 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Sat, 24 Nov 2018 12:03:02 -0800 Subject: [PATCH 02/26] map char to uint8_t --- rosidl_generator_py/resource/_msg_support.c.em | 9 +++++++-- .../rosidl_generator_py/generate_py_impl.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index b2b9fd81..d38897f0 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -193,8 +193,13 @@ lowercase_field_type = convert_camel_case_to_lower_case_underscore(field.type.ty return false; } @[ else]@ - if (!rosidl_generator_c__@(field.type.type)__Sequence__init(&(ros_message->@(field.name)), size)) { - PyErr_SetString(PyExc_RuntimeError, "unable to create @(field.type.type)__Sequence ros_message"); +@{ +type_ = field.type.type +if type_ == 'char': + type_ = 'uint8' +}@ + if (!rosidl_generator_c__@(type_)__Sequence__init(&(ros_message->@(field.name)), size)) { + PyErr_SetString(PyExc_RuntimeError, "unable to create @(type_)__Sequence ros_message"); Py_DECREF(seq_field); Py_DECREF(field); return false; diff --git a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py index e68e189b..318fa98f 100644 --- a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py +++ b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py @@ -30,7 +30,7 @@ def _primitive_msg_type_to_c(type_): msg_type_to_c = { 'bool': 'bool', 'byte': 'uint8_t', - 'char': 'signed char', + 'char': 'uint8_t', 'float32': 'float', 'float64': 'double', 'uint8': 'uint8_t', From 6eefdee94b6d29a7c73b3f7bd941ccee2b3473f9 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Mon, 3 Dec 2018 08:42:00 -0800 Subject: [PATCH 03/26] update rosidl_generator_py to use IDL-based extension point --- rosidl_generator_py/cmake/register_py.cmake | 2 +- ...idl_generator_py_generate_interfaces.cmake | 109 ++--- rosidl_generator_py/resource/_idl.py.em | 89 ++++ .../_idl_pkg_typesupport_entry_point.c.em | 194 ++++++++ .../resource/_idl_support.c.em | 122 +++++ rosidl_generator_py/resource/_msg.py.em | 368 ++++++++------- .../_msg_pkg_typesupport_entry_point.c.em | 167 +++---- .../resource/_msg_support.c.em | 440 ++++++++++-------- rosidl_generator_py/resource/_srv.py.em | 62 +-- .../_srv_pkg_typesupport_entry_point.c.em | 49 ++ .../rosidl_generator_py/generate_py_impl.py | 264 ++++------- rosidl_generator_py/test/test_interfaces.py | 34 +- 12 files changed, 1127 insertions(+), 773 deletions(-) create mode 100644 rosidl_generator_py/resource/_idl.py.em create mode 100644 rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em create mode 100644 rosidl_generator_py/resource/_idl_support.c.em create mode 100644 rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em diff --git a/rosidl_generator_py/cmake/register_py.cmake b/rosidl_generator_py/cmake/register_py.cmake index 937b3916..5e3e4b69 100644 --- a/rosidl_generator_py/cmake/register_py.cmake +++ b/rosidl_generator_py/cmake/register_py.cmake @@ -15,7 +15,7 @@ macro(rosidl_generator_py_extras BIN GENERATOR_FILES TEMPLATE_DIR) find_package(ament_cmake_core QUIET REQUIRED) ament_register_extension( - "rosidl_generate_interfaces" + "rosidl_generate_idl_interfaces" "rosidl_generator_py" "rosidl_generator_py_generate_interfaces.cmake") diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake index 5c0d6773..66cc14e2 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Open Source Robotics Foundation, Inc. +# Copyright 2014-2018 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. @@ -34,83 +34,38 @@ endif() set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py/${PROJECT_NAME}") set(_generated_extension_files "") -set(_generated_msg_py_files "") -set(_generated_msg_c_files "") -set(_generated_srv_py_files "") -set(_generated_srv_c_files "") -set(_generated_action_py_files "") -set(_generated_action_c_files "") +set(_generated_py_files "") +set(_generated_c_files "") foreach(_typesupport_impl ${_typesupport_impls}) set(_generated_extension_${_typesupport_impl}_files "") endforeach() -foreach(_idl_file ${rosidl_generate_interfaces_IDL_FILES}) - get_filename_component(_parent_folder "${_idl_file}" DIRECTORY) +foreach(_idl_tuple ${rosidl_generate_interfaces_IDL_TUPLES}) + string(REGEX REPLACE ":([^:]*)$" "/\\1" _abs_idl_file "${_idl_tuple}") + get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) get_filename_component(_parent_folder "${_parent_folder}" NAME) - get_filename_component(_msg_name1 "${_idl_file}" NAME_WE) - get_filename_component(_ext "${_idl_file}" EXT) - string_camel_case_to_lower_case_underscore("${_msg_name1}" _module_name) - - if(_parent_folder STREQUAL "msg") - list(APPEND _generated_msg_py_files - "${_output_path}/${_parent_folder}/_${_module_name}.py" - ) - list(APPEND _generated_msg_c_files - "${_output_path}/${_parent_folder}/_${_module_name}_s.c" - ) - elseif(_parent_folder STREQUAL "srv") - if("_${_module_name}_s.c" MATCHES "(.*)__response(.*)" OR "_${_module_name}_s.c" MATCHES "(.*)__request(.*)") - list(APPEND _generated_srv_c_files - "${_output_path}/${_parent_folder}/_${_module_name}_s.c" - ) - endif() - list(APPEND _generated_srv_py_files - "${_output_path}/${_parent_folder}/_${_module_name}.py" - ) - elseif(_parent_folder STREQUAL "action") - # C files generated for .msg, _Request.msg and _Response.msg but not .srv - if(_ext STREQUAL ".msg") - list(APPEND _generated_action_c_files - "${_output_path}/${_parent_folder}/_${_module_name}_s.c" - ) - endif() - list(APPEND _generated_action_py_files - "${_output_path}/${_parent_folder}/_${_module_name}.py" - ) - else() - message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}") - endif() + get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) + string_camel_case_to_lower_case_underscore("${_idl_name}" _module_name) + list(APPEND _generated_py_files + "${_output_path}/${_parent_folder}/_${_module_name}.py") + list(APPEND _generated_c_files + "${_output_path}/${_parent_folder}/_${_module_name}_s.c") endforeach() file(MAKE_DIRECTORY "${_output_path}") file(WRITE "${_output_path}/__init__.py" "") -if(NOT _generated_msg_py_files STREQUAL "") - list(GET _generated_msg_py_files 0 _msg_file) - get_filename_component(_parent_folder "${_msg_file}" DIRECTORY) - list(APPEND _generated_msg_py_files - "${_parent_folder}/__init__.py" - ) -endif() - -if(NOT _generated_srv_py_files STREQUAL "") - list(GET _generated_srv_py_files 0 _srv_file) - get_filename_component(_parent_folder "${_srv_file}" DIRECTORY) - list(APPEND _generated_srv_py_files - "${_parent_folder}/__init__.py" - ) -endif() - -if(NOT _generated_action_py_files STREQUAL "") - list(GET _generated_action_py_files 0 _action_file) - get_filename_component(_parent_folder "${_action_file}" DIRECTORY) - list(APPEND _generated_action_py_files - "${_parent_folder}/__init__.py" - ) -endif() +foreach(_generated_py_file ${_generated_py_files}) + get_filename_component(_parent_folder "${_generated_py_file}" DIRECTORY) + set(_init_module "${_parent_folder}/__init__.py") + list(FIND _generated_py_files "${_init_module}" _index) + if(_index EQUAL -1) + list(APPEND _generated_py_files "${_init_module}") + endif() +endforeach() -if(NOT _generated_msg_c_files STREQUAL "" OR NOT _generated_srv_c_files STREQUAL "" OR NOT _generated_action_c_files STREQUAL "") +if(NOT _generated_c_files STREQUAL "") foreach(_typesupport_impl ${_typesupport_impls}) list(APPEND _generated_extension_${_typesupport_impl}_files "${_output_path}/_${PROJECT_NAME}_s.ep.${_typesupport_impl}.c") list(APPEND _generated_extension_files "${_generated_extension_${_typesupport_impl}_files}") @@ -119,7 +74,7 @@ endif() set(_dependency_files "") set(_dependencies "") foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) - foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES}) + foreach(_idl_file ${${_pkg_name}_IDL_FILES}) set(_abs_idl_file "${${_pkg_name}_DIR}/../${_idl_file}") normalize_path(_abs_idl_file "${_abs_idl_file}") list(APPEND _dependency_files "${_abs_idl_file}") @@ -130,8 +85,10 @@ endforeach() set(target_dependencies "${rosidl_generator_py_BIN}" ${rosidl_generator_py_GENERATOR_FILES} + "${rosidl_generator_py_TEMPLATE_DIR}/_idl_support.c.em" "${rosidl_generator_py_TEMPLATE_DIR}/_msg_support.c.em" "${rosidl_generator_py_TEMPLATE_DIR}/_msg_pkg_typesupport_entry_point.c.em" + "${rosidl_generator_py_TEMPLATE_DIR}/_idl.py.em" "${rosidl_generator_py_TEMPLATE_DIR}/_msg.py.em" "${rosidl_generator_py_TEMPLATE_DIR}/_srv.py.em" ${_dependency_files}) @@ -145,7 +102,7 @@ set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py__a rosidl_write_generator_arguments( "${generator_arguments_file}" PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_interfaces_IDL_FILES}" + IDL_TUPLES "${rosidl_generate_interfaces_IDL_TUPLES}" ROS_INTERFACE_DEPENDENCIES "${_dependencies}" OUTPUT_DIR "${_output_path}" TEMPLATE_DIR "${rosidl_generator_py_TEMPLATE_DIR}" @@ -210,7 +167,7 @@ file(WRITE "${_subdir}/CMakeLists.txt" "${_custom_command}") add_subdirectory("${_subdir}" ${rosidl_generate_interfaces_TARGET}${_target_suffix}) set_property( SOURCE - ${_generated_extension_files} ${_generated_msg_py_files} ${_generated_msg_c_files} ${_generated_srv_py_files} ${_generated_srv_c_files} ${_generated_action_py_files} ${_generated_action_c_files} + ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} PROPERTY GENERATED 1) macro(set_properties _build_type) @@ -231,11 +188,7 @@ macro(set_lib_properties _build_type) endmacro() set(_target_name_lib "${rosidl_generate_interfaces_TARGET}__python") -add_library(${_target_name_lib} SHARED - ${_generated_msg_c_files} - ${_generated_srv_c_files} - ${_generated_action_c_files} -) +add_library(${_target_name_lib} SHARED ${_generated_c_files}) add_dependencies( ${_target_name_lib} ${rosidl_generate_interfaces_TARGET}${_target_suffix} @@ -359,13 +312,9 @@ endif() if(BUILD_TESTING AND rosidl_generate_interfaces_ADD_LINTER_TESTS) if( - NOT _generated_msg_py_files STREQUAL "" OR + NOT _generated_py_files STREQUAL "" OR NOT _generated_extension_files STREQUAL "" OR - NOT _generated_msg_c_files STREQUAL "" OR - NOT _generated_srv_py_files STREQUAL "" OR - NOT _generated_srv_c_files STREQUAL "" OR - NOT _generated_action_c_files STREQUAL "" OR - NOT _generated_action_py_files STREQUAL "" + NOT _generated_c_files STREQUAL "" ) find_package(ament_cmake_cppcheck REQUIRED) ament_cppcheck( diff --git a/rosidl_generator_py/resource/_idl.py.em b/rosidl_generator_py/resource/_idl.py.em new file mode 100644 index 00000000..72e6275c --- /dev/null +++ b/rosidl_generator_py/resource/_idl.py.em @@ -0,0 +1,89 @@ +# generated from rosidl_generator_py/resource/_idl.py.em +# with input from @(package_name):@(interface_path) +# generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating _.py files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@####################################################################### +@# Handle messages +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=message) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle services +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=service.request_message) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=service.response_message) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle actions +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.goal_request) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.result_response) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.goal_service.request_message) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.goal_service.response_message) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.result_service.request_message) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.result_service.response_message) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback_message) +}@ +@[end for]@ diff --git a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em new file mode 100644 index 00000000..2ad6fa66 --- /dev/null +++ b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em @@ -0,0 +1,194 @@ +// generated from rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __s.ep..c files +@# +@# Context: +@# - package_name (string) +@# - content (IdlContent, combined list of elements across all interface files +@# - typesupport_impl (string identifying the typesupport used) +@####################################################################### +@ +@####################################################################### +@# Handle messages +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_parser.definition import Message + +include_directives = set() +}@ +#include + +static PyMethodDef @(package_name)__methods[] = { + {NULL, NULL, 0, NULL} /* sentinel */ +}; + +static struct PyModuleDef @(package_name)__module = { + PyModuleDef_HEAD_INIT, + "_@(package_name)_support", + "_@(package_name)_doc", + -1, /* -1 means that the module keeps state in global variables */ + @(package_name)__methods, + NULL, + NULL, + NULL, + NULL, +}; +@ +@[for message in content.get_elements_of_type(Message)]@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, message=message, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle services +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ + +@{ +TEMPLATE( + '_srv_pkg_typesupport_entry_point.c.em', + package_name=package_name, service=service, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle actions +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, message=action.goal_request, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, message=action.result_response, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, message=action.feedback, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_srv_pkg_typesupport_entry_point.c.em', + package_name=package_name, service=action.goal_service, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_srv_pkg_typesupport_entry_point.c.em', + package_name=package_name, service=action.result_service, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, message=action.feedback_message, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ +@[end for]@ + +PyMODINIT_FUNC +PyInit_@(package_name)_s__@(typesupport_impl)(void) +{ + PyObject * pymodule = NULL; + pymodule = PyModule_Create(&@(package_name)__module); + if (!pymodule) { + return NULL; + } + int8_t err; +@[for message in content.get_elements_of_type(Message)]@ + + err = _register_msg_type__@('__'.join(message.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(message.structure.type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } +@[end for]@ +@[for service in content.get_elements_of_type(Service)]@ + + err = _register_msg_type__@('__'.join(service.request_message.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(service.request_message.structure.type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_msg_type__@('__'.join(service.response_message.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(service.response_message.structure.type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_srv_type__@('__'.join(service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(service.structure_type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } +@[end for]@ +@[for action in content.get_elements_of_type(Action)]@ + + err = _register_msg_type__@('__'.join(action.goal_request.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.goal_request.structure.type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_msg_type__@('__'.join(action.result_response.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.result_response.structure.type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_msg_type__@('__'.join(action.feedback.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.feedback.structure.type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_srv_type__@('__'.join(action.goal_service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.goal_service.structure_type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_srv_type__@('__'.join(action.result_service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.result_service.structure_type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } + + err = _register_msg_type__@('__'.join(action.feedback_message.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.feedback_message.structure.type.name))(pymodule); + if (err) { + Py_XDECREF(pymodule); + return NULL; + } +@[end for]@ + + return pymodule; +} diff --git a/rosidl_generator_py/resource/_idl_support.c.em b/rosidl_generator_py/resource/_idl_support.c.em new file mode 100644 index 00000000..6a279895 --- /dev/null +++ b/rosidl_generator_py/resource/_idl_support.c.em @@ -0,0 +1,122 @@ +// generated from rosidl_generator_py/resource/_idl_support.c.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __s.c files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@####################################################################### +@# Handle messages +@####################################################################### +@{ +from rosidl_parser.definition import Message + +include_directives = set() +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ + +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=message, include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle services +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ + +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=service.request_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=service.response_message, include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle actions +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ + +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=action.goal_request, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=action.result_response, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=action.goal_service.request_message, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=action.goal_service.response_message, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=action.result_service.request_message, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=action.result_service.response_message, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_support.c.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback_message, include_directives=include_directives) +}@ +@[end for]@ diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 24180fb7..2359df0b 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -1,26 +1,24 @@ -# generated from rosidl_generator_py/resource/_msg.py.em -# generated code does not contain a copyright notice +@# Included from rosidl_generator_py/resource/_idl.py.em +@{ -@####################################################################### -@# EmPy template for generating _.py files -@# -@# Context: -@# - module_name -@# - package_name -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - constant_value_to_py (function) -@# - get_python_type (function) -@# - value_to_py (function) -@####################################################################### -@ -from copy import copy -import logging -import traceback +from rosidl_cmake 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 +from rosidl_generator_py.generate_py_impl import value_to_py +from rosidl_parser.definition import Array +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import BoundedSequence +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import String +from rosidl_parser.definition import WString +}@ -class Metaclass(type): - """Metaclass of message '@(spec.base_type.type)'.""" +class Metaclass_@(message.structure.type.name)(type): + """Metaclass of message '@(message.structure.type.name)'.""" _CREATE_ROS_MESSAGE = None _CONVERT_FROM_PY = None @@ -29,7 +27,7 @@ class Metaclass(type): _TYPE_SUPPORT = None __constants = { -@[for constant in spec.constants]@ +@[for constant in message.constants.values()]@ '@(constant.name)': @constant_value_to_py(constant.type, constant.value), @[end for]@ } @@ -40,28 +38,36 @@ class Metaclass(type): from rosidl_generator_py import import_type_support module = import_type_support('@(package_name)') except ImportError: - logger = logging.getLogger('rosidl_generator_py.@(spec.base_type.type)') + import logging + import traceback + logger = logging.getLogger('@('.'.join(message.structure.type.namespaces + [message.structure.type.name]))') logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__@(subfolder)_@(module_name) - cls._CONVERT_FROM_PY = module.convert_from_py_msg__@(subfolder)_@(module_name) - cls._CONVERT_TO_PY = module.convert_to_py_msg__@(subfolder)_@(module_name) - cls._TYPE_SUPPORT = module.type_support_msg__@(subfolder)_@(module_name) - cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__@(subfolder)_@(module_name) @{ -importable_typesupports = {} -for field in spec.fields: - if not field.type.is_primitive_type(): - key = '%s.msg.%s' % (field.type.pkg_name, field.type.type) - if key not in importable_typesupports: - importable_typesupports[key] = [field.type.pkg_name, field.type.type] -for key in sorted(importable_typesupports.keys()): - (pkg_name, field_name) = importable_typesupports[key] - print('%sfrom %s.msg import %s' % (' ' * 4 * 3, pkg_name, field_name)) - print('%sif %s.__class__._TYPE_SUPPORT is None:' % (' ' * 4 * 3, field_name)) - print('%s%s.__class__.__import_type_support__()' % (' ' * 4 * 4, field_name)) +suffix = '.'.join(message.structure.type.namespaces[1:]) + '_' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) +}@ + cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__@(suffix) + cls._CONVERT_FROM_PY = module.convert_from_py_msg__@(suffix) + cls._CONVERT_TO_PY = module.convert_to_py_msg__@(suffix) + cls._TYPE_SUPPORT = module.type_support_msg__@(suffix) + cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__@(suffix) +@{ +importable_typesupports = set() +for member in message.structure.members: + type_ = member.type + if isinstance(type_, NestedType): + type_ = type_.basetype + if isinstance(type_, NamespacedType): + typename = (*type_.namespaces, type_.name) + importable_typesupports.add(typename) }@ +@[for typename in sorted(importable_typesupports)]@ + + from @('.'.join(typename[:-1])) import @(typename[-1]) + if @(typename[-1]).__class__._TYPE_SUPPORT is None: + @(typename[-1]).__class__.__import_type_support__() +@[end for]@ @@classmethod def __prepare__(cls, name, bases, **kwargs): @@ -69,119 +75,139 @@ for key in sorted(importable_typesupports.keys()): # the message class under "Data and other attributes defined here:" # as well as populate each message instance return { -@[for constant in spec.constants]@ +@[for constant in message.constants.values()]@ '@(constant.name)': cls.__constants['@(constant.name)'], @[end for]@ -@[for field in spec.fields]@ -@[ if field.default_value]@ - '@(field.name.upper())__DEFAULT': @value_to_py(field.type, field.default_value), +@[for member in message.structure.members]@ +@[ if member.has_annotation('default')]@ + '@(member.name.upper())__DEFAULT': @(value_to_py(member.type, member.get_annotation_value('default')['value'])), @[ end if]@ @[end for]@ } -@[for constant in spec.constants]@ +@[for constant in message.constants.values()]@ @@property def @(constant.name)(self): """Message constant '@(constant.name)'.""" - return Metaclass.__constants['@(constant.name)'] + return Metaclass_@(message.structure.type.name).__constants['@(constant.name)'] @[end for]@ -@[for field in spec.fields]@ -@[ if field.default_value]@ +@[for member in message.structure.members]@ +@[ if member.has_annotation('default')]@ @@property - def @(field.name.upper())__DEFAULT(cls): - """Return default value for message field '@(field.name)'.""" - return @value_to_py(field.type, field.default_value) + def @(member.name.upper())__DEFAULT(cls): + """Return default value for message field '@(member.name)'.""" + return @(value_to_py(member.type, member.get_annotation_value('default')['value'])) @[ end if]@ @[end for]@ -class @(spec.base_type.type)(metaclass=Metaclass): -@[if not spec.constants]@ - """Message class '@(spec.base_type.type)'.""" +class @(message.structure.type.name)(metaclass=Metaclass_@(message.structure.type.name)): +@[if not message.constants]@ + """Message class '@(message.structure.type.name)'.""" @[else]@ """ - Message class '@(spec.base_type.type)'. + Message class '@(message.structure.type.name)'. Constants: -@[ for constant in spec.constants]@ - @(constant.name) +@[ for constant_name in message.constants.keys()]@ + @(constant_name) @[ end for]@ """ @[end if]@ __slots__ = [ -@[for field in spec.fields]@ - '_@(field.name)', +@[for member in message.structure.members]@ + '_@(member.name)', @[end for]@ ] _fields_and_field_types = { -@[for field in spec.fields]@ -@[ if field.type.is_primitive_type() ]@ - '@(field.name)': '@(field.type)', -@[ else ]@ -@[ if field.type.is_array ]@ -@[ if field.type.array_size ]@ -@[ if field.type.is_upper_bound ]@ - '@(field.name)': '@(field.type.pkg_name)/@(field.type.type)[<=@(field.type.array_size)]', -@[ else ]@ - '@(field.name)': '@(field.type.pkg_name)/@(field.type.type)[@(field.type.array_size)]', -@[ end if ]@ -@[ else ]@ - '@(field.name)': '@(field.type.pkg_name)/@(field.type.type)[]', -@[ end if ]@ -@[ else ]@ - '@(field.name)': '@(field.type.pkg_name)/@(field.type.type)', -@[ end if ]@ -@[ end if ]@ +@[for member in message.structure.members]@ +@{ +type_ = member.type +if isinstance(type_, NestedType): + type_ = type_.basetype +}@ + '@(member.name)': '@ +@# the prefix for nested types +@[ if isinstance(member.type, Sequence)]@ +sequence<@ +@[ end if]@ +@# the typename of the non-nested type or the nested basetype +@[ if isinstance(type_, BasicType)]@ +@(type_.type)@ +@[ elif isinstance(type_, BaseString)]@ +@ +@[ if isinstance(type_, WString)]@ +w@ +@[ end if]@ +string@ +@[ if type_.maximum_size is not None]@ +<@(type_.maximum_size)>@ +@[ end if]@ +@[ elif isinstance(type_, NamespacedType)]@ +@('::'.join(type_.namespaces + [type_.name]))@ +@[ end if]@ +@# the suffix for nested types +@[ if isinstance(member.type, Sequence)]@ +@[ if isinstance(member.type, BoundedSequence)]@ +, @(member.type.upper_bound)@ +@[ end if]@ +>@ +@[ elif isinstance(member.type, Array)]@ +[@(member.type.size)]@ +@[ end if]@ +', @[end for]@ } -@ -@[if len(spec.fields) > 0]@ def __init__(self, **kwargs): assert all('_' + key in self.__slots__ for key in kwargs.keys()), \ 'Invalid arguments passed to constructor: %s' % \ ', '.join(sorted(k for k in kwargs.keys() if '_' + k not in self.__slots__)) -@[ for field in spec.fields]@ -@[ if field.default_value]@ - self.@(field.name) = kwargs.get( - '@(field.name)', @(spec.base_type.type).@(field.name.upper())__DEFAULT) -@[ else]@ -@[ if not field.type.is_primitive_type() and (not field.type.is_array or - (field.type.array_size and not field.type.is_upper_bound))]@ - from @(field.type.pkg_name).msg import @(field.type.type) -@[ end if]@ -@[ if field.type.array_size and not field.type.is_upper_bound]@ -@[ if field.type.type == 'byte']@ - self.@(field.name) = kwargs.get( - '@(field.name)', - [bytes([0]) for x in range(@(field.type.array_size))] - ) -@[ elif field.type.type == 'char']@ - self.@(field.name) = kwargs.get( - '@(field.name)', - [chr(0) for x in range(@(field.type.array_size))] +@[for member in message.structure.members]@ +@{ +type_ = member.type +if isinstance(type_, NestedType): + type_ = type_.basetype +}@ +@[ if member.has_annotation('default')]@ + self.@(member.name) = kwargs.get( + '@(member.name)', @(message.structure.type.name).@(member.name.upper())__DEFAULT) +@[ else]@ +@[ if isinstance(type_, NamespacedType) and not isinstance(member.type, Sequence)]@ +@# import @('.'.join(type_.namespaces + [type_.name])) + from @('.'.join(type_.namespaces)) import @(type_.name) +@[ end if]@ +@[ if isinstance(member.type, Array)]@ +@[ if isinstance(type_, BasicType) and type_.type == 'octet']@ + self.@(member.name) = kwargs.get( + '@(member.name)', + [bytes([0]) for x in range(@(member.type.size))] ) -@[ else]@ - self.@(field.name) = kwargs.get( - '@(field.name)', - [@(get_python_type(field.type))() for x in range(@(field.type.array_size))] +@[ elif isinstance(type_, BasicType) and type_.type in ('char', 'wchar')]@ + self.@(member.name) = kwargs.get( + '@(member.name)', + [chr(0) for x in range(@(member.type.size))] ) -@[ end if]@ -@[ elif field.type.is_array]@ - self.@(field.name) = kwargs.get('@(field.name)', []) -@[ elif field.type.type == 'byte']@ - self.@(field.name) = kwargs.get('@(field.name)', bytes([0])) -@[ elif field.type.type == 'char']@ - self.@(field.name) = kwargs.get('@(field.name)', chr(0)) @[ else]@ - self.@(field.name) = kwargs.get('@(field.name)', @(get_python_type(field.type))()) + self.@(member.name) = kwargs.get( + '@(member.name)', + [@(get_python_type(type_))() for x in range(@(member.type.size))] + ) @[ end if]@ +@[ elif isinstance(member.type, Sequence)]@ + self.@(member.name) = kwargs.get('@(member.name)', []) +@[ elif isinstance(type_, BasicType) and type_.type == 'octet']@ + self.@(member.name) = kwargs.get('@(member.name)', bytes([0])) +@[ elif isinstance(type_, BasicType) and type_.type in ('char', 'wchar')]@ + self.@(member.name) = kwargs.get('@(member.name)', chr(0)) +@[ else]@ + self.@(member.name) = kwargs.get('@(member.name)', @(get_python_type(type_))()) @[ end if]@ -@[ end for]@ -@[end if]@ +@[ end if]@ +@[end for]@ def __repr__(self): typename = self.__class__.__module__.split('.') @@ -193,136 +219,144 @@ class @(spec.base_type.type)(metaclass=Metaclass): def __eq__(self, other): if not isinstance(other, self.__class__): return False -@[for field in spec.fields]@ - if self.@(field.name) != other.@(field.name): +@[for member in message.structure.members]@ + if self.@(member.name) != other.@(member.name): return False @[end for]@ return True @@classmethod def get_fields_and_field_types(cls): + from copy import copy return copy(cls._fields_and_field_types) -@[for field in spec.fields]@ +@[for member in message.structure.members]@ @{ +type_ = member.type +if isinstance(type_, NestedType): + type_ = type_.basetype + import inspect import builtins noqa_string = '' -if field.name in dict(inspect.getmembers(builtins)).keys(): +if member.name in dict(inspect.getmembers(builtins)).keys(): noqa_string = ' # noqa: A003' }@ @@property@(noqa_string) - def @(field.name)(self): - """Message field '@(field.name)'.""" - return self._@(field.name) + def @(member.name)(self): + """Message field '@(member.name)'.""" + return self._@(member.name) - @@@(field.name).setter@(noqa_string) - def @(field.name)(self, value): + @@@(member.name).setter@(noqa_string) + def @(member.name)(self, value): if __debug__: -@[ if not field.type.is_primitive_type()]@ - from @(field.type.pkg_name).msg import @(field.type.type) +@[ if isinstance(type_, NamespacedType)]@ +@# import @('.'.join(type_.namespaces + [type_.name])) + from @('.'.join(type_.namespaces)) import @(type_.name) @[ end if]@ -@[ if field.type.is_array]@ +@[ if isinstance(member.type, NestedType)]@ from collections.abc import Sequence from collections.abc import Set from collections import UserList from collections import UserString -@[ elif field.type.string_upper_bound]@ +@[ elif isinstance(type_, String) and type_.maximum_size is not None]@ from collections import UserString -@[ elif field.type.type == 'byte']@ +@[ elif isinstance(type_, BasicType) and type_.type == 'octet']@ from collections.abc import ByteString -@[ elif field.type.type in ['char']]@ +@[ elif isinstance(type_, BasicType) and type_.type in ('char', 'wchar')]@ from collections import UserString @[ end if]@ assert \ -@[ if field.type.is_array]@ +@[ if isinstance(member.type, NestedType)]@ ((isinstance(value, Sequence) or isinstance(value, Set) or isinstance(value, UserList)) and not isinstance(value, str) and not isinstance(value, UserString) and @{assert_msg_suffixes = ['a set or sequence']}@ -@[ if field.type.type == 'string' and field.type.string_upper_bound]@ - all(len(val) <= @field.type.string_upper_bound for val in value) and -@{assert_msg_suffixes.append('and each string value not longer than %d' % field.type.string_upper_bound)}@ +@[ if isinstance(type_, String) and type_.maximum_size is not None]@ + 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 field.type.array_size]@ -@[ if field.type.is_upper_bound]@ - len(value) <= @(field.type.array_size) and -@{assert_msg_suffixes.insert(1, 'with length <= %d' % field.type.array_size)}@ +@[ if isinstance(member.type, Array) or isinstance(member.type, BoundedSequence)]@ +@[ if isinstance(member.type, BoundedSequence)]@ + len(value) <= @(member.type.upper_bound) and +@{assert_msg_suffixes.insert(1, 'with length <= %d' % member.type.upper_bound)}@ @[ else]@ - len(value) == @(field.type.array_size) and -@{assert_msg_suffixes.insert(1, 'with length %d' % field.type.array_size)}@ + 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(field.type))) for v in value) and -@{assert_msg_suffixes.append("and each value of type '%s'" % get_python_type(field.type))}@ -@[ if field.type.type.startswith('int')]@ + 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_.type.startswith('int')]@ @{ -nbits = int(field.type.type[3:]) +nbits = int(type_.type[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 field.type.type.startswith('uint')]@ +@[ elif isinstance(type_, BasicType) and type_.type.startswith('uint')]@ @{ -nbits = int(field.type.type[4:]) +nbits = int(type_.type[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 field.type.type == 'char']@ +@[ elif isinstance(type_, BasicType) and type_.type == 'char']@ all(ord(val) >= -128 and ord(val) < 128 for val in value)), \ @{assert_msg_suffixes.append('and each characters ord() in [-128, 127]')}@ @[ else]@ True), \ @[ end if]@ - "The '@(field.name)' field must be @(' '.join(assert_msg_suffixes))" -@[ elif field.type.string_upper_bound]@ + "The '@(member.name)' field must be @(' '.join(assert_msg_suffixes))" +@[ elif isinstance(member.type, BaseString) and member.type.maximum_size is not None]@ ((isinstance(value, str) or isinstance(value, UserString)) and - len(value) <= @(field.type.string_upper_bound)), \ - "The '@(field.name)' field must be string value " \ - 'not longer than @(field.type.string_upper_bound)' -@[ elif not field.type.is_primitive_type()]@ - isinstance(value, @(field.type.type)), \ - "The '@(field.name)' field must be a sub message of type '@(field.type.type)'" -@[ elif field.type.type == 'byte']@ + 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_.type == 'octet']@ ((isinstance(value, bytes) or isinstance(value, ByteString)) and len(value) == 1), \ - "The '@(field.name)' field must of type 'bytes' or 'ByteString' with a length 1" -@[ elif field.type.type == 'char']@ + "The '@(member.name)' field must of type 'bytes' or 'ByteString' with a length 1" +@[ elif isinstance(type_, BasicType) and type_.type == 'char']@ ((isinstance(value, str) or isinstance(value, UserString)) and len(value) == 1 and ord(value) >= -128 and ord(value) < 128), \ - "The '@(field.name)' field must of type 'str' or 'UserString' " \ + "The '@(member.name)' field must of type 'str' or 'UserString' " \ 'with a length 1 and the character ord() in [-128, 127]' -@[ elif field.type.type in [ - 'bool', - 'float32', 'float64', +@[ elif isinstance(type_, BaseString)]@ + isinstance(value, str), \ + "The '@(member.name)' field must of type '@(get_python_type(type_))'" +@[ elif isinstance(type_, BasicType) and type_.type in [ + 'boolean', + 'float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', - 'string', ]]@ - isinstance(value, @(get_python_type(field.type))), \ - "The '@(field.name)' field must of type '@(get_python_type(field.type))'" -@[ if field.type.type.startswith('int')]@ + isinstance(value, @(get_python_type(type_))), \ + "The '@(member.name)' field must of type '@(get_python_type(type_))'" +@[ if type_.type.startswith('int')]@ @{ -nbits = int(field.type.type[3:]) +nbits = int(type_.type[3:]) bound = 2**(nbits - 1) }@ assert value >= -@(bound) and value < @(bound), \ - "The '@(field.name)' field must be an integer in [@(-bound), @(bound - 1)]" -@[ elif field.type.type.startswith('uint')]@ + "The '@(member.name)' field must be an integer in [@(-bound), @(bound - 1)]" +@[ elif type_.type.startswith('uint')]@ @{ -nbits = int(field.type.type[4:]) +nbits = int(type_.type[4:]) bound = 2**nbits }@ assert value >= 0 and value < @(bound), \ - "The '@(field.name)' field must be an unsigned integer in [0, @(bound - 1)]" + "The '@(member.name)' field must be an unsigned integer in [0, @(bound - 1)]" @[ end if]@ @[ else]@ False @[ end if]@ - self._@(field.name) = value + self._@(member.name) = value @[end for]@ diff --git a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em index 8f0159f5..02033758 100644 --- a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em @@ -1,134 +1,91 @@ -// generated from rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __s.ep._c.c files -@# -@# Context: -@# - package_name -@# - message_specs (list of rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg files -@# - service_specs (list of rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv files -@# - action_specs (list of rosidl_parser.ActionSpecification) -@# Parsed specification of the .action files -@# - typesupport_impl (string identifying the typesupport used) -@# - convert_camel_case_to_lower_case_underscore (function) -@####################################################################### -@ -#include -#include -#include - +@# Included from rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em @{ -static_includes = set([ - '#include ', -]) -if message_specs: - static_includes.add('#include ') -if service_specs: - static_includes.add('#include ') -if action_specs: - static_includes.add('#include ') -}@ -@[for value in sorted(static_includes)]@ -@(value) -@[end for]@ -@{ -def strip_suffix(name): - if name.endswith('__request'): - name = name[:-9] - elif name.endswith('__response'): - name = name[:-10] - if name.endswith('__goal'): - name = name[:-6] - elif name.endswith('__result'): - name = name[:-8] - return name -includes = {} -for spec, subfolder in message_specs: - type_name = spec.base_type.type - module_name = convert_camel_case_to_lower_case_underscore(type_name) - module_name = strip_suffix(module_name) - key = '%s/%s/%s' % (spec.base_type.pkg_name, subfolder, module_name) - includes[key + '_support'] = '#include <%s__type_support.h>' % key - includes[key + '_struct'] = '#include <%s__struct.h>' % key - includes[key + '_functions'] = '#include <%s__functions.h>' % key - -for spec, subfolder in service_specs: - type_name = convert_camel_case_to_lower_case_underscore(spec.srv_name) - module_name = convert_camel_case_to_lower_case_underscore(type_name) - module_name = strip_suffix(module_name) - key = '%s/%s/%s' % (spec.pkg_name, subfolder, module_name) - includes[key] = '#include <%s.h>' % key +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +module_name = convert_camel_case_to_lower_case_underscore(message.structure.type.name) + +header_filename = module_name +if header_filename.endswith('__request'): + header_filename = header_filename[:-9] +elif header_filename.endswith('__response'): + header_filename = header_filename[:-10] +if header_filename.endswith('__goal'): + header_filename = header_filename[:-6] +elif header_filename.endswith('__result'): + header_filename = header_filename[:-8] +elif header_filename.endswith('__feedback'): + header_filename = header_filename[:-10] +if header_filename.endswith('__action'): + header_filename = header_filename[:-8] + +include_parts = message.structure.type.namespaces + [header_filename] +include_base = '/'.join(include_parts) + +header_files = [ + 'stdbool.h', + 'stdint.h', + 'rosidl_generator_c/visibility_control.h', + 'rosidl_generator_c/message_type_support_struct.h', + 'rosidl_generator_c/service_type_support_struct.h', + 'rosidl_generator_c/action_type_support_struct.h', + include_base + '__type_support.h', + include_base + '__struct.h', + include_base + '__functions.h', +] }@ -@[for v in sorted(includes.values())]@ -@(v) +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +@[ if '/' not in header_file]@ +#include <@(header_file)> +@[ else]@ +#include "@(header_file)" +@[ end if]@ @[end for]@ @ -@[for spec, subfolder in message_specs]@ @{ -pkg_name = spec.base_type.pkg_name -type_name = spec.base_type.type -module_name = convert_camel_case_to_lower_case_underscore(type_name) -msg_typename = '%s__%s__%s' % (pkg_name, subfolder, type_name) +msg_typename = '__'.join(message.structure.type.namespaces + [message.structure.type.name]) }@ -static void * @(pkg_name)__@(subfolder)__@(module_name)__create_ros_message(void) +static void * @('__'.join(message.structure.type.namespaces + [module_name]))__create_ros_message(void) { return @(msg_typename)__create(); } -static void @(pkg_name)__@(subfolder)__@(module_name)__destroy_ros_message(void * raw_ros_message) +static void @('__'.join(message.structure.type.namespaces + [module_name]))__destroy_ros_message(void * raw_ros_message) { @(msg_typename) * ros_message = (@(msg_typename) *)raw_ros_message; @(msg_typename)__destroy(ros_message); } ROSIDL_GENERATOR_C_IMPORT -bool @(pkg_name)__@(subfolder)__@(module_name)__convert_from_py(PyObject * _pymsg, void * ros_message); +bool @('__'.join(message.structure.type.namespaces + [module_name]))__convert_from_py(PyObject * _pymsg, void * ros_message); ROSIDL_GENERATOR_C_IMPORT -PyObject * @(pkg_name)__@(subfolder)__@(module_name)__convert_to_py(void * raw_ros_message); -@[end for]@ +PyObject * @('__'.join(message.structure.type.namespaces + [module_name]))__convert_to_py(void * raw_ros_message); -static PyMethodDef @(package_name)__methods[] = { - {NULL, NULL, 0, NULL} /* sentinel */ -}; - -static struct PyModuleDef @(package_name)__module = { - PyModuleDef_HEAD_INIT, - "_@(package_name)_support", - "_@(package_name)_doc", - -1, /* -1 means that the module keeps state in global variables */ - @(package_name)__methods, - NULL, - NULL, - NULL, - NULL, -}; -@ -@[for spec, subfolder in message_specs]@ -@{ -type_name = convert_camel_case_to_lower_case_underscore(spec.base_type.type) -function_names = ['create_ros_message', 'destroy_ros_message', 'convert_from_py', 'convert_to_py', 'type_support'] -}@ ROSIDL_GENERATOR_C_IMPORT const rosidl_message_type_support_t * -ROSIDL_GET_MSG_TYPE_SUPPORT(@(pkg_name), @(subfolder), @(spec.msg_name)); +ROSIDL_GET_MSG_TYPE_SUPPORT(@(', '.join(message.structure.type.namespaces + [message.structure.type.name]))); int8_t -_register_msg_type__@(subfolder)__@(type_name)(PyObject * pymodule) +_register_msg_type__@('__'.join(message.structure.type.namespaces[1:] + [module_name]))(PyObject * pymodule) { int8_t err; -@[ for function_name in function_names]@ +@{ +function_names = ['create_ros_message', 'destroy_ros_message', 'convert_from_py', 'convert_to_py', 'type_support'] +}@ +@[for function_name in function_names]@ PyObject * pyobject_@(function_name) = NULL; pyobject_@(function_name) = PyCapsule_New( @[ if function_name != 'type_support']@ - (void *)&@(pkg_name)__@(subfolder)__@(type_name)__@(function_name), + (void *)&@('__'.join(message.structure.type.namespaces + [module_name]))__@(function_name), @[ else]@ - (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(@(pkg_name), @(subfolder), @(spec.msg_name)), + (void *)ROSIDL_GET_MSG_TYPE_SUPPORT(@(', '.join(message.structure.type.namespaces + [message.structure.type.name]))), @[ end if]@ NULL, NULL); if (!pyobject_@(function_name)) { @@ -137,7 +94,7 @@ _register_msg_type__@(subfolder)__@(type_name)(PyObject * pymodule) } err = PyModule_AddObject( pymodule, - "@(function_name)_msg__@(subfolder)_@(type_name)", + "@(function_name)_msg__@('__'.join(message.structure.type.namespaces[1:] + [module_name]))", pyobject_@(function_name)); if (err) { // the created capsule needs to be decremented @@ -145,10 +102,8 @@ _register_msg_type__@(subfolder)__@(type_name)(PyObject * pymodule) // previously added objects will be removed when the module is destroyed return err; } -@[ end for]@ - return 0; -} @[end for]@ +<<<<<<< HEAD @ @[for spec, subfolder in service_specs]@ @{ @@ -264,3 +219,7 @@ type_name = convert_camel_case_to_lower_case_underscore(spec.action_name) return pymodule; } +======= + return 0; +} +>>>>>>> update rosidl_generator_py to use IDL-based extension point diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index d38897f0..71991a00 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -1,92 +1,133 @@ -// generated from rosidl_generator_py/resource/_msg_support.c.em -// generated code does not contain a copyright notice +@# Included from rosidl_generator_py/resource/_idl.py.em +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_parser.definition import Array +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import String +from rosidl_parser.definition import WString -@####################################################################### -@# EmPy template for generating __s.c files -@# -@# Context: -@# - module_name -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - convert_camel_case_to_lower_case_underscore (function) -@# - primitive_msg_type_to_c (function) -@####################################################################### -@ -#include -#include -#include +def primitive_msg_type_to_c(type_): + from rosidl_generator_c import BASIC_IDL_TYPES_TO_C + from rosidl_parser.definition import BasicType + from rosidl_parser.definition import String + if isinstance(type_, String): + return 'rosidl_generator_c__String' + assert isinstance(type_, BasicType) + return BASIC_IDL_TYPES_TO_C[type_.type] -@{ -header_filename = module_name -if header_filename.endswith('__request'): - header_filename = header_filename[:-9] -elif header_filename.endswith('__response'): - header_filename = header_filename[:-10] -if header_filename.endswith('__goal'): - header_filename = header_filename[:-6] -elif header_filename.endswith('__result'): - header_filename = header_filename[:-8] -elif header_filename.endswith('__feedback'): - header_filename = header_filename[:-10] + +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +include_base = '/'.join(include_parts) + +header_files = [ + 'Python.h', + 'stdbool.h', + 'rosidl_generator_c/visibility_control.h', + include_base + '__struct.h', + include_base + '__functions.h', +] }@ -#include <@(spec.base_type.pkg_name)/@(subfolder)/@(header_filename)__struct.h> -#include <@(spec.base_type.pkg_name)/@(subfolder)/@(header_filename)__functions.h> +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +@[ if '/' not in header_file]@ +#include <@(header_file)> +@[ else]@ +#include "@(header_file)" +@[ end if]@ +@[end for]@ @{ have_not_included_primitive_arrays = True have_not_included_string = True -nested_array_dict = {} +have_not_included_wstring = True +nested_types = set() }@ -@[for field in spec.fields]@ -@[ if field.type.is_array and have_not_included_primitive_arrays]@ -@{have_not_included_primitive_arrays = False}@ -#include -#include - -@[ end if]@ -@[ if field.type.type == 'string' and have_not_included_string]@ -@{have_not_included_string = False}@ -#include -#include +@[for member in message.structure.members]@ +@{ +type_ = member.type +if isinstance(type_, NestedType): + type_ = type_.basetype +header_files = [] +if isinstance(member.type, NestedType) and have_not_included_primitive_arrays: + have_not_included_primitive_arrays = False + header_files += [ + 'rosidl_generator_c/primitives_sequence.h', + 'rosidl_generator_c/primitives_sequence_functions.h'] +if isinstance(type_, String) and have_not_included_string: + have_not_included_string = False + header_files += [ + 'rosidl_generator_c/string.h', + 'rosidl_generator_c/string_functions.h'] +if isinstance(type_, WString) and have_not_included_wstring: + have_not_included_wstring = False + header_files += [ + 'rosidl_generator_c/u16string.h', + 'rosidl_generator_c/u16string_functions.h'] +}@ +@[if header_files]@ +@[ for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[ end for]@ -@[ end if]@ +@[end if]@ @{ -if not field.type.is_primitive_type() and field.type.is_array: - if field.type.type not in nested_array_dict: - nested_array_dict[field.type.type] = field.type.pkg_name +if isinstance(member.type, NestedType) and isinstance(member.type.basetype, NamespacedType): + nested_types.add((*member.type.basetype.namespaces, member.type.basetype.name)) }@ @[end for]@ -@[if nested_array_dict != {}]@ +@[if nested_types]@ // Nested array functions includes -@[ for key in nested_array_dict]@ -#include <@(nested_array_dict[key])/msg/@convert_camel_case_to_lower_case_underscore(key)__functions.h> +@[ for type_ in nested_types]@ +#include "@('/'.join(type_[:-1]))/@(convert_camel_case_to_lower_case_underscore(type_[-1]))__functions.h" @[ end for]@ // end nested array functions include @[end if]@ @{ -msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type) +msg_typename = '__'.join(message.structure.type.namespaces + [message.structure.type.name]) }@ @ -@[for field in spec.fields]@ -@{lowercase_field_type = convert_camel_case_to_lower_case_underscore(field.type.type)}@ -@[ if not field.type.is_primitive_type()]@ -@[ if spec.base_type.pkg_name != field.type.pkg_name]@ +@[for member in message.structure.members]@ +@{ +type_ = member.type +if isinstance(type_, NestedType): + type_ = type_.basetype +}@ +@[ if isinstance(type_, NamespacedType)]@ +@[ if type_.namespaces[0] != package_name]@ ROSIDL_GENERATOR_C_IMPORT @[ end if]@ -bool @(field.type.pkg_name)__msg__@(lowercase_field_type)__convert_from_py(PyObject * _pymsg, void * _ros_message); -@[ if spec.base_type.pkg_name != field.type.pkg_name]@ +bool @('__'.join(type_.namespaces + [type_.name]))__convert_from_py(PyObject * _pymsg, void * _ros_message); +@[ if type_.namespaces[0] != package_name]@ ROSIDL_GENERATOR_C_IMPORT @[ end if]@ -PyObject * @(field.type.pkg_name)__msg__@(lowercase_field_type)__convert_to_py(void * raw_ros_message); +PyObject * @('__'.join(type_.namespaces + [type_.name]))__convert_to_py(void * raw_ros_message); @[ end if]@ @[end for]@ +@{ +module_name = '_' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) +}@ ROSIDL_GENERATOR_C_EXPORT -bool @(spec.base_type.pkg_name)__@(subfolder)__@(module_name)__convert_from_py(PyObject * _pymsg, void * _ros_message) +bool @('__'.join(message.structure.type.namespaces + [message.structure.type.name]))__convert_from_py(PyObject * _pymsg, void * _ros_message) { @{ -full_classname = '%s.%s._%s.%s' % (spec.base_type.pkg_name, subfolder, module_name, spec.base_type.type) +full_classname = '%s._%s.%s' % ('.'.join(message.structure.type.namespaces), module_name, message.structure.type.name) }@ // check that the passed message is of the expected Python class { @@ -120,46 +161,47 @@ full_classname = '%s.%s._%s.%s' % (spec.base_type.pkg_name, subfolder, module_na full_classname_dest, @(len(full_classname))) == 0); } @(msg_typename) * ros_message = _ros_message; -@[if not spec.fields]@ - (void)ros_message; -@[end if]@ -@[for field in spec.fields]@ - { // @(field.name) - PyObject * field = PyObject_GetAttrString(_pymsg, "@(field.name)"); +@[for member in message.structure.members]@ +@{ +type_ = member.type +if isinstance(type_, NestedType): + type_ = type_.basetype +}@ + { // @(member.name) + PyObject * field = PyObject_GetAttrString(_pymsg, "@(member.name)"); if (!field) { return false; } -@[ if not field.type.is_primitive_type()]@ +@[ if isinstance(type_, NamespacedType)]@ @{ -nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type) -lowercase_field_type = convert_camel_case_to_lower_case_underscore(field.type.type) +nested_type = '__'.join(type_.namespaces + [type_.name]) }@ -@[ if field.type.is_array]@ - PyObject * seq_field = PySequence_Fast(field, "expected a sequence in '@(field.name)'"); +@[ if isinstance(member.type, NestedType)]@ + PyObject * seq_field = PySequence_Fast(field, "expected a sequence in '@(member.name)'"); if (!seq_field) { Py_DECREF(field); return false; } -@[ if field.type.array_size is None or field.type.is_upper_bound]@ +@[ if isinstance(member.type, Sequence)]@ Py_ssize_t size = PySequence_Size(field); if (-1 == size) { Py_DECREF(seq_field); Py_DECREF(field); return false; } - if (!@(nested_type)__Sequence__init(&(ros_message->@(field.name)), size)) { + if (!@(nested_type)__Sequence__init(&(ros_message->@(member.name)), size)) { PyErr_SetString(PyExc_RuntimeError, "unable to create @(nested_type)__Sequence ros_message"); Py_DECREF(seq_field); Py_DECREF(field); return false; } - @(nested_type) * dest = ros_message->@(field.name).data; + @(nested_type) * dest = ros_message->@(member.name).data; @[ else]@ - Py_ssize_t size = @(field.type.array_size); - @(nested_type) * dest = ros_message->@(field.name); + Py_ssize_t size = @(member.type.size); + @(nested_type) * dest = ros_message->@(member.name); @[ end if]@ for (Py_ssize_t i = 0; i < size; ++i) { - if (!@(field.type.pkg_name)__msg__@(lowercase_field_type)__convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) { + if (!@('__'.join(type_.namespaces + [type_.name]))__convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) { Py_DECREF(seq_field); Py_DECREF(field); return false; @@ -167,48 +209,43 @@ lowercase_field_type = convert_camel_case_to_lower_case_underscore(field.type.ty } Py_DECREF(seq_field); @[ else]@ - if (!@(field.type.pkg_name)__msg__@(lowercase_field_type)__convert_from_py(field, &ros_message->@(field.name))) { + if (!@('__'.join(type_.namespaces + [type_.name]))__convert_from_py(field, &ros_message->@(member.name))) { Py_DECREF(field); return false; } @[ end if]@ -@[ elif field.type.is_array]@ - PyObject * seq_field = PySequence_Fast(field, "expected a sequence in '@(field.name)'"); +@[ elif isinstance(member.type, NestedType)]@ + PyObject * seq_field = PySequence_Fast(field, "expected a sequence in '@(member.name)'"); if (!seq_field) { Py_DECREF(field); return false; } -@[ if field.type.array_size is None or field.type.is_upper_bound]@ +@[ if isinstance(member.type, Sequence)]@ Py_ssize_t size = PySequence_Size(field); if (-1 == size) { Py_DECREF(seq_field); Py_DECREF(field); return false; } -@[ if field.type.type == 'string']@ - if (!rosidl_generator_c__String__Sequence__init(&(ros_message->@(field.name)), size)) { +@[ if isinstance(member.type.basetype, String)]@ + if (!rosidl_generator_c__String__Sequence__init(&(ros_message->@(member.name)), size)) { PyErr_SetString(PyExc_RuntimeError, "unable to create String__Sequence ros_message"); Py_DECREF(seq_field); Py_DECREF(field); return false; } @[ else]@ -@{ -type_ = field.type.type -if type_ == 'char': - type_ = 'uint8' -}@ - if (!rosidl_generator_c__@(type_)__Sequence__init(&(ros_message->@(field.name)), size)) { - PyErr_SetString(PyExc_RuntimeError, "unable to create @(type_)__Sequence ros_message"); + if (!rosidl_generator_c__@(member.type.basetype.type)__Sequence__init(&(ros_message->@(member.name)), size)) { + PyErr_SetString(PyExc_RuntimeError, "unable to create @(member.type.basetype.type)__Sequence ros_message"); Py_DECREF(seq_field); Py_DECREF(field); return false; } @[ end if]@ - @primitive_msg_type_to_c(field.type.type) * dest = ros_message->@(field.name).data; + @primitive_msg_type_to_c(member.type.basetype) * dest = ros_message->@(member.name).data; @[ else]@ - Py_ssize_t size = @(field.type.array_size); - @primitive_msg_type_to_c(field.type.type) * dest = ros_message->@(field.name); + Py_ssize_t size = @(member.type.size); + @primitive_msg_type_to_c(member.type.basetype) * dest = ros_message->@(member.name); @[ end if]@ for (Py_ssize_t i = 0; i < size; ++i) { PyObject * item = PySequence_Fast_GET_ITEM(seq_field, i); @@ -217,7 +254,7 @@ if type_ == 'char': Py_DECREF(field); return false; } -@[ if field.type.type == 'char']@ +@[ if isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'char']@ assert(PyUnicode_Check(item)); PyObject * encoded_item = PyUnicode_AsASCIIString(item); if (!encoded_item) { @@ -225,12 +262,12 @@ if type_ == 'char': Py_DECREF(field); return false; } - @primitive_msg_type_to_c(field.type.type) tmp = PyBytes_AS_STRING(encoded_item)[0]; + @primitive_msg_type_to_c(member.type.basetype) tmp = PyBytes_AS_STRING(encoded_item)[0]; Py_DECREF(encoded_item); -@[ elif field.type.type == 'byte']@ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'octet']@ assert(PyBytes_Check(item)); - @primitive_msg_type_to_c(field.type.type) tmp = PyBytes_AS_STRING(item)[0]; -@[ elif field.type.type == 'string']@ + @primitive_msg_type_to_c(member.type.basetype) tmp = PyBytes_AS_STRING(item)[0]; +@[ elif isinstance(member.type.basetype, String)]@ assert(PyUnicode_Check(item)); PyObject * encoded_item = PyUnicode_AsASCIIString(item); if (!encoded_item) { @@ -240,101 +277,101 @@ if type_ == 'char': } rosidl_generator_c__String__assign(&dest[i], PyBytes_AS_STRING(encoded_item)); Py_DECREF(encoded_item); -@[ elif field.type.type == 'bool']@ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'boolean']@ assert(PyBool_Check(item)); - @primitive_msg_type_to_c(field.type.type) tmp = (item == Py_True); -@[ elif field.type.type in ['float32', 'float64']]@ + @primitive_msg_type_to_c(member.type.basetype) tmp = (item == Py_True); +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type in ('float', 'double')]@ assert(PyFloat_Check(item)); -@[ if field.type.type == 'float32']@ - @primitive_msg_type_to_c(field.type.type) tmp = (float)PyFloat_AS_DOUBLE(item); +@[ if member.type.basetype.type == 'float']@ + @primitive_msg_type_to_c(member.type.basetype) tmp = (float)PyFloat_AS_DOUBLE(item); @[ else]@ - @primitive_msg_type_to_c(field.type.type) tmp = PyFloat_AS_DOUBLE(item); + @primitive_msg_type_to_c(member.type.basetype) tmp = PyFloat_AS_DOUBLE(item); @[ end if]@ -@[ elif field.type.type in [ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type in ( 'int8', 'int16', 'int32', - ]]@ + )]@ assert(PyLong_Check(item)); - @primitive_msg_type_to_c(field.type.type) tmp = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(item); -@[ elif field.type.type in [ + @primitive_msg_type_to_c(member.type.basetype) tmp = (@(primitive_msg_type_to_c(member.type.basetype)))PyLong_AsLong(item); +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type in ( 'uint8', 'uint16', 'uint32', - ]]@ + )]@ assert(PyLong_Check(item)); -@[ if field.type.type == 'uint32']@ - @primitive_msg_type_to_c(field.type.type) tmp = PyLong_AsUnsignedLong(item); +@[ if isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'uint32']@ + @primitive_msg_type_to_c(member.type.basetype) tmp = PyLong_AsUnsignedLong(item); @[ else]@ - @primitive_msg_type_to_c(field.type.type) tmp = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(item); + @primitive_msg_type_to_c(member.type.basetype) tmp = (@(primitive_msg_type_to_c(member.type.basetype)))PyLong_AsUnsignedLong(item); @[ end if] -@[ elif field.type.type == 'int64']@ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'int64']@ assert(PyLong_Check(item)); - @primitive_msg_type_to_c(field.type.type) tmp = PyLong_AsLongLong(item); -@[ elif field.type.type == 'uint64']@ + @primitive_msg_type_to_c(member.type.basetype) tmp = PyLong_AsLongLong(item); +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'uint64']@ assert(PyLong_Check(item)); - @primitive_msg_type_to_c(field.type.type) tmp = PyLong_AsUnsignedLongLong(item); + @primitive_msg_type_to_c(member.type.basetype) tmp = PyLong_AsUnsignedLongLong(item); @[ end if]@ -@[ if field.type.type != 'string']@ - memcpy(&dest[i], &tmp, sizeof(@primitive_msg_type_to_c(field.type.type))); +@[ if isinstance(member.type.basetype, BasicType)]@ + memcpy(&dest[i], &tmp, sizeof(@primitive_msg_type_to_c(member.type.basetype))); @[ end if]@ } Py_DECREF(seq_field); -@[ elif field.type.type == 'char']@ +@[ elif isinstance(member.type, BasicType) and member.type.type == 'char']@ assert(PyUnicode_Check(field)); PyObject * encoded_field = PyUnicode_AsASCIIString(field); if (!encoded_field) { Py_DECREF(field); return false; } - ros_message->@(field.name) = PyBytes_AS_STRING(encoded_field)[0]; + ros_message->@(member.name) = PyBytes_AS_STRING(encoded_field)[0]; Py_DECREF(encoded_field); -@[ elif field.type.type == 'byte']@ +@[ elif isinstance(member.type, BasicType) and member.type.type == 'octet']@ assert(PyBytes_Check(field)); - ros_message->@(field.name) = PyBytes_AS_STRING(field)[0]; -@[ elif field.type.type == 'string']@ + ros_message->@(member.name) = PyBytes_AS_STRING(field)[0]; +@[ elif isinstance(member.type, String)]@ assert(PyUnicode_Check(field)); PyObject * encoded_field = PyUnicode_AsASCIIString(field); if (!encoded_field) { Py_DECREF(field); return false; } - rosidl_generator_c__String__assign(&ros_message->@(field.name), PyBytes_AS_STRING(encoded_field)); + rosidl_generator_c__String__assign(&ros_message->@(member.name), PyBytes_AS_STRING(encoded_field)); Py_DECREF(encoded_field); -@[ elif field.type.type == 'bool']@ +@[ elif isinstance(member.type, BasicType) and member.type.type == 'boolean']@ assert(PyBool_Check(field)); - ros_message->@(field.name) = (Py_True == field); -@[ elif field.type.type in ['float32', 'float64']]@ + ros_message->@(member.name) = (Py_True == field); +@[ elif isinstance(member.type, BasicType) and member.type.type in ('float', 'double')]@ assert(PyFloat_Check(field)); -@[ if field.type.type == 'float32']@ - ros_message->@(field.name) = (float)PyFloat_AS_DOUBLE(field); +@[ if member.type.type == 'float']@ + ros_message->@(member.name) = (float)PyFloat_AS_DOUBLE(field); @[ else]@ - ros_message->@(field.name) = PyFloat_AS_DOUBLE(field); + ros_message->@(member.name) = PyFloat_AS_DOUBLE(field); @[ end if]@ -@[ elif field.type.type in [ +@[ elif isinstance(member.type, BasicType) and member.type.type in ( 'int8', 'int16', 'int32', - ]]@ + )]@ assert(PyLong_Check(field)); - ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(field); -@[ elif field.type.type in [ + ros_message->@(member.name) = (@(primitive_msg_type_to_c(member.type)))PyLong_AsLong(field); +@[ elif isinstance(member.type, BasicType) and member.type.type in ( 'uint8', 'uint16', 'uint32', - ]]@ + )]@ assert(PyLong_Check(field)); -@[ if field.type.type == 'uint32']@ - ros_message->@(field.name) = PyLong_AsUnsignedLong(field); +@[ if member.type.type == 'uint32']@ + ros_message->@(member.name) = PyLong_AsUnsignedLong(field); @[ else]@ - ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(field); + ros_message->@(member.name) = (@(primitive_msg_type_to_c(member.type)))PyLong_AsUnsignedLong(field); @[ end if]@ -@[ elif field.type.type == 'int64']@ +@[ elif isinstance(member.type, BasicType) and member.type.type == 'int64']@ assert(PyLong_Check(field)); - ros_message->@(field.name) = PyLong_AsLongLong(field); -@[ elif field.type.type == 'uint64']@ + ros_message->@(member.name) = PyLong_AsLongLong(field); +@[ elif isinstance(member.type, BasicType) and member.type.type == 'uint64']@ assert(PyLong_Check(field)); - ros_message->@(field.name) = PyLong_AsUnsignedLongLong(field); + ros_message->@(member.name) = PyLong_AsUnsignedLongLong(field); @[ else]@ assert(false); @[ end if]@ @@ -346,14 +383,14 @@ if type_ == 'char': } ROSIDL_GENERATOR_C_EXPORT -PyObject * @(spec.base_type.pkg_name)__@(subfolder)__@(module_name)__convert_to_py(void * raw_ros_message) +PyObject * @('__'.join(message.structure.type.namespaces + [message.structure.type.name]))__convert_to_py(void * raw_ros_message) { - /* NOTE(esteve): Call constructor of @(spec.base_type.type) */ + /* NOTE(esteve): Call constructor of @(message.structure.type.name) */ PyObject * _pymessage = NULL; { - PyObject * pymessage_module = PyImport_ImportModule("@(spec.base_type.pkg_name).@(subfolder)._@(module_name)"); + PyObject * pymessage_module = PyImport_ImportModule("@('.'.join(message.structure.type.namespaces))._@(module_name)"); assert(pymessage_module); - PyObject * pymessage_class = PyObject_GetAttrString(pymessage_module, "@(spec.base_type.type)"); + PyObject * pymessage_class = PyObject_GetAttrString(pymessage_module, "@(message.structure.type.name)"); assert(pymessage_class); Py_DECREF(pymessage_module); _pymessage = PyObject_CallObject(pymessage_class, NULL); @@ -363,22 +400,23 @@ PyObject * @(spec.base_type.pkg_name)__@(subfolder)__@(module_name)__convert_to_ } } @(msg_typename) * ros_message = (@(msg_typename) *)raw_ros_message; -@[if not spec.fields]@ - (void)ros_message; -@[end if]@ -@[for field in spec.fields]@ - { // @(field.name) +@[for member in message.structure.members]@ +@{ +type_ = member.type +if isinstance(type_, NestedType): + type_ = type_.basetype +}@ + { // @(member.name) PyObject * field = NULL; -@[ if not field.type.is_primitive_type()]@ +@[ if isinstance(type_, NamespacedType)]@ @{ -nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type) -lowercase_field_type = convert_camel_case_to_lower_case_underscore(field.type.type) +nested_type = '__'.join(type_.namespaces + [type_.name]) }@ -@[ if field.type.is_array]@ -@[ if field.type.array_size is None or field.type.is_upper_bound]@ - size_t size = ros_message->@(field.name).size; +@[ if isinstance(member.type, NestedType)]@ +@[ if isinstance(member.type, Sequence)]@ + size_t size = ros_message->@(member.name).size; @[ else]@ - size_t size = @(field.type.array_size); + size_t size = @(member.type.size); @[ end if]@ field = PyList_New(size); if (!field) { @@ -386,12 +424,12 @@ lowercase_field_type = convert_camel_case_to_lower_case_underscore(field.type.ty } @(nested_type) * item; for (size_t i = 0; i < size; ++i) { -@[ if field.type.array_size is None or field.type.is_upper_bound]@ - item = &(ros_message->@(field.name).data[i]); +@[ if isinstance(member.type, Sequence)]@ + item = &(ros_message->@(member.name).data[i]); @[ else]@ - item = &(ros_message->@(field.name)[i]); + item = &(ros_message->@(member.name)[i]); @[ end if]@ - PyObject * pyitem = @(field.type.pkg_name)__msg__@(lowercase_field_type)__convert_to_py(item); + PyObject * pyitem = @('__'.join(type_.namespaces + [type_.name]))__convert_to_py(item); if (!pyitem) { Py_DECREF(field); return NULL; @@ -402,33 +440,33 @@ lowercase_field_type = convert_camel_case_to_lower_case_underscore(field.type.ty } assert(PySequence_Check(field)); @[ else]@ - field = @(field.type.pkg_name)__msg__@(lowercase_field_type)__convert_to_py(&ros_message->@(field.name)); + field = @('__'.join(type_.namespaces + [type_.name]))__convert_to_py(&ros_message->@(member.name)); if (!field) { return NULL; } @[ end if]@ -@[ elif field.type.is_array]@ -@[ if field.type.array_size is None or field.type.is_upper_bound]@ - size_t size = ros_message->@(field.name).size; - @primitive_msg_type_to_c(field.type.type) * src = ros_message->@(field.name).data; +@[ elif isinstance(member.type, NestedType)]@ +@[ if isinstance(member.type, Sequence)]@ + size_t size = ros_message->@(member.name).size; + @primitive_msg_type_to_c(member.type.basetype) * src = ros_message->@(member.name).data; @[ else]@ - size_t size = @(field.type.array_size); - @primitive_msg_type_to_c(field.type.type) * src = ros_message->@(field.name); + size_t size = @(member.type.size); + @primitive_msg_type_to_c(member.type.basetype) * src = ros_message->@(member.name); @[ end if]@ field = PyList_New(size); if (!field) { return NULL; } for (size_t i = 0; i < size; ++i) { -@[ if field.type.type == 'char']@ +@[ if isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'char']@ int rc = PyList_SetItem(field, i, Py_BuildValue("C", src[i])); (void)rc; assert(rc == 0); -@[ elif field.type.type == 'byte']@ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'octet']@ int rc = PyList_SetItem(field, i, PyBytes_FromStringAndSize((const char *)&src[i], 1)); (void)rc; assert(rc == 0); -@[ elif field.type.type == 'string']@ +@[ elif isinstance(member.type.basetype, String)]@ PyObject * decoded_item = PyUnicode_DecodeASCII(src[i].data, strlen(src[i].data), "strict"); if (!decoded_item) { return NULL; @@ -436,86 +474,86 @@ lowercase_field_type = convert_camel_case_to_lower_case_underscore(field.type.ty int rc = PyList_SetItem(field, i, decoded_item); (void)rc; assert(rc == 0); -@[ elif field.type.type == 'bool']@ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'boolean']@ @# using PyBool_FromLong because PyList_SetItem will steal ownership of the passed item int rc = PyList_SetItem(field, i, PyBool_FromLong(src[i] ? 1 : 0)); (void)rc; assert(rc == 0); -@[ elif field.type.type in ['float32', 'float64']]@ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type in ('float', 'double')]@ int rc = PyList_SetItem(field, i, PyFloat_FromDouble(src[i])); (void)rc; assert(rc == 0); -@[ elif field.type.type in [ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type in ( 'int8', 'int16', 'int32', - ]]@ + )]@ int rc = PyList_SetItem(field, i, PyLong_FromLong(src[i])); (void)rc; assert(rc == 0); -@[ elif field.type.type in [ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type in ( 'uint8', 'uint16', 'uint32', - ]]@ + )]@ int rc = PyList_SetItem(field, i, PyLong_FromUnsignedLong(src[i])); (void)rc; assert(rc == 0); -@[ elif field.type.type == 'int64']@ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'int64']@ int rc = PyList_SetItem(field, i, PyLong_FromLongLong(src[i])); (void)rc; assert(rc == 0); -@[ elif field.type.type == 'uint64']@ +@[ elif isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'uint64']@ int rc = PyList_SetItem(field, i, PyLong_FromUnsignedLongLong(src[i])); (void)rc; assert(rc == 0); @[ end if]@ } assert(PySequence_Check(field)); -@[ elif field.type.type == 'char']@ - field = Py_BuildValue("C", ros_message->@(field.name)); +@[ elif isinstance(member.type, BasicType) and member.type.type == 'char']@ + field = Py_BuildValue("C", ros_message->@(member.name)); if (!field) { return NULL; } -@[ elif field.type.type == 'byte']@ - field = PyBytes_FromStringAndSize((const char *)&ros_message->@(field.name), 1); +@[ elif isinstance(member.type, BasicType) and member.type.type == 'octet']@ + field = PyBytes_FromStringAndSize((const char *)&ros_message->@(member.name), 1); if (!field) { return NULL; } -@[ elif field.type.type == 'string']@ +@[ elif isinstance(member.type, String)]@ field = PyUnicode_DecodeASCII( - ros_message->@(field.name).data, - strlen(ros_message->@(field.name).data), + ros_message->@(member.name).data, + strlen(ros_message->@(member.name).data), "strict"); if (!field) { return NULL; } -@[ elif field.type.type == 'bool']@ +@[ elif isinstance(member.type, BasicType) and member.type.type == 'boolean']@ @# using PyBool_FromLong allows treating the variable uniformly by calling Py_DECREF on it later - field = PyBool_FromLong(ros_message->@(field.name) ? 1 : 0); -@[ elif field.type.type in ['float32', 'float64']]@ - field = PyFloat_FromDouble(ros_message->@(field.name)); -@[ elif field.type.type in [ + field = PyBool_FromLong(ros_message->@(member.name) ? 1 : 0); +@[ elif isinstance(member.type, BasicType) and member.type.type in ('float', 'double')]@ + field = PyFloat_FromDouble(ros_message->@(member.name)); +@[ elif isinstance(member.type, BasicType) and member.type.type in ( 'int8', 'int16', 'int32', - ]]@ - field = PyLong_FromLong(ros_message->@(field.name)); -@[ elif field.type.type in [ + )]@ + field = PyLong_FromLong(ros_message->@(member.name)); +@[ elif isinstance(member.type, BasicType) and member.type.type in ( 'uint8', 'uint16', 'uint32', - ]]@ - field = PyLong_FromUnsignedLong(ros_message->@(field.name)); -@[ elif field.type.type == 'int64']@ - field = PyLong_FromLongLong(ros_message->@(field.name)); -@[ elif field.type.type == 'uint64']@ - field = PyLong_FromUnsignedLongLong(ros_message->@(field.name)); + )]@ + field = PyLong_FromUnsignedLong(ros_message->@(member.name)); +@[ elif isinstance(member.type, BasicType) and member.type.type == 'int64']@ + field = PyLong_FromLongLong(ros_message->@(member.name)); +@[ elif isinstance(member.type, BasicType) and member.type.type == 'uint64']@ + field = PyLong_FromUnsignedLongLong(ros_message->@(member.name)); @[ else]@ assert(false); @[ end if]@ { - int rc = PyObject_SetAttrString(_pymessage, "@(field.name)", field); + int rc = PyObject_SetAttrString(_pymessage, "@(member.name)", field); Py_DECREF(field); if (rc) { return NULL; diff --git a/rosidl_generator_py/resource/_srv.py.em b/rosidl_generator_py/resource/_srv.py.em index 8f188140..89fefe87 100644 --- a/rosidl_generator_py/resource/_srv.py.em +++ b/rosidl_generator_py/resource/_srv.py.em @@ -1,23 +1,22 @@ -# generated from rosidl_generator_py/resource/_srv.py.em -# generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating _.py files -@# -@# Context: -@# - module_name -@# - package_name -@# - spec (rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv file -@# - convert_camel_case_to_lower_case_underscore (function) -@####################################################################### -@ -import logging -import traceback - - -class Metaclass(type): - """Metaclass of message '@(spec.srv_name)'.""" +@# Included from rosidl_generator_py/resource/_idl.py.em +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore + +module_name = '_' + convert_camel_case_to_lower_case_underscore(service.structure_type.name) + +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=service.request_message) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=service.response_message) +}@ + + +class Metaclass_@(service.structure_type.name)(type): + """Metaclass of message '@(service.structure_type.name)'.""" _TYPE_SUPPORT = None @@ -27,23 +26,24 @@ class Metaclass(type): from rosidl_generator_py import import_type_support module = import_type_support('@(package_name)') except ImportError: - logger = logging.getLogger('rosidl_generator_py.@(spec.srv_name)') + import logging + import traceback + logger = logging.getLogger('@('.'join(service.structure_type.namespaces + [service.structure_type.name]))') logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: cls._TYPE_SUPPORT = module.type_support_srv__@(subfolder)_@(module_name) -@{ -srv_name = '_' + convert_camel_case_to_lower_case_underscore(spec.srv_name) -for field_name in [srv_name + '__request', srv_name + '__response']: - print('%sfrom %s.%s import %s' % (' ' * 4 * 3, package_name, subfolder, field_name)) - print('%sif %s.Metaclass._TYPE_SUPPORT is None:' % (' ' * 4 * 3, field_name)) - print('%s%s.Metaclass.__import_type_support__()' % (' ' * 4 * 4, field_name)) -}@ + + from @('.'.join(service.structure_type.namespaces[:-1])) import @(module_name) + if @(module_name).Metaclass_@(service.request_message.structure.type.name)._TYPE_SUPPORT is None: + @(module_name).Metaclass_@(service.request_message.structure.type.name).__import_type_support__() + if @(module_name).Metaclass_@(service.response_message.structure.type.name)._TYPE_SUPPORT is None: + @(module_name).Metaclass_@(service.response_message.structure.type.name).__import_type_support__() -class @(spec.srv_name)(metaclass=Metaclass): - from @(package_name).@(subfolder)._@convert_camel_case_to_lower_case_underscore(spec.srv_name)__request import @(spec.srv_name)_Request as Request - from @(package_name).@(subfolder)._@convert_camel_case_to_lower_case_underscore(spec.srv_name)__response import @(spec.srv_name)_Response as Response +class @(service.structure_type.name)(metaclass=Metaclass_@(service.structure_type.name)): + from @('.'.join(service.structure_type.namespaces)).@(module_name) import @(service.request_message.structure.type.name) as Request + from @('.'.join(service.structure_type.namespaces)).@(module_name) import @(service.response_message.structure.type.name) as Response def __init__(self): raise NotImplementedError('Service classes can not be instantiated') diff --git a/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em new file mode 100644 index 00000000..0dfb14fa --- /dev/null +++ b/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em @@ -0,0 +1,49 @@ +@# Included from rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, message=service.request_message, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, message=service.response_message, + typesupport_impl=typesupport_impl, include_directives=include_directives) +}@ +@ +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +type_name = convert_camel_case_to_lower_case_underscore(service.structure_type.name) +function_name = 'type_support' +}@ + +ROSIDL_GENERATOR_C_IMPORT +const rosidl_service_type_support_t * +ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, @(', '.join(service.structure_type.namespaces + [service.structure_type.name])))(); + +int8_t +_register_srv_type__@('__'.join(service.structure_type.namespaces[1:] + [type_name]))(PyObject * pymodule) +{ + int8_t err; + PyObject * pyobject_@(function_name) = NULL; + pyobject_@(function_name) = PyCapsule_New( + (void *)ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, @(', '.join(service.structure_type.namespaces + [service.structure_type.name])))(), + NULL, NULL); + if (!pyobject_@(function_name)) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "@(function_name)_srv__@('_'.join(service.structure_type.namespaces[1:] + [type_name]))", + pyobject_@(function_name)); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_@(function_name)); + // previously added objects will be removed when the module is destroyed + return err; + } + return 0; +} diff --git a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py index 318fa98f..f1a712a8 100644 --- a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py +++ b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Open Source Robotics Foundation, Inc. +# Copyright 2014-2018 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. @@ -12,168 +12,83 @@ # See the License for the specific language governing permissions and # limitations under the License. -from collections import defaultdict +from ast import literal_eval import os -import re +import pathlib from rosidl_cmake import convert_camel_case_to_lower_case_underscore from rosidl_cmake import expand_template +from rosidl_cmake import generate_files from rosidl_cmake import get_newest_modification_time from rosidl_cmake import read_generator_arguments -from rosidl_generator_c import primitive_msg_type_to_c -from rosidl_parser import parse_action_file -from rosidl_parser import parse_message_file -from rosidl_parser import parse_service_file - - -def _primitive_msg_type_to_c(type_): - msg_type_to_c = { - 'bool': 'bool', - 'byte': 'uint8_t', - 'char': 'uint8_t', - 'float32': 'float', - 'float64': 'double', - 'uint8': 'uint8_t', - 'int8': 'int8_t', - 'uint16': 'uint16_t', - 'int16': 'int16_t', - 'uint32': 'uint32_t', - 'int32': 'int32_t', - 'uint64': 'uint64_t', - 'int64': 'int64_t', - 'string': 'rosidl_generator_c__String', - } - return msg_type_to_c[type_] +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import IdlContent +from rosidl_parser.definition import IdlLocator +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_parser.definition import String +from rosidl_parser.parser import parse_idl_file def generate_py(generator_arguments_file, typesupport_impls): + mapping = { + '_idl.py.em': '_%s.py', + '_idl_support.c.em': '_%s_s.c', + } + generate_files(generator_arguments_file, mapping) + args = read_generator_arguments(generator_arguments_file) + package_name = args['package_name'] + + # expand init modules for each directory + modules = {} + idl_content = IdlContent() + for idl_tuple in args.get('idl_tuples', []): + idl_parts = idl_tuple.rsplit(':', 1) + assert len(idl_parts) == 2 + + idl_rel_path = pathlib.Path(idl_parts[1]) + idl_stems = modules.setdefault(str(idl_rel_path.parent), set()) + idl_stems.add(idl_rel_path.stem) + locator = IdlLocator(*idl_parts) + idl_file = parse_idl_file(locator) + idl_content.elements += idl_file.content.elements + + for subfolder in modules.keys(): + with open(os.path.join(args['output_dir'], subfolder, '__init__.py'), 'w') as f: + for idl_stem in sorted(modules[subfolder]): + module_name = '_' + \ + convert_camel_case_to_lower_case_underscore(idl_stem) + f.write( + 'from {package_name}.{subfolder}.{module_name} import ' + '{idl_stem} # noqa: F401\n'.format_map(locals())) + + # expand templates per available typesupport implementation template_dir = args['template_dir'] type_support_impl_by_filename = { '_%s_s.ep.{0}.c'.format(impl): impl for impl in typesupport_impls } - mapping_msgs = { - os.path.join(template_dir, '_msg.py.em'): ['_%s.py'], - os.path.join(template_dir, '_msg_support.c.em'): ['_%s_s.c'], - } mapping_msg_pkg_extension = { - os.path.join(template_dir, '_msg_pkg_typesupport_entry_point.c.em'): + os.path.join(template_dir, '_idl_pkg_typesupport_entry_point.c.em'): type_support_impl_by_filename.keys(), } - mapping_srvs = { - os.path.join(template_dir, '_srv.py.em'): ['_%s.py'], - } - - mapping_actions = { - os.path.join(template_dir, '_action.py.em'): ['_%s.py'], - } - - for template_file in mapping_msgs.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file for template_file in mapping_msg_pkg_extension.keys(): assert os.path.exists(template_file), 'Could not find template: ' + template_file - for template_file in mapping_srvs.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - for template_file in mapping_actions.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - functions = { - 'constant_value_to_py': constant_value_to_py, - 'get_python_type': get_python_type, - 'primitive_msg_type_to_c': _primitive_msg_type_to_c, - 'value_to_py': value_to_py, - 'convert_camel_case_to_lower_case_underscore': convert_camel_case_to_lower_case_underscore, - } latest_target_timestamp = get_newest_modification_time(args['target_dependencies']) - modules = defaultdict(list) - message_specs = [] - service_specs = [] - action_specs = [] - for ros_interface_file in args['ros_interface_files']: - extension = os.path.splitext(ros_interface_file)[1] - subfolder = os.path.basename(os.path.dirname(ros_interface_file)) - if extension == '.msg': - spec = parse_message_file(args['package_name'], ros_interface_file) - message_specs.append((spec, subfolder)) - mapping = mapping_msgs - type_name = spec.base_type.type - elif extension == '.srv': - spec = parse_service_file(args['package_name'], ros_interface_file) - service_specs.append((spec, subfolder)) - mapping = mapping_srvs - type_name = spec.srv_name - elif extension == '.action': - spec = parse_action_file(args['package_name'], ros_interface_file) - action_specs.append((spec, subfolder)) - mapping = mapping_actions - type_name = spec.action_name - else: - continue - - module_name = convert_camel_case_to_lower_case_underscore(type_name) - modules[subfolder].append((module_name, type_name)) - for template_file, generated_filenames in mapping.items(): - for generated_filename in generated_filenames: - data = { - 'module_name': module_name, - 'package_name': args['package_name'], - 'spec': spec, 'subfolder': subfolder, - } - data.update(functions) - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % module_name) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - - for subfolder in modules.keys(): - import_list = {} - for module_name, type_ in modules[subfolder]: - if (subfolder == 'srv' or subfolder == 'action') and \ - (type_.endswith('Request') or type_.endswith('Response')): - continue - import_list['%s # noqa\n' % type_] = 'from %s.%s._%s import %s # noqa: I100\n' % \ - (args['package_name'], subfolder, module_name, type_) - - path_to_module = os.path.join(args['output_dir'], subfolder, '__init__.py') - - content = '' - if os.path.isfile(path_to_module): - with open(path_to_module, 'r') as f: - content = f.read() - with open(path_to_module, 'w') as f: - block_name = args['package_name'] - if action_specs: - block_name += '_action' - content = re.sub( - r'# BEGIN %s$.*^# END %s' % (block_name, block_name), - '', content, 0, re.M | re.S - ) - content = re.sub(r'^\s*$', '', content, 0, re.M) - content = ''.join( - ['# BEGIN %s\n' % block_name] + - sorted(import_list.values()) + # import_line - sorted(import_list.keys()) + # noqa_line - ['# END %s\n' % block_name] - ) + content - f.write(content) - for template_file, generated_filenames in mapping_msg_pkg_extension.items(): for generated_filename in generated_filenames: package_name = args['package_name'] if action_specs: package_name += '_action' data = { - 'package_name': package_name, - 'action_specs': action_specs, - 'message_specs': message_specs, - 'service_specs': service_specs, + 'package_name': args['package_name'], + 'content': idl_content, 'typesupport_impl': type_support_impl_by_filename.get(generated_filename, ''), } - data.update(functions) generated_file = os.path.join( args['output_dir'], generated_filename % package_name ) @@ -185,15 +100,14 @@ def generate_py(generator_arguments_file, typesupport_impls): def value_to_py(type_, value, array_as_tuple=False): - assert type_.is_primitive_type() assert value is not None - if not type_.is_array: + if not isinstance(type_, NestedType): return primitive_value_to_py(type_, value) py_values = [] - for single_value in value: - py_value = primitive_value_to_py(type_, single_value) + for single_value in literal_eval(value): + py_value = primitive_value_to_py(type_.basetype, single_value) py_values.append(py_value) if array_as_tuple: return '(%s)' % ', '.join(py_values) @@ -202,59 +116,61 @@ def value_to_py(type_, value, array_as_tuple=False): def primitive_value_to_py(type_, value): - assert type_.is_primitive_type() assert value is not None - if type_.type == 'bool': + if isinstance(type_, String): + return "'%s'" % escape_string(value) + + assert isinstance(type_, BasicType) + + if type_.type == 'boolean': return 'True' if value else 'False' - if type_.type in [ + if type_.type in ( 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', - ]: + ): return str(value) if type_.type == 'char': return repr('%c' % value) - if type_.type == 'byte': + if type_.type == 'octet': return repr(bytes([value])) - if type_.type in ['float32', 'float64']: + if type_.type in ('float', 'double'): return '%s' % value - if type_.type == 'string': - return "'%s'" % escape_string(value) - assert False, "unknown primitive type '%s'" % type_.type def constant_value_to_py(type_, value): assert value is not None - if type_ == 'bool': - return 'True' if value else 'False' + if isinstance(type_, BasicType): + if type_.type == 'bool': + return 'True' if value else 'False' - if type_ in [ - 'int8', 'uint8', - 'int16', 'uint16', - 'int32', 'uint32', - 'int64', 'uint64', - ]: - return str(value) + if type_.type in ( + 'int8', 'uint8', + 'int16', 'uint16', + 'int32', 'uint32', + 'int64', 'uint64', + ): + return str(value) - if type_ == 'char': - return repr('%c' % value) + if type_.type == 'char': + return repr('%c' % value) - if type_ == 'byte': - return repr(bytes([value])) + if type_.type == 'octet': + return repr(bytes([value])) - if type_ in ['float32', 'float64']: - return '%s' % value + if type_.type in ('float', 'double'): + return '%s' % value - if type_ == 'string': + if isinstance(type_, String): return "'%s'" % escape_string(value) assert False, "unknown constant type '%s'" % type_ @@ -267,37 +183,41 @@ def escape_string(s): def get_python_type(type_): - if not type_.is_primitive_type(): - return type_.type + if isinstance(type_, NamespacedType): + return type_.name - if type_.string_upper_bound: + if isinstance(type_, String): return 'str' - if type_.is_array: - if type_.type == 'byte': + if isinstance(type_, NestedType): + if isinstance(type_.basetype, BasicType) and type_.basetype.type == 'octet': return 'bytes' - if type_.type == 'char': + if isinstance(type_.basetype, BasicType) and type_.basetype.type in ('char', 'wchar'): return 'str' - if type_.type == 'bool': + if isinstance(type_, BasicType) and type_.type == 'boolean': return 'bool' - if type_.type == 'byte': + if isinstance(type_, BasicType) and type_.type == 'octet': return 'bytes' - if type_.type in [ + if isinstance(type_, BasicType) and type_.type in ( 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', - ]: + ): return 'int' - if type_.type in ['float32', 'float64']: + if isinstance(type_, BasicType) and type_.type in ( + 'float', 'double', + ): return 'float' - if type_.type in ['char', 'string']: + if isinstance(type_, BasicType) and type_.type in ( + 'char', 'wchar', + ): return 'str' assert False, "unknown type '%s'" % type_ diff --git a/rosidl_generator_py/test/test_interfaces.py b/rosidl_generator_py/test/test_interfaces.py index 23e961e5..4ef4b859 100644 --- a/rosidl_generator_py/test/test_interfaces.py +++ b/rosidl_generator_py/test/test_interfaces.py @@ -95,7 +95,7 @@ def test_constants(): assert 123 == Constants.X assert -123 == Constants.Y assert 'foo' == Constants.FOO - assert '\x7F' == Constants.TOTO + assert 127 == Constants.TOTO assert b'0' == Constants.TATA with pytest.raises(AttributeError): @@ -132,7 +132,7 @@ def test_default_values(): assert [5, 23] == c.UP_TO_THREE_INT32_VALUES_WITH_DEFAULT_VALUES__DEFAULT - assert '\x01' == c.CHAR_VALUE__DEFAULT + assert 1 == c.CHAR_VALUE__DEFAULT assert '1' != c.CHAR_VALUE__DEFAULT assert b'\x01' == c.BYTE_VALUE__DEFAULT assert b'1' != c.BYTE_VALUE__DEFAULT @@ -198,8 +198,8 @@ def test_check_constraints(): with pytest.raises(AssertionError): setattr(c, 'byte_value', 'abc') - c.char_value = 'a' - assert 'a' == c.char_value + c.char_value = ord('a') + assert ord('a') == c.char_value assert b'a' != c.char_value with pytest.raises(AssertionError): setattr(c, 'char_value', b'a') @@ -267,10 +267,10 @@ def test_slot_attributes(): 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': 'rosidl_generator_py/Primitives[<=3]', - 'unbounded_primitives': 'rosidl_generator_py/Primitives[]', + 'primitives': 'rosidl_generator_py::msg::Primitives', + 'two_primitives': 'rosidl_generator_py::msg::Primitives[2]', + 'up_to_three_primitives': 'sequence', + 'unbounded_primitives': 'sequence', } assert len(nested_slot_types_dict) == len(expected_nested_slot_types_dict) @@ -287,17 +287,17 @@ def test_primative_slot_attributes(): 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': 'string<=5[<=10]', - 'ub_string_dynamic_array_value': 'string<=5[]', - 'string_dynamic_array_value': 'string[]', + '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': 'string[<=10]', - 'def_string_dynamic_array_value': 'string[]', + 'string_bounded_array_value': 'sequence', + 'def_string_dynamic_array_value': 'sequence', 'def_string_static_array_value': 'string[3]', - 'def_string_bounded_array_value': 'string[<=10]', - 'def_various_quotes': 'string[]', - 'def_various_commas': 'string[]', + '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) From 73312ebee65058af7e9176a407b6c77f4bfbd82d Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Tue, 4 Dec 2018 09:43:24 -0800 Subject: [PATCH 04/26] fix usage of service template --- rosidl_generator_py/resource/_idl.py.em | 25 ++++++------------------- rosidl_generator_py/resource/_srv.py.em | 4 ++-- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/rosidl_generator_py/resource/_idl.py.em b/rosidl_generator_py/resource/_idl.py.em index 72e6275c..8e8d75bf 100644 --- a/rosidl_generator_py/resource/_idl.py.em +++ b/rosidl_generator_py/resource/_idl.py.em @@ -35,13 +35,8 @@ from rosidl_parser.definition import Service @[for service in content.get_elements_of_type(Service)]@ @{ TEMPLATE( - '_msg.py.em', - package_name=package_name, interface_path=interface_path, - message=service.request_message) -TEMPLATE( - '_msg.py.em', - package_name=package_name, interface_path=interface_path, - message=service.response_message) + '_srv.py.em', + package_name=package_name, interface_path=interface_path, service=service) }@ @[end for]@ @ @@ -66,21 +61,13 @@ TEMPLATE( package_name=package_name, interface_path=interface_path, message=action.feedback) TEMPLATE( - '_msg.py.em', + '_srv.py.em', package_name=package_name, interface_path=interface_path, - message=action.goal_service.request_message) + service=action.goal_service) TEMPLATE( - '_msg.py.em', - package_name=package_name, interface_path=interface_path, - message=action.goal_service.response_message) -TEMPLATE( - '_msg.py.em', - package_name=package_name, interface_path=interface_path, - message=action.result_service.request_message) -TEMPLATE( - '_msg.py.em', + '_srv.py.em', package_name=package_name, interface_path=interface_path, - message=action.result_service.response_message) + service=action.result_service) TEMPLATE( '_msg.py.em', package_name=package_name, interface_path=interface_path, diff --git a/rosidl_generator_py/resource/_srv.py.em b/rosidl_generator_py/resource/_srv.py.em index 89fefe87..f23aed95 100644 --- a/rosidl_generator_py/resource/_srv.py.em +++ b/rosidl_generator_py/resource/_srv.py.em @@ -28,11 +28,11 @@ class Metaclass_@(service.structure_type.name)(type): except ImportError: import logging import traceback - logger = logging.getLogger('@('.'join(service.structure_type.namespaces + [service.structure_type.name]))') + logger = logging.getLogger('@('.'.join(service.structure_type.namespaces + [service.structure_type.name]))') logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_srv__@(subfolder)_@(module_name) + cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(service.structure_type.namespaces[1:]))_@(module_name) from @('.'.join(service.structure_type.namespaces[:-1])) import @(module_name) if @(module_name).Metaclass_@(service.request_message.structure.type.name)._TYPE_SUPPORT is None: From 3cda2aff59dec1738a0da605ac0201b48673e26c Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Tue, 4 Dec 2018 16:40:47 -0800 Subject: [PATCH 05/26] fix Python TS symbols --- rosidl_generator_py/resource/_msg_support.c.em | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index 71991a00..6c1ab5a9 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -112,11 +112,11 @@ if isinstance(type_, NestedType): @[ if type_.namespaces[0] != package_name]@ ROSIDL_GENERATOR_C_IMPORT @[ end if]@ -bool @('__'.join(type_.namespaces + [type_.name]))__convert_from_py(PyObject * _pymsg, void * _ros_message); +bool @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message); @[ if type_.namespaces[0] != package_name]@ ROSIDL_GENERATOR_C_IMPORT @[ end if]@ -PyObject * @('__'.join(type_.namespaces + [type_.name]))__convert_to_py(void * raw_ros_message); +PyObject * @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]))__convert_to_py(void * raw_ros_message); @[ end if]@ @[end for]@ @@ -124,7 +124,7 @@ PyObject * @('__'.join(type_.namespaces + [type_.name]))__convert_to_py(void * r module_name = '_' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) }@ ROSIDL_GENERATOR_C_EXPORT -bool @('__'.join(message.structure.type.namespaces + [message.structure.type.name]))__convert_from_py(PyObject * _pymsg, void * _ros_message) +bool @('__'.join(message.structure.type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.type.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message) { @{ full_classname = '%s._%s.%s' % ('.'.join(message.structure.type.namespaces), module_name, message.structure.type.name) @@ -201,7 +201,7 @@ nested_type = '__'.join(type_.namespaces + [type_.name]) @(nested_type) * dest = ros_message->@(member.name); @[ end if]@ for (Py_ssize_t i = 0; i < size; ++i) { - if (!@('__'.join(type_.namespaces + [type_.name]))__convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) { + if (!@('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]))__convert_from_py(PySequence_Fast_GET_ITEM(seq_field, i), &dest[i])) { Py_DECREF(seq_field); Py_DECREF(field); return false; @@ -209,7 +209,7 @@ nested_type = '__'.join(type_.namespaces + [type_.name]) } Py_DECREF(seq_field); @[ else]@ - if (!@('__'.join(type_.namespaces + [type_.name]))__convert_from_py(field, &ros_message->@(member.name))) { + if (!@('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]))__convert_from_py(field, &ros_message->@(member.name))) { Py_DECREF(field); return false; } @@ -383,7 +383,7 @@ nested_type = '__'.join(type_.namespaces + [type_.name]) } ROSIDL_GENERATOR_C_EXPORT -PyObject * @('__'.join(message.structure.type.namespaces + [message.structure.type.name]))__convert_to_py(void * raw_ros_message) +PyObject * @('__'.join(message.structure.type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.type.name)]))__convert_to_py(void * raw_ros_message) { /* NOTE(esteve): Call constructor of @(message.structure.type.name) */ PyObject * _pymessage = NULL; @@ -429,7 +429,7 @@ nested_type = '__'.join(type_.namespaces + [type_.name]) @[ else]@ item = &(ros_message->@(member.name)[i]); @[ end if]@ - PyObject * pyitem = @('__'.join(type_.namespaces + [type_.name]))__convert_to_py(item); + PyObject * pyitem = @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]))__convert_to_py(item); if (!pyitem) { Py_DECREF(field); return NULL; @@ -440,7 +440,7 @@ nested_type = '__'.join(type_.namespaces + [type_.name]) } assert(PySequence_Check(field)); @[ else]@ - field = @('__'.join(type_.namespaces + [type_.name]))__convert_to_py(&ros_message->@(member.name)); + field = @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_underscore(type_.name)]))__convert_to_py(&ros_message->@(member.name)); if (!field) { return NULL; } From 4dc23c6b3b45cf3996a583c79dcbfd789f10a1a0 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Tue, 4 Dec 2018 16:41:05 -0800 Subject: [PATCH 06/26] minor fix --- 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 2359df0b..b4713ea8 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -45,7 +45,7 @@ class Metaclass_@(message.structure.type.name)(type): 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: @{ -suffix = '.'.join(message.structure.type.namespaces[1:]) + '_' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) +suffix = '__'.join(message.structure.type.namespaces[1:]) + '_' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) }@ cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__@(suffix) cls._CONVERT_FROM_PY = module.convert_from_py_msg__@(suffix) From e466173e56c4077ccf62fa673001270e55d3bcaf Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Tue, 4 Dec 2018 16:41:24 -0800 Subject: [PATCH 07/26] update template list to trigger rebuilds correctly --- .../cmake/rosidl_generator_py_generate_interfaces.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake index 66cc14e2..46bc24bd 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -85,11 +85,13 @@ endforeach() set(target_dependencies "${rosidl_generator_py_BIN}" ${rosidl_generator_py_GENERATOR_FILES} + "${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}/_msg_support.c.em" - "${rosidl_generator_py_TEMPLATE_DIR}/_msg_pkg_typesupport_entry_point.c.em" "${rosidl_generator_py_TEMPLATE_DIR}/_idl.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" + "${rosidl_generator_py_TEMPLATE_DIR}/_srv_pkg_typesupport_entry_point.c.em" "${rosidl_generator_py_TEMPLATE_DIR}/_srv.py.em" ${_dependency_files}) foreach(dep ${target_dependencies}) From ee906d8b5ee7c408b73177074fcd116f007695ea Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Tue, 4 Dec 2018 17:16:29 -0800 Subject: [PATCH 08/26] and yet another symbol fix --- 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 b4713ea8..349aacf1 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -45,7 +45,7 @@ class Metaclass_@(message.structure.type.name)(type): 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: @{ -suffix = '__'.join(message.structure.type.namespaces[1:]) + '_' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) +suffix = '__'.join(message.structure.type.namespaces[1:]) + '__' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) }@ cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__@(suffix) cls._CONVERT_FROM_PY = module.convert_from_py_msg__@(suffix) From 0967d349030359db4b1f59d946ce1f064201f552 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Wed, 5 Dec 2018 10:07:59 -0800 Subject: [PATCH 09/26] fix installation of generated Python files --- ...idl_generator_py_generate_interfaces.cmake | 50 +++++-------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake index 46bc24bd..bfda4d85 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -56,12 +56,18 @@ endforeach() file(MAKE_DIRECTORY "${_output_path}") file(WRITE "${_output_path}/__init__.py" "") +set(_generated_py_dirs "") foreach(_generated_py_file ${_generated_py_files}) get_filename_component(_parent_folder "${_generated_py_file}" DIRECTORY) set(_init_module "${_parent_folder}/__init__.py") list(FIND _generated_py_files "${_init_module}" _index) if(_index EQUAL -1) list(APPEND _generated_py_files "${_init_module}") + + string(LENGTH "${_output_path}" _length) + math(EXPR _index "${_length} + 1") + string(SUBSTRING "${_parent_folder}" ${_index} -1 _relative_directory) + list(APPEND _generated_py_dirs "${_relative_directory}") endif() endforeach() @@ -110,53 +116,21 @@ rosidl_write_generator_arguments( TEMPLATE_DIR "${rosidl_generator_py_TEMPLATE_DIR}" TARGET_DEPENDENCIES ${target_dependencies} ) -set(extra_generator_dependencies "") - -if(NOT _generated_msg_py_files STREQUAL "") - list(GET _generated_msg_py_files 0 _msg_file) - get_filename_component(_msg_package_dir1 "${_msg_file}" DIRECTORY) - get_filename_component(_msg_package_dir2 "${_msg_package_dir1}" NAME) -endif() - -if(NOT _generated_srv_py_files STREQUAL "") - list(GET _generated_srv_py_files 0 _srv_file) - get_filename_component(_srv_package_dir1 "${_srv_file}" DIRECTORY) - get_filename_component(_srv_package_dir2 "${_srv_package_dir1}" NAME) -endif() - -if(NOT _generated_action_py_files STREQUAL "") - list(GET _generated_action_py_files 0 _action_file) - get_filename_component(_action_package_dir1 "${_action_file}" DIRECTORY) - get_filename_component(_action_package_dir2 "${_action_package_dir1}" NAME) -endif() if(NOT rosidl_generate_interfaces_SKIP_INSTALL) ament_python_install_module("${_output_path}/__init__.py" DESTINATION_SUFFIX "${PROJECT_NAME}" ) - ament_python_install_module("${_output_path}/__init__.py" - DESTINATION_SUFFIX "${PROJECT_NAME}/${_msg_package_dir2}" - ) - # TODO(esteve): replace this with ament_python_install_module and allow a list - # of modules to be passed instead of iterating over _generated_msg_py_files + # of modules to be passed instead of iterating over _generated_py_files # See https://github.com/ros2/rosidl/issues/89 - if(NOT _msg_package_dir2 STREQUAL "") - install(FILES ${_generated_msg_py_files} - DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}/${_msg_package_dir2}" - ) - endif() - if(NOT _srv_package_dir2 STREQUAL "") - install(FILES ${_generated_srv_py_files} - DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}/${_srv_package_dir2}" + foreach(_generated_py_dir ${_generated_py_dirs}) + install(DIRECTORY "${_output_path}/${_generated_py_dir}" + DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}/${_generated_py_dir}" + PATTERN "*.py" ) - endif() - if(NOT _action_package_dir2 STREQUAL "") - install(FILES ${_generated_action_py_files} - DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}/${_action_package_dir2}" - ) - endif() + endforeach() endif() set(_target_suffix "__py") From 4e44deed4b044c48830ddf1bc3163fd3815f50ca Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Wed, 5 Dec 2018 11:23:28 -0800 Subject: [PATCH 10/26] and fix the fix --- .../cmake/rosidl_generator_py_generate_interfaces.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake index bfda4d85..6d209397 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -126,7 +126,7 @@ if(NOT rosidl_generate_interfaces_SKIP_INSTALL) # of modules to be passed instead of iterating over _generated_py_files # See https://github.com/ros2/rosidl/issues/89 foreach(_generated_py_dir ${_generated_py_dirs}) - install(DIRECTORY "${_output_path}/${_generated_py_dir}" + install(DIRECTORY "${_output_path}/${_generated_py_dir}/" DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}/${_generated_py_dir}" PATTERN "*.py" ) From 42f5ede20ed5bd9250ea4c8e37c86c2ada94ca3d Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Wed, 6 Feb 2019 13:45:15 -0800 Subject: [PATCH 11/26] redo recent action changes to work with IDL --- .../cmake/custom_command.cmake | 12 +- rosidl_generator_py/cmake/register_py.cmake | 5 - ...erator_py_generate_action_interfaces.cmake | 241 ------------------ rosidl_generator_py/resource/_action.py.em | 103 ++++---- rosidl_generator_py/resource/_idl.py.em | 25 +- .../_msg_pkg_typesupport_entry_point.c.em | 118 --------- rosidl_generator_py/resource/_srv.py.em | 2 +- .../rosidl_generator_py/generate_py_impl.py | 2 - 8 files changed, 67 insertions(+), 441 deletions(-) delete mode 100644 rosidl_generator_py/cmake/rosidl_generator_py_generate_action_interfaces.cmake diff --git a/rosidl_generator_py/cmake/custom_command.cmake b/rosidl_generator_py/cmake/custom_command.cmake index 558716d1..62fd7627 100644 --- a/rosidl_generator_py/cmake/custom_command.cmake +++ b/rosidl_generator_py/cmake/custom_command.cmake @@ -19,11 +19,11 @@ # a different CMake subdirectory, and this command is invoked after an # add_subdirectory() call. add_custom_command( - OUTPUT ${_generated_extension_files} ${_generated_msg_py_files} ${_generated_msg_c_files} ${_generated_srv_py_files} ${_generated_srv_c_files} ${_generated_action_py_files} ${_generated_action_c_files} + OUTPUT ${_generated_extension_files} ${_generated_py_files} ${_generated_c_files} COMMAND ${PYTHON_EXECUTABLE} ${rosidl_generator_py_BIN} --generator-arguments-file "${generator_arguments_file}" --typesupport-impls "${_typesupport_impls}" - DEPENDS ${target_dependencies} ${rosidl_generate_interfaces_TARGET} ${extra_generator_dependencies} + DEPENDS ${target_dependencies} ${rosidl_generate_interfaces_TARGET} COMMENT "Generating Python code for ROS interfaces" VERBATIM ) @@ -35,11 +35,7 @@ else() ${rosidl_generate_interfaces_TARGET}${_target_suffix} DEPENDS ${_generated_extension_files} - ${_generated_msg_py_files} - ${_generated_msg_c_files} - ${_generated_srv_py_files} - ${_generated_srv_c_files} - ${_generated_action_py_files} - ${_generated_action_c_files} + ${_generated_py_files} + ${_generated_c_files} ) endif() diff --git a/rosidl_generator_py/cmake/register_py.cmake b/rosidl_generator_py/cmake/register_py.cmake index 5e3e4b69..f3f21156 100644 --- a/rosidl_generator_py/cmake/register_py.cmake +++ b/rosidl_generator_py/cmake/register_py.cmake @@ -19,11 +19,6 @@ macro(rosidl_generator_py_extras BIN GENERATOR_FILES TEMPLATE_DIR) "rosidl_generator_py" "rosidl_generator_py_generate_interfaces.cmake") - ament_register_extension( - "rosidl_generate_action_interfaces" - "rosidl_generator_py" - "rosidl_generator_py_generate_action_interfaces.cmake") - normalize_path(BIN "${BIN}") set(rosidl_generator_py_BIN "${BIN}") diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_action_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_action_interfaces.cmake deleted file mode 100644 index 177592d4..00000000 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_action_interfaces.cmake +++ /dev/null @@ -1,241 +0,0 @@ -# Copyright 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. - -find_package(rmw_implementation_cmake REQUIRED) -find_package(rmw REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_typesupport_c REQUIRED) -find_package(rosidl_typesupport_interface REQUIRED) - -find_package(PythonInterp 3.5 REQUIRED) - -find_package(python_cmake_module REQUIRED) -find_package(PythonExtra MODULE REQUIRED) - -set(_typesupport_impls "rosidl_typesupport_c") - -set(_output_path - "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py/${PROJECT_NAME}") - -set(_generated_action_py_files "") -foreach(_idl_file ${rosidl_generate_action_interfaces_IDL_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - get_filename_component(_parent_folder "${_idl_file}" DIRECTORY) - get_filename_component(_parent_folder "${_parent_folder}" NAME) - if(_extension STREQUAL ".action") - set(_allowed_parent_folders "action") - if(NOT _parent_folder IN_LIST _allowed_parent_folders) - message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}") - endif() - else() - message(FATAL_ERROR "Interface file with unknown extension: ${_idl_file}") - endif() - get_filename_component(_msg_name "${_idl_file}" NAME_WE) - string_camel_case_to_lower_case_underscore("${_msg_name}" _module_name) - list(APPEND _generated_action_py_files - "${_output_path}/${_parent_folder}/_${_module_name}.py" - ) -endforeach() - -foreach(_typesupport_impl ${_typesupport_impls}) - set(_generated_extension_${_typesupport_impl}_files "") -endforeach() -set(_generated_extension_files "") - -if(NOT _generated_action_py_files STREQUAL "") - foreach(_typesupport_impl ${_typesupport_impls}) - list(APPEND _generated_extension_${_typesupport_impl}_files "${_output_path}/_${PROJECT_NAME}_action_s.ep.${_typesupport_impl}.c") - list(APPEND _generated_extension_files "${_generated_extension_${_typesupport_impl}_files}") - endforeach() - list(GET _generated_action_py_files 0 _action_file) - get_filename_component(_parent_folder "${_action_file}" DIRECTORY) - list(APPEND _generated_action_py_files "${_parent_folder}/__init__.py") -endif() - -set(_dependency_files "") -set(_dependencies "") -foreach(_pkg_name ${rosidl_generate_action_interfaces_DEPENDENCY_PACKAGE_NAMES}) - foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - if(_extension STREQUAL ".msg") - set(_abs_idl_file "${${_pkg_name}_DIR}/../${_idl_file}") - normalize_path(_abs_idl_file "${_abs_idl_file}") - list(APPEND _dependency_files "${_abs_idl_file}") - list(APPEND _dependencies "${_pkg_name}:${_abs_idl_file}") - endif() - endforeach() -endforeach() - -set(target_dependencies - "${rosidl_generator_py_BIN}" - ${rosidl_generator_py_GENERATOR_FILES} - "${rosidl_generator_py_TEMPLATE_DIR}/_action.py.em" - "${rosidl_generator_py_TEMPLATE_DIR}/_msg_pkg_typesupport_entry_point.c.em" - ${rosidl_generate_action_interfaces_IDL_FILES} - ${_dependency_files}) -foreach(dep ${target_dependencies}) - if(NOT EXISTS "${dep}") - get_property(is_generated SOURCE "${dep}" PROPERTY GENERATED) - if(NOT ${_is_generated}) - message(FATAL_ERROR "Target dependency '${dep}' does not exist") - endif() - endif() -endforeach() - -set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py__generate_actions__arguments.json") -rosidl_write_generator_arguments( - "${generator_arguments_file}" - PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_action_interfaces_IDL_FILES}" - ROS_INTERFACE_DEPENDENCIES "${_dependencies}" - OUTPUT_DIR "${_output_path}" - TEMPLATE_DIR "${rosidl_generator_py_TEMPLATE_DIR}" - TARGET_DEPENDENCIES ${target_dependencies} -) -# make sure that actions generation run sequentially with messages/services generation -set(extra_generator_dependencies "${rosidl_generate_interfaces_TARGET}__py") - -set(_target_suffix "__action_py") - -# move custom command into a subdirectory to avoid multiple invocations on Windows -set(_subdir "${CMAKE_CURRENT_BINARY_DIR}/${rosidl_generate_interfaces_TARGET}${_target_suffix}") -file(MAKE_DIRECTORY "${_subdir}") -file(READ "${rosidl_generator_py_DIR}/custom_command.cmake" _custom_command) -file(WRITE "${_subdir}/CMakeLists.txt" "${_custom_command}") -add_subdirectory("${_subdir}" ${rosidl_generate_interfaces_TARGET}${_target_suffix}) -set_property( - SOURCE - ${_generated_extension_files} ${_generated_action_py_files} - PROPERTY GENERATED 1) - -macro(set_properties _build_type) - set_target_properties(${_target_name} PROPERTIES - COMPILE_OPTIONS "${_extension_compile_flags}" - PREFIX "" - LIBRARY_OUTPUT_DIRECTORY${_build_type} ${_output_path} - RUNTIME_OUTPUT_DIRECTORY${_build_type} ${_output_path} - OUTPUT_NAME "${PROJECT_NAME}_action_s__${_typesupport_impl}${PythonExtra_EXTENSION_SUFFIX}" - SUFFIX "${PythonExtra_EXTENSION_EXTENSION}") -endmacro() - -foreach(_typesupport_impl ${_typesupport_impls}) - find_package(${_typesupport_impl} REQUIRED) - - set(_pyext_suffix "__pyext") - set(_target_name "${PROJECT_NAME}_action__${_typesupport_impl}${_pyext_suffix}") - - add_library(${_target_name} SHARED - ${_generated_extension_${_typesupport_impl}_files} - ) - add_dependencies( - ${_target_name} - ${rosidl_generate_interfaces_TARGET}${_target_suffix} - ${rosidl_generate_interfaces_TARGET}__rosidl_typesupport_c - ) - - set(_extension_compile_flags "") - set(_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) - if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(_extension_compile_flags -Wall -Wextra) - endif() - if(WIN32 AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE_DEBUG}) - endif() - set_properties("") - if(WIN32) - set_properties("_DEBUG") - set_properties("_MINSIZEREL") - set_properties("_RELEASE") - set_properties("_RELWITHDEBINFO") - endif() - target_link_libraries( - ${_target_name} - ${PythonExtra_LIBRARIES} - ${rosidl_generate_interfaces_TARGET}__${_typesupport_impl} - ${rosidl_generate_interfaces_TARGET}__${_typesupport_impl}__generate_actions - ) - - target_include_directories(${_target_name} - PUBLIC - ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c - ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_py - ${PythonExtra_INCLUDE_DIRS} - ) - - rosidl_target_interfaces(${_target_name} - ${rosidl_generate_interfaces_TARGET} rosidl_typesupport_c) - - ament_target_dependencies(${_target_name} - "rosidl_generator_c" - "rosidl_typesupport_c" - "rosidl_typesupport_interface" - ) - foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) - ament_target_dependencies(${_target_name} - ${_pkg_name} - ) - endforeach() - - add_dependencies(${_target_name} - ${rosidl_generate_interfaces_TARGET}__${_typesupport_impl} - ${rosidl_generate_interfaces_TARGET}__${_typesupport_impl}__generate_actions - ) - ament_target_dependencies(${_target_name} - "rosidl_generator_c" - "rosidl_generator_py" - "${rosidl_generate_interfaces_TARGET}__rosidl_generator_c" - ) - set(PYTHON_EXECUTABLE ${_PYTHON_EXECUTABLE}) - - if(NOT rosidl_generate_interfaces_SKIP_INSTALL) - install(TARGETS ${_target_name} - DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}") - endif() -endforeach() - -if(NOT rosidl_generate_action_interfaces_SKIP_INSTALL) - if(NOT _generated_action_py_files STREQUAL "") - list(GET _generated_action_py_files 0 _action_file) - get_filename_component(_action_package_dir "${_action_file}" DIRECTORY) - get_filename_component(_action_package_dir "${_action_package_dir}" NAME) - if(NOT _action_package_dir STREQUAL "") - install(FILES ${_generated_action_py_files} - DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}/${_action_package_dir}" - ) - endif() - endif() -endif() - -if(BUILD_TESTING AND rosidl_generate_action_interfaces_ADD_LINTER_TESTS) - if(NOT _generated_action_py_files STREQUAL "") - find_package(ament_cmake_flake8 REQUIRED) - ament_flake8( - TESTNAME "flake8_rosidl_generated_py_generate_actions" - # the generated code might contain longer lines for templated types - MAX_LINE_LENGTH 999 - "${_output_path}") - - find_package(ament_cmake_pep257 REQUIRED) - ament_pep257( - TESTNAME "pep257_rosidl_generated_py_generate_actions" - "${_output_path}") - - find_package(ament_cmake_uncrustify REQUIRED) - ament_uncrustify( - TESTNAME "uncrustify_rosidl_generated_py_generate_actions" - # the generated code might contain longer lines for templated types - MAX_LINE_LENGTH 0 - "${_output_path}") - endif() -endif() diff --git a/rosidl_generator_py/resource/_action.py.em b/rosidl_generator_py/resource/_action.py.em index 4393fe8c..0158c48b 100644 --- a/rosidl_generator_py/resource/_action.py.em +++ b/rosidl_generator_py/resource/_action.py.em @@ -1,23 +1,38 @@ -# generated from rosidl_generator_py/resource/_action.py.em -# generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating _.py files -@# -@# Context: -@# - module_name -@# - package_name -@# - spec (rosidl_parser.ActionSpecification) -@# Parsed specification of the .action file -@# - convert_camel_case_to_lower_case_underscore (function) -@####################################################################### -@ -import logging -import traceback - - -class Metaclass(type): - """Metaclass of action '@(spec.action_name)'.""" +@# Included from rosidl_generator_py/resource/_idl.py.em +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore + +module_name = '_' + convert_camel_case_to_lower_case_underscore(action.structure_type.name) + +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.goal_request) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.result_response) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback) +TEMPLATE( + '_srv.py.em', + package_name=package_name, interface_path=interface_path, + service=action.goal_service) +TEMPLATE( + '_srv.py.em', + package_name=package_name, interface_path=interface_path, + service=action.result_service) +TEMPLATE( + '_msg.py.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback_message) +}@ + + +class Metaclass_@(action.structure_type.name)(type): + """Metaclass of action '@(action.structure_type.name)'.""" _TYPE_SUPPORT = None @@ -25,38 +40,40 @@ class Metaclass(type): def __import_type_support__(cls): try: from rosidl_generator_py import import_type_support - module = import_type_support('@(package_name)', '@(package_name)_action') + module = import_type_support('@(package_name)') except ImportError: - logger = logging.getLogger('rosidl_generator_py.@(spec.action_name)') + import logging + import traceback + logger = logging.getLogger('@('.'.join(action.structure_type.namespaces + [action.structure_type.name]))') logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_action__@(subfolder)_@(module_name) -@{ -prefix = '_' + convert_camel_case_to_lower_case_underscore(spec.action_name) + '__' -suffixes = ['feedback', 'goal', 'result'] -for field_name in [prefix + suffix for suffix in suffixes]: - print('%sfrom %s.%s import %s' % (' ' * 4 * 3, package_name, subfolder, field_name)) - print('%sif %s.Metaclass._TYPE_SUPPORT is None:' % (' ' * 4 * 3, field_name)) - print('%s%s.Metaclass.__import_type_support__()' % (' ' * 4 * 4, field_name)) -print('%sfrom %s.%s import %s' % (' ' * 4 * 3, 'action_msgs', 'msg', '_goal_status_array')) -print('%sif %s.Metaclass._TYPE_SUPPORT is None:' % (' ' * 4 * 3, '_goal_status_array')) -print('%s%s.Metaclass.__import_type_support__()' % (' ' * 4 * 4, '_goal_status_array')) -print('%sfrom %s.%s import %s' % (' ' * 4 * 3, 'action_msgs', 'srv', '_cancel_goal')) -print('%sif %s.Metaclass._TYPE_SUPPORT is None:' % (' ' * 4 * 3, '_cancel_goal')) -print('%s%s.Metaclass.__import_type_support__()' % (' ' * 4 * 4, '_cancel_goal')) -}@ + cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(action.structure_type.namespaces[1:]))_@(module_name) + + from action_msgs.msg import _goal_status_array + if _goal_status_array.Metaclass._TYPE_SUPPORT is None: + _goal_status_array.Metaclass.__import_type_support__() + from action_msgs.srv import _cancel_goal + if _cancel_goal.Metaclass._TYPE_SUPPORT is None: + _cancel_goal.Metaclass.__import_type_support__() + + if @(module_name).Metaclass_@(action.goal_service.structure_type.name)._TYPE_SUPPORT is None: + @(module_name).Metaclass_@(action.goal_service.structure_type.name).__import_type_support__() + if @(module_name).Metaclass_@(action.result_service.structure_type.name)._TYPE_SUPPORT is None: + @(module_name).Metaclass_@(action.result_service.structure_type.name).__import_type_support__() + if @(module_name).Metaclass_@(action.feedback.structure.type.name)._TYPE_SUPPORT is None: + @(module_name).Metaclass_@(action.feedback.structure.type.name).__import_type_support__() -class @(spec.action_name)(metaclass=Metaclass): +class @(action.structure_type.name)(metaclass=Metaclass_@(action.structure_type.name)): from action_msgs.srv._cancel_goal import CancelGoal as CancelGoalService from action_msgs.msg._goal_status_array import GoalStatusArray as GoalStatusMessage - from @(package_name).@(subfolder)._@convert_camel_case_to_lower_case_underscore(spec.action_name)__goal import @(spec.action_name)_Goal as GoalRequestService - from @(package_name).@(subfolder)._@convert_camel_case_to_lower_case_underscore(spec.action_name)__result import @(spec.action_name)_Result as GoalResultService - from @(package_name).@(subfolder)._@convert_camel_case_to_lower_case_underscore(spec.action_name)__feedback import @(spec.action_name)_Feedback as Feedback + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.goal_service.structure_type.name) as GoalService + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.result_service.structure_type.name) as ResultService + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.feedback.structure.type.name) as Feedback - Goal = GoalRequestService.Request - Result = GoalResultService.Response + Goal = GoalService.Request + Result = ResultService.Response def __init__(self): raise NotImplementedError('Action classes can not be instantiated') diff --git a/rosidl_generator_py/resource/_idl.py.em b/rosidl_generator_py/resource/_idl.py.em index 8e8d75bf..300691f1 100644 --- a/rosidl_generator_py/resource/_idl.py.em +++ b/rosidl_generator_py/resource/_idl.py.em @@ -49,28 +49,7 @@ from rosidl_parser.definition import Action @[for action in content.get_elements_of_type(Action)]@ @{ TEMPLATE( - '_msg.py.em', - package_name=package_name, interface_path=interface_path, - message=action.goal_request) -TEMPLATE( - '_msg.py.em', - package_name=package_name, interface_path=interface_path, - message=action.result_response) -TEMPLATE( - '_msg.py.em', - package_name=package_name, interface_path=interface_path, - message=action.feedback) -TEMPLATE( - '_srv.py.em', - package_name=package_name, interface_path=interface_path, - service=action.goal_service) -TEMPLATE( - '_srv.py.em', - package_name=package_name, interface_path=interface_path, - service=action.result_service) -TEMPLATE( - '_msg.py.em', - package_name=package_name, interface_path=interface_path, - message=action.feedback_message) + '_action.py.em', + package_name=package_name, interface_path=interface_path, action=action) }@ @[end for]@ diff --git a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em index 02033758..524ea049 100644 --- a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em @@ -103,123 +103,5 @@ function_names = ['create_ros_message', 'destroy_ros_message', 'convert_from_py' return err; } @[end for]@ -<<<<<<< HEAD -@ -@[for spec, subfolder in service_specs]@ -@{ -type_name = convert_camel_case_to_lower_case_underscore(spec.srv_name) -function_name = 'type_support' -}@ - -ROSIDL_GENERATOR_C_IMPORT -const rosidl_service_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name))(); - -int8_t -_register_srv_type__@(subfolder)__@(type_name)(PyObject * pymodule) -{ - int8_t err; - PyObject * pyobject_@(function_name) = NULL; - pyobject_@(function_name) = PyCapsule_New( - (void *)ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name))(), - NULL, NULL); - if (!pyobject_@(function_name)) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "@(function_name)_srv__@(subfolder)_@(type_name)", - pyobject_@(function_name)); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_@(function_name)); - // previously added objects will be removed when the module is destroyed - return err; - } - return 0; -} -@[end for]@ -@ -@[for spec, subfolder in action_specs]@ -@{ -type_name = convert_camel_case_to_lower_case_underscore(spec.action_name) -function_name = 'type_support' -}@ - -ROSIDL_GENERATOR_C_IMPORT -const rosidl_action_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__ACTION_SYMBOL_NAME(rosidl_typesupport_c, @(spec.pkg_name), @(subfolder), @(spec.action_name))(); - -int8_t -_register_action_type__@(subfolder)__@(type_name)(PyObject * pymodule) -{ - int8_t err; - PyObject * pyobject_@(function_name) = NULL; - pyobject_@(function_name) = PyCapsule_New( - (void *)ROSIDL_TYPESUPPORT_INTERFACE__ACTION_SYMBOL_NAME(rosidl_typesupport_c, @(spec.pkg_name), @(subfolder), @(spec.action_name))(), - NULL, NULL); - if (!pyobject_@(function_name)) { - // previously added objects will be removed when the module is destroyed - return -1; - } - err = PyModule_AddObject( - pymodule, - "@(function_name)_action__@(subfolder)_@(type_name)", - pyobject_@(function_name)); - if (err) { - // the created capsule needs to be decremented - Py_XDECREF(pyobject_@(function_name)); - // previously added objects will be removed when the module is destroyed - return err; - } - return 0; -} -@[end for]@ - -PyMODINIT_FUNC -PyInit_@(package_name)_s__@(typesupport_impl)(void) -{ - PyObject * pymodule = NULL; - pymodule = PyModule_Create(&@(package_name)__module); - if (!pymodule) { - return NULL; - } - int8_t err; -@[for spec, subfolder in message_specs]@ -@{ -type_name = convert_camel_case_to_lower_case_underscore(spec.base_type.type) -}@ - err = _register_msg_type__@(subfolder)__@(type_name)(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } -@[end for]@ -@[for spec, subfolder in service_specs]@ -@{ -type_name = convert_camel_case_to_lower_case_underscore(spec.srv_name) -}@ - err = _register_srv_type__@(subfolder)__@(type_name)(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } -@[end for]@ -@[for spec, subfolder in action_specs]@ -@{ -type_name = convert_camel_case_to_lower_case_underscore(spec.action_name) -}@ - err = _register_action_type__@(subfolder)__@(type_name)(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } -@[end for]@ - - return pymodule; -} -======= return 0; } ->>>>>>> update rosidl_generator_py to use IDL-based extension point diff --git a/rosidl_generator_py/resource/_srv.py.em b/rosidl_generator_py/resource/_srv.py.em index f23aed95..06405e72 100644 --- a/rosidl_generator_py/resource/_srv.py.em +++ b/rosidl_generator_py/resource/_srv.py.em @@ -16,7 +16,7 @@ TEMPLATE( class Metaclass_@(service.structure_type.name)(type): - """Metaclass of message '@(service.structure_type.name)'.""" + """Metaclass of service '@(service.structure_type.name)'.""" _TYPE_SUPPORT = None diff --git a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py index f1a712a8..15130194 100644 --- a/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py +++ b/rosidl_generator_py/rosidl_generator_py/generate_py_impl.py @@ -82,8 +82,6 @@ def generate_py(generator_arguments_file, typesupport_impls): for template_file, generated_filenames in mapping_msg_pkg_extension.items(): for generated_filename in generated_filenames: package_name = args['package_name'] - if action_specs: - package_name += '_action' data = { 'package_name': args['package_name'], 'content': idl_content, From d4a1e4197ef020de656adb21ed07936f0ea497f4 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Tue, 12 Feb 2019 11:57:06 -0800 Subject: [PATCH 12/26] match renamed action types --- rosidl_generator_py/resource/_action.py.em | 20 ++++----- .../_idl_pkg_typesupport_entry_point.c.em | 45 +++++++++++-------- .../resource/_idl_support.c.em | 12 ++--- .../_msg_pkg_typesupport_entry_point.c.em | 19 ++------ .../_srv_pkg_typesupport_entry_point.c.em | 10 +++-- 5 files changed, 51 insertions(+), 55 deletions(-) diff --git a/rosidl_generator_py/resource/_action.py.em b/rosidl_generator_py/resource/_action.py.em index 0158c48b..1c5a4bcc 100644 --- a/rosidl_generator_py/resource/_action.py.em +++ b/rosidl_generator_py/resource/_action.py.em @@ -7,11 +7,11 @@ module_name = '_' + convert_camel_case_to_lower_case_underscore(action.structure TEMPLATE( '_msg.py.em', package_name=package_name, interface_path=interface_path, - message=action.goal_request) + message=action.goal) TEMPLATE( '_msg.py.em', package_name=package_name, interface_path=interface_path, - message=action.result_response) + message=action.result) TEMPLATE( '_msg.py.em', package_name=package_name, interface_path=interface_path, @@ -19,11 +19,11 @@ TEMPLATE( TEMPLATE( '_srv.py.em', package_name=package_name, interface_path=interface_path, - service=action.goal_service) + service=action.send_goal_service) TEMPLATE( '_srv.py.em', package_name=package_name, interface_path=interface_path, - service=action.result_service) + service=action.get_result_service) TEMPLATE( '_msg.py.em', package_name=package_name, interface_path=interface_path, @@ -57,10 +57,10 @@ class Metaclass_@(action.structure_type.name)(type): if _cancel_goal.Metaclass._TYPE_SUPPORT is None: _cancel_goal.Metaclass.__import_type_support__() - if @(module_name).Metaclass_@(action.goal_service.structure_type.name)._TYPE_SUPPORT is None: - @(module_name).Metaclass_@(action.goal_service.structure_type.name).__import_type_support__() - if @(module_name).Metaclass_@(action.result_service.structure_type.name)._TYPE_SUPPORT is None: - @(module_name).Metaclass_@(action.result_service.structure_type.name).__import_type_support__() + if @(module_name).Metaclass_@(action.send_goal_service.structure_type.name)._TYPE_SUPPORT is None: + @(module_name).Metaclass_@(action.send_goal_service.structure_type.name).__import_type_support__() + if @(module_name).Metaclass_@(action.get_result_service.structure_type.name)._TYPE_SUPPORT is None: + @(module_name).Metaclass_@(action.get_result_service.structure_type.name).__import_type_support__() if @(module_name).Metaclass_@(action.feedback.structure.type.name)._TYPE_SUPPORT is None: @(module_name).Metaclass_@(action.feedback.structure.type.name).__import_type_support__() @@ -68,8 +68,8 @@ class Metaclass_@(action.structure_type.name)(type): class @(action.structure_type.name)(metaclass=Metaclass_@(action.structure_type.name)): from action_msgs.srv._cancel_goal import CancelGoal as CancelGoalService from action_msgs.msg._goal_status_array import GoalStatusArray as GoalStatusMessage - from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.goal_service.structure_type.name) as GoalService - from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.result_service.structure_type.name) as ResultService + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.send_goal_service.structure_type.name) as GoalService + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.get_result_service.structure_type.name) as ResultService from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.feedback.structure.type.name) as Feedback Goal = GoalService.Request diff --git a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em index 2ad6fa66..d0a9f767 100644 --- a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em @@ -42,7 +42,7 @@ static struct PyModuleDef @(package_name)__module = { @{ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, message=message, + package_name=package_name, idl_type=message.structure.type, message=message, typesupport_impl=typesupport_impl, include_directives=include_directives) }@ @[end for]@ @@ -58,8 +58,9 @@ from rosidl_parser.definition import Service @{ TEMPLATE( '_srv_pkg_typesupport_entry_point.c.em', - package_name=package_name, service=service, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=service.structure_type, + service=service, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @[end for]@ @ @@ -74,43 +75,49 @@ from rosidl_parser.definition import Action @{ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, message=action.goal_request, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=action.structure_type, + message=action.goal, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @{ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, message=action.result_response, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=action.structure_type, + message=action.result, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @{ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, message=action.feedback, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=action.structure_type, + message=action.feedback, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @{ TEMPLATE( '_srv_pkg_typesupport_entry_point.c.em', - package_name=package_name, service=action.goal_service, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=action.structure_type, + service=action.send_goal_service, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @{ TEMPLATE( '_srv_pkg_typesupport_entry_point.c.em', - package_name=package_name, service=action.result_service, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=action.structure_type, + service=action.get_result_service, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @{ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, message=action.feedback_message, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=action.structure_type, + message=action.feedback_message, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @[end for]@ @@ -153,13 +160,13 @@ PyInit_@(package_name)_s__@(typesupport_impl)(void) @[end for]@ @[for action in content.get_elements_of_type(Action)]@ - err = _register_msg_type__@('__'.join(action.goal_request.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.goal_request.structure.type.name))(pymodule); + err = _register_msg_type__@('__'.join(action.goal.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.goal.structure.type.name))(pymodule); if (err) { Py_XDECREF(pymodule); return NULL; } - err = _register_msg_type__@('__'.join(action.result_response.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.result_response.structure.type.name))(pymodule); + err = _register_msg_type__@('__'.join(action.result.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.result.structure.type.name))(pymodule); if (err) { Py_XDECREF(pymodule); return NULL; @@ -171,13 +178,13 @@ PyInit_@(package_name)_s__@(typesupport_impl)(void) return NULL; } - err = _register_srv_type__@('__'.join(action.goal_service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.goal_service.structure_type.name))(pymodule); + err = _register_srv_type__@('__'.join(action.send_goal_service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.send_goal_service.structure_type.name))(pymodule); if (err) { Py_XDECREF(pymodule); return NULL; } - err = _register_srv_type__@('__'.join(action.result_service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.result_service.structure_type.name))(pymodule); + err = _register_srv_type__@('__'.join(action.get_result_service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.get_result_service.structure_type.name))(pymodule); if (err) { Py_XDECREF(pymodule); return NULL; diff --git a/rosidl_generator_py/resource/_idl_support.c.em b/rosidl_generator_py/resource/_idl_support.c.em index 6a279895..abb7536e 100644 --- a/rosidl_generator_py/resource/_idl_support.c.em +++ b/rosidl_generator_py/resource/_idl_support.c.em @@ -64,14 +64,14 @@ from rosidl_parser.definition import Action TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.goal_request, include_directives=include_directives) + message=action.goal, include_directives=include_directives) }@ @{ TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.result_response, include_directives=include_directives) + message=action.result, include_directives=include_directives) }@ @{ @@ -85,7 +85,7 @@ TEMPLATE( TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.goal_service.request_message, + message=action.send_goal_service.request_message, include_directives=include_directives) }@ @@ -93,7 +93,7 @@ TEMPLATE( TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.goal_service.response_message, + message=action.send_goal_service.response_message, include_directives=include_directives) }@ @@ -101,7 +101,7 @@ TEMPLATE( TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.result_service.request_message, + message=action.get_result_service.request_message, include_directives=include_directives) }@ @@ -109,7 +109,7 @@ TEMPLATE( TEMPLATE( '_msg_support.c.em', package_name=package_name, interface_path=interface_path, - message=action.result_service.response_message, + message=action.get_result_service.response_message, include_directives=include_directives) }@ diff --git a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em index 524ea049..4f9a8672 100644 --- a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em @@ -1,23 +1,9 @@ @# Included from rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em @{ from rosidl_cmake import convert_camel_case_to_lower_case_underscore -module_name = convert_camel_case_to_lower_case_underscore(message.structure.type.name) - -header_filename = module_name -if header_filename.endswith('__request'): - header_filename = header_filename[:-9] -elif header_filename.endswith('__response'): - header_filename = header_filename[:-10] -if header_filename.endswith('__goal'): - header_filename = header_filename[:-6] -elif header_filename.endswith('__result'): - header_filename = header_filename[:-8] -elif header_filename.endswith('__feedback'): - header_filename = header_filename[:-10] -if header_filename.endswith('__action'): - header_filename = header_filename[:-8] -include_parts = message.structure.type.namespaces + [header_filename] +include_parts = idl_type.namespaces + [ + convert_camel_case_to_lower_case_underscore(idl_type.name)] include_base = '/'.join(include_parts) header_files = [ @@ -47,6 +33,7 @@ header_files = [ @[end for]@ @ @{ +module_name = convert_camel_case_to_lower_case_underscore(message.structure.type.name) msg_typename = '__'.join(message.structure.type.namespaces + [message.structure.type.name]) }@ diff --git a/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em index 0dfb14fa..65493789 100644 --- a/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em @@ -2,15 +2,17 @@ @{ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, message=service.request_message, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=idl_type, + message=service.request_message, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @{ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, message=service.response_message, - typesupport_impl=typesupport_impl, include_directives=include_directives) + package_name=package_name, idl_type=idl_type, + message=service.response_message, typesupport_impl=typesupport_impl, + include_directives=include_directives) }@ @ @{ From 93d39114a90703e85444817f08d218fc995f93e8 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Thu, 14 Feb 2019 12:54:03 -0800 Subject: [PATCH 13/26] fix type names --- rosidl_generator_py/resource/_action.py.em | 2 +- rosidl_generator_py/resource/_msg.py.em | 10 +++++----- rosidl_generator_py/resource/_srv.py.em | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rosidl_generator_py/resource/_action.py.em b/rosidl_generator_py/resource/_action.py.em index 1c5a4bcc..5c984121 100644 --- a/rosidl_generator_py/resource/_action.py.em +++ b/rosidl_generator_py/resource/_action.py.em @@ -48,7 +48,7 @@ class Metaclass_@(action.structure_type.name)(type): logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(action.structure_type.namespaces[1:]))_@(module_name) + cls._TYPE_SUPPORT = module.type_support_@('__'.join(action.structure_type.namespaces[1:]))_@(module_name) from action_msgs.msg import _goal_status_array if _goal_status_array.Metaclass._TYPE_SUPPORT is None: diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 349aacf1..724b5bd4 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -47,11 +47,11 @@ class Metaclass_@(message.structure.type.name)(type): @{ suffix = '__'.join(message.structure.type.namespaces[1:]) + '__' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) }@ - cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__@(suffix) - cls._CONVERT_FROM_PY = module.convert_from_py_msg__@(suffix) - cls._CONVERT_TO_PY = module.convert_to_py_msg__@(suffix) - cls._TYPE_SUPPORT = module.type_support_msg__@(suffix) - cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__@(suffix) + cls._CREATE_ROS_MESSAGE = module.create_ros_message_@(suffix) + cls._CONVERT_FROM_PY = module.convert_from_py_@(suffix) + cls._CONVERT_TO_PY = module.convert_to_py_@(suffix) + cls._TYPE_SUPPORT = module.type_support_@(suffix) + cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_@(suffix) @{ importable_typesupports = set() for member in message.structure.members: diff --git a/rosidl_generator_py/resource/_srv.py.em b/rosidl_generator_py/resource/_srv.py.em index 06405e72..46ca4048 100644 --- a/rosidl_generator_py/resource/_srv.py.em +++ b/rosidl_generator_py/resource/_srv.py.em @@ -32,7 +32,7 @@ class Metaclass_@(service.structure_type.name)(type): logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(service.structure_type.namespaces[1:]))_@(module_name) + cls._TYPE_SUPPORT = module.type_support_@('__'.join(service.structure_type.namespaces[1:]))_@(module_name) from @('.'.join(service.structure_type.namespaces[:-1])) import @(module_name) if @(module_name).Metaclass_@(service.request_message.structure.type.name)._TYPE_SUPPORT is None: From 39456834aed206cc1ea5bfd503e9d7f78fac2c42 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Thu, 14 Feb 2019 14:02:11 -0800 Subject: [PATCH 14/26] fix symbol names --- rosidl_generator_py/resource/_action.py.em | 2 +- rosidl_generator_py/resource/_msg.py.em | 10 +++++----- rosidl_generator_py/resource/_msg_support.c.em | 4 ++-- rosidl_generator_py/resource/_srv.py.em | 4 ++-- .../resource/_srv_pkg_typesupport_entry_point.c.em | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rosidl_generator_py/resource/_action.py.em b/rosidl_generator_py/resource/_action.py.em index 5c984121..1c5a4bcc 100644 --- a/rosidl_generator_py/resource/_action.py.em +++ b/rosidl_generator_py/resource/_action.py.em @@ -48,7 +48,7 @@ class Metaclass_@(action.structure_type.name)(type): logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_@('__'.join(action.structure_type.namespaces[1:]))_@(module_name) + cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(action.structure_type.namespaces[1:]))_@(module_name) from action_msgs.msg import _goal_status_array if _goal_status_array.Metaclass._TYPE_SUPPORT is None: diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 724b5bd4..349aacf1 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -47,11 +47,11 @@ class Metaclass_@(message.structure.type.name)(type): @{ suffix = '__'.join(message.structure.type.namespaces[1:]) + '__' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) }@ - cls._CREATE_ROS_MESSAGE = module.create_ros_message_@(suffix) - cls._CONVERT_FROM_PY = module.convert_from_py_@(suffix) - cls._CONVERT_TO_PY = module.convert_to_py_@(suffix) - cls._TYPE_SUPPORT = module.type_support_@(suffix) - cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_@(suffix) + cls._CREATE_ROS_MESSAGE = module.create_ros_message_msg__@(suffix) + cls._CONVERT_FROM_PY = module.convert_from_py_msg__@(suffix) + cls._CONVERT_TO_PY = module.convert_to_py_msg__@(suffix) + cls._TYPE_SUPPORT = module.type_support_msg__@(suffix) + cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__@(suffix) @{ importable_typesupports = set() for member in message.structure.members: diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index 6c1ab5a9..904408e8 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -127,7 +127,7 @@ ROSIDL_GENERATOR_C_EXPORT bool @('__'.join(message.structure.type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.type.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message) { @{ -full_classname = '%s._%s.%s' % ('.'.join(message.structure.type.namespaces), module_name, message.structure.type.name) +full_classname = '%s.%s.%s' % ('.'.join(message.structure.type.namespaces), module_name, message.structure.type.name) }@ // check that the passed message is of the expected Python class { @@ -388,7 +388,7 @@ PyObject * @('__'.join(message.structure.type.namespaces + [convert_camel_case_t /* NOTE(esteve): Call constructor of @(message.structure.type.name) */ PyObject * _pymessage = NULL; { - PyObject * pymessage_module = PyImport_ImportModule("@('.'.join(message.structure.type.namespaces))._@(module_name)"); + PyObject * pymessage_module = PyImport_ImportModule("@('.'.join(message.structure.type.namespaces)).@(module_name)"); assert(pymessage_module); PyObject * pymessage_class = PyObject_GetAttrString(pymessage_module, "@(message.structure.type.name)"); assert(pymessage_class); diff --git a/rosidl_generator_py/resource/_srv.py.em b/rosidl_generator_py/resource/_srv.py.em index 46ca4048..e753b253 100644 --- a/rosidl_generator_py/resource/_srv.py.em +++ b/rosidl_generator_py/resource/_srv.py.em @@ -32,9 +32,9 @@ class Metaclass_@(service.structure_type.name)(type): logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_@('__'.join(service.structure_type.namespaces[1:]))_@(module_name) + cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(service.structure_type.namespaces[1:]))_@(module_name) - from @('.'.join(service.structure_type.namespaces[:-1])) import @(module_name) + from @('.'.join(service.structure_type.namespaces)) import @(module_name) if @(module_name).Metaclass_@(service.request_message.structure.type.name)._TYPE_SUPPORT is None: @(module_name).Metaclass_@(service.request_message.structure.type.name).__import_type_support__() if @(module_name).Metaclass_@(service.response_message.structure.type.name)._TYPE_SUPPORT is None: diff --git a/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em index 65493789..8ca12e57 100644 --- a/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em @@ -39,7 +39,7 @@ _register_srv_type__@('__'.join(service.structure_type.namespaces[1:] + [type_na } err = PyModule_AddObject( pymodule, - "@(function_name)_srv__@('_'.join(service.structure_type.namespaces[1:] + [type_name]))", + "@(function_name)_srv__@('__'.join(service.structure_type.namespaces[1:] + [type_name]))", pyobject_@(function_name)); if (err) { // the created capsule needs to be decremented From b375421c0b1a66e446197bda71d5c2539ac488e9 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Thu, 14 Feb 2019 15:14:06 -0800 Subject: [PATCH 15/26] fix imports and CMake dep --- .../cmake/rosidl_generator_py_generate_interfaces.cmake | 1 + rosidl_generator_py/resource/_action.py.em | 6 ++++-- rosidl_generator_py/resource/_srv.py.em | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake index 6d209397..495f9a19 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -91,6 +91,7 @@ endforeach() set(target_dependencies "${rosidl_generator_py_BIN}" ${rosidl_generator_py_GENERATOR_FILES} + "${rosidl_generator_py_TEMPLATE_DIR}/_action.py.em" "${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" diff --git a/rosidl_generator_py/resource/_action.py.em b/rosidl_generator_py/resource/_action.py.em index 1c5a4bcc..4da12e4d 100644 --- a/rosidl_generator_py/resource/_action.py.em +++ b/rosidl_generator_py/resource/_action.py.em @@ -2,7 +2,8 @@ @{ from rosidl_cmake import convert_camel_case_to_lower_case_underscore -module_name = '_' + convert_camel_case_to_lower_case_underscore(action.structure_type.name) +action_name = '_' + convert_camel_case_to_lower_case_underscore(action.structure_type.name) +module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_path.stem) TEMPLATE( '_msg.py.em', @@ -48,7 +49,7 @@ class Metaclass_@(action.structure_type.name)(type): logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(action.structure_type.namespaces[1:]))_@(module_name) + cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(action.structure_type.namespaces[1:]))_@(action_name) from action_msgs.msg import _goal_status_array if _goal_status_array.Metaclass._TYPE_SUPPORT is None: @@ -57,6 +58,7 @@ class Metaclass_@(action.structure_type.name)(type): if _cancel_goal.Metaclass._TYPE_SUPPORT is None: _cancel_goal.Metaclass.__import_type_support__() + from @('.'.join(action.structure_type.namespaces)) import @(module_name) if @(module_name).Metaclass_@(action.send_goal_service.structure_type.name)._TYPE_SUPPORT is None: @(module_name).Metaclass_@(action.send_goal_service.structure_type.name).__import_type_support__() if @(module_name).Metaclass_@(action.get_result_service.structure_type.name)._TYPE_SUPPORT is None: diff --git a/rosidl_generator_py/resource/_srv.py.em b/rosidl_generator_py/resource/_srv.py.em index e753b253..4f584699 100644 --- a/rosidl_generator_py/resource/_srv.py.em +++ b/rosidl_generator_py/resource/_srv.py.em @@ -2,7 +2,8 @@ @{ from rosidl_cmake import convert_camel_case_to_lower_case_underscore -module_name = '_' + convert_camel_case_to_lower_case_underscore(service.structure_type.name) +service_name = '_' + convert_camel_case_to_lower_case_underscore(service.structure_type.name) +module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_path.stem) TEMPLATE( '_msg.py.em', @@ -32,7 +33,7 @@ class Metaclass_@(service.structure_type.name)(type): logger.debug( 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(service.structure_type.namespaces[1:]))_@(module_name) + cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(service.structure_type.namespaces[1:]))_@(service_name) from @('.'.join(service.structure_type.namespaces)) import @(module_name) if @(module_name).Metaclass_@(service.request_message.structure.type.name)._TYPE_SUPPORT is None: From c1d7c34df9f7f28472a5b4760c9b34e42f1a2750 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Fri, 15 Feb 2019 13:24:35 -0800 Subject: [PATCH 16/26] fix module name for services / actions --- rosidl_generator_py/resource/_msg_support.c.em | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index 904408e8..23262261 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -121,7 +121,7 @@ PyObject * @('__'.join(type_.namespaces + [convert_camel_case_to_lower_case_unde @[end for]@ @{ -module_name = '_' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) +module_name = '_' + convert_camel_case_to_lower_case_underscore(interface_path.stem) }@ ROSIDL_GENERATOR_C_EXPORT bool @('__'.join(message.structure.type.namespaces + [convert_camel_case_to_lower_case_underscore(message.structure.type.name)]))__convert_from_py(PyObject * _pymsg, void * _ros_message) From bce6279eb9e375bf2a5f6181ae934ace0b776e06 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Fri, 15 Feb 2019 22:34:19 -0800 Subject: [PATCH 17/26] update action types --- rosidl_generator_py/resource/_action.py.em | 35 +++++++++++++++------- rosidl_generator_py/resource/_msg.py.em | 6 ++-- rosidl_generator_py/resource/_srv.py.em | 6 ++-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/rosidl_generator_py/resource/_action.py.em b/rosidl_generator_py/resource/_action.py.em index 4da12e4d..19cba4dd 100644 --- a/rosidl_generator_py/resource/_action.py.em +++ b/rosidl_generator_py/resource/_action.py.em @@ -45,9 +45,11 @@ class Metaclass_@(action.structure_type.name)(type): except ImportError: import logging import traceback - logger = logging.getLogger('@('.'.join(action.structure_type.namespaces + [action.structure_type.name]))') + logger = logging.getLogger( + '@('.'.join(action.structure_type.namespaces + [action.structure_type.name]))') logger.debug( - 'Failed to import needed modules for type support:\n' + traceback.format_exc()) + 'Failed to import needed modules for type support:\n' + + traceback.format_exc()) else: cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(action.structure_type.namespaces[1:]))_@(action_name) @@ -63,19 +65,32 @@ class Metaclass_@(action.structure_type.name)(type): @(module_name).Metaclass_@(action.send_goal_service.structure_type.name).__import_type_support__() if @(module_name).Metaclass_@(action.get_result_service.structure_type.name)._TYPE_SUPPORT is None: @(module_name).Metaclass_@(action.get_result_service.structure_type.name).__import_type_support__() - if @(module_name).Metaclass_@(action.feedback.structure.type.name)._TYPE_SUPPORT is None: - @(module_name).Metaclass_@(action.feedback.structure.type.name).__import_type_support__() + if @(module_name).Metaclass_@(action.feedback_message.structure.type.name)._TYPE_SUPPORT is None: + @(module_name).Metaclass_@(action.feedback_message.structure.type.name).__import_type_support__() class @(action.structure_type.name)(metaclass=Metaclass_@(action.structure_type.name)): - from action_msgs.srv._cancel_goal import CancelGoal as CancelGoalService - from action_msgs.msg._goal_status_array import GoalStatusArray as GoalStatusMessage - from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.send_goal_service.structure_type.name) as GoalService - from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.get_result_service.structure_type.name) as ResultService + + # The goal message defined in the action definition. + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.goal.structure.type.name) as Goal + # The result message defined in the action definition. + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.result.structure.type.name) as Result + # The feedback message defined in the action definition. from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.feedback.structure.type.name) as Feedback - Goal = GoalService.Request - Result = ResultService.Response + class Impl: + + # The send_goal service using a wrapped version of the goal message as a request. + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.send_goal_service.structure_type.name) as SendGoalService + # The get_result service using a wrapped version of the result message as a response. + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.get_result_service.structure_type.name) as GetResultService + # The feedback message with generic fields which wraps the feedback message. + from @('.'.join(action.structure_type.namespaces)).@(module_name) import @(action.feedback_message.structure.type.name) as FeedbackMessage + + # The generic service to cancel a goal. + from action_msgs.srv._cancel_goal import CancelGoal as CancelGoalService + # The generic message for get the status of a goal. + from action_msgs.msg._goal_status_array import GoalStatusArray as GoalStatusMessage def __init__(self): raise NotImplementedError('Action classes can not be instantiated') diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 349aacf1..94067246 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -40,9 +40,11 @@ class Metaclass_@(message.structure.type.name)(type): except ImportError: import logging import traceback - logger = logging.getLogger('@('.'.join(message.structure.type.namespaces + [message.structure.type.name]))') + logger = logging.getLogger( + '@('.'.join(message.structure.type.namespaces + [message.structure.type.name]))') logger.debug( - 'Failed to import needed modules for type support:\n' + traceback.format_exc()) + 'Failed to import needed modules for type support:\n' + + traceback.format_exc()) else: @{ suffix = '__'.join(message.structure.type.namespaces[1:]) + '__' + convert_camel_case_to_lower_case_underscore(message.structure.type.name) diff --git a/rosidl_generator_py/resource/_srv.py.em b/rosidl_generator_py/resource/_srv.py.em index 4f584699..523c2c24 100644 --- a/rosidl_generator_py/resource/_srv.py.em +++ b/rosidl_generator_py/resource/_srv.py.em @@ -29,9 +29,11 @@ class Metaclass_@(service.structure_type.name)(type): except ImportError: import logging import traceback - logger = logging.getLogger('@('.'.join(service.structure_type.namespaces + [service.structure_type.name]))') + logger = logging.getLogger( + '@('.'.join(service.structure_type.namespaces + [service.structure_type.name]))') logger.debug( - 'Failed to import needed modules for type support:\n' + traceback.format_exc()) + 'Failed to import needed modules for type support:\n' + + traceback.format_exc()) else: cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(service.structure_type.namespaces[1:]))_@(service_name) From 6cbff0f2460a8d1b06b6a7f260579f5742fa4b4a Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Fri, 15 Feb 2019 22:35:05 -0800 Subject: [PATCH 18/26] fix Python type registration --- .../_idl_pkg_typesupport_entry_point.c.em | 87 ++++--------------- .../_msg_pkg_typesupport_entry_point.c.em | 6 +- .../_srv_pkg_typesupport_entry_point.c.em | 12 ++- 3 files changed, 33 insertions(+), 72 deletions(-) diff --git a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em index d0a9f767..84f4a2f3 100644 --- a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em @@ -18,6 +18,7 @@ from rosidl_cmake import convert_camel_case_to_lower_case_underscore from rosidl_parser.definition import Message include_directives = set() +register_functions = [] }@ #include @@ -43,7 +44,8 @@ static struct PyModuleDef @(package_name)__module = { TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=message.structure.type, message=message, - typesupport_impl=typesupport_impl, include_directives=include_directives) + typesupport_impl=typesupport_impl, include_directives=include_directives, + register_functions=register_functions) }@ @[end for]@ @ @@ -60,7 +62,8 @@ TEMPLATE( '_srv_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=service.structure_type, service=service, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @[end for]@ @ @@ -77,7 +80,8 @@ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=action.structure_type, message=action.goal, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @{ @@ -85,7 +89,8 @@ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=action.structure_type, message=action.result, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @{ @@ -93,7 +98,8 @@ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=action.structure_type, message=action.feedback, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @{ @@ -101,7 +107,8 @@ TEMPLATE( '_srv_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=action.structure_type, service=action.send_goal_service, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @{ @@ -109,7 +116,8 @@ TEMPLATE( '_srv_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=action.structure_type, service=action.get_result_service, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @{ @@ -117,7 +125,8 @@ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=action.structure_type, message=action.feedback_message, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @[end for]@ @@ -130,67 +139,9 @@ PyInit_@(package_name)_s__@(typesupport_impl)(void) return NULL; } int8_t err; -@[for message in content.get_elements_of_type(Message)]@ - - err = _register_msg_type__@('__'.join(message.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(message.structure.type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } -@[end for]@ -@[for service in content.get_elements_of_type(Service)]@ - - err = _register_msg_type__@('__'.join(service.request_message.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(service.request_message.structure.type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_msg_type__@('__'.join(service.response_message.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(service.response_message.structure.type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_srv_type__@('__'.join(service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(service.structure_type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } -@[end for]@ -@[for action in content.get_elements_of_type(Action)]@ - - err = _register_msg_type__@('__'.join(action.goal.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.goal.structure.type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_msg_type__@('__'.join(action.result.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.result.structure.type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_msg_type__@('__'.join(action.feedback.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.feedback.structure.type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_srv_type__@('__'.join(action.send_goal_service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.send_goal_service.structure_type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } - - err = _register_srv_type__@('__'.join(action.get_result_service.structure_type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.get_result_service.structure_type.name))(pymodule); - if (err) { - Py_XDECREF(pymodule); - return NULL; - } +@[for register_function in register_functions]@ - err = _register_msg_type__@('__'.join(action.feedback_message.structure.type.namespaces[1:]))__@(convert_camel_case_to_lower_case_underscore(action.feedback_message.structure.type.name))(pymodule); + err = @(register_function)(pymodule); if (err) { Py_XDECREF(pymodule); return NULL; diff --git a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em index 4f9a8672..d9cda9ca 100644 --- a/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_msg_pkg_typesupport_entry_point.c.em @@ -58,8 +58,12 @@ ROSIDL_GENERATOR_C_IMPORT const rosidl_message_type_support_t * ROSIDL_GET_MSG_TYPE_SUPPORT(@(', '.join(message.structure.type.namespaces + [message.structure.type.name]))); +@{ +register_function = '_register_msg_type__' + '__'.join(message.structure.type.namespaces[1:] + [module_name]) +register_functions.append(register_function) +}@ int8_t -_register_msg_type__@('__'.join(message.structure.type.namespaces[1:] + [module_name]))(PyObject * pymodule) +@(register_function)(PyObject * pymodule) { int8_t err; @{ diff --git a/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em index 8ca12e57..943b9bf6 100644 --- a/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_srv_pkg_typesupport_entry_point.c.em @@ -4,7 +4,8 @@ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=idl_type, message=service.request_message, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @{ @@ -12,7 +13,8 @@ TEMPLATE( '_msg_pkg_typesupport_entry_point.c.em', package_name=package_name, idl_type=idl_type, message=service.response_message, typesupport_impl=typesupport_impl, - include_directives=include_directives) + include_directives=include_directives, + register_functions=register_functions) }@ @ @{ @@ -25,8 +27,12 @@ ROSIDL_GENERATOR_C_IMPORT const rosidl_service_type_support_t * ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, @(', '.join(service.structure_type.namespaces + [service.structure_type.name])))(); +@{ +register_function = '_register_srv_type__' + '__'.join(service.structure_type.namespaces[1:] + [type_name]) +register_functions.append(register_function) +}@ int8_t -_register_srv_type__@('__'.join(service.structure_type.namespaces[1:] + [type_name]))(PyObject * pymodule) +@(register_function)(PyObject * pymodule) { int8_t err; PyObject * pyobject_@(function_name) = NULL; From 07594196d7cbb89f53bf6bc51d8fb9960e72eb2d Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Sat, 16 Feb 2019 11:48:24 -0800 Subject: [PATCH 19/26] fix import ts for action messages --- rosidl_generator_py/resource/_msg.py.em | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 94067246..a9c9ecd0 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -55,18 +55,29 @@ suffix = '__'.join(message.structure.type.namespaces[1:]) + '__' + convert_camel cls._TYPE_SUPPORT = module.type_support_msg__@(suffix) cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__@(suffix) @{ +from rosidl_parser.definition import ACTION_FEEDBACK_SUFFIX +from rosidl_parser.definition import ACTION_GOAL_SUFFIX +from rosidl_parser.definition import ACTION_RESULT_SUFFIX importable_typesupports = set() for member in message.structure.members: type_ = member.type if isinstance(type_, NestedType): type_ = type_.basetype if isinstance(type_, NamespacedType): - typename = (*type_.namespaces, type_.name) + if ( + type_.name.endswith(ACTION_GOAL_SUFFIX) or + type_.name.endswith(ACTION_RESULT_SUFFIX) or + type_.name.endswith(ACTION_FEEDBACK_SUFFIX) + ): + action_name, suffix = type_.name.rsplit('_', 1) + typename = (*type_.namespaces, action_name, action_name + '.' + suffix) + else: + typename = (*type_.namespaces, type_.name, type_.name) importable_typesupports.add(typename) }@ @[for typename in sorted(importable_typesupports)]@ - from @('.'.join(typename[:-1])) import @(typename[-1]) + from @('.'.join(typename[:-2])) import @(typename[-2]) if @(typename[-1]).__class__._TYPE_SUPPORT is None: @(typename[-1]).__class__.__import_type_support__() @[end for]@ @@ -306,8 +317,8 @@ 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_.type == 'char']@ - all(ord(val) >= -128 and ord(val) < 128 for val in value)), \ -@{assert_msg_suffixes.append('and each characters ord() in [-128, 127]')}@ + all(val >= 0 and val) < 256 for val in value)), \ +@{assert_msg_suffixes.append('and each char in [0, 255]')}@ @[ else]@ True), \ @[ end if]@ From ff1723e14a38b32c24c51c9a2b7c6f2464652cf7 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Sat, 16 Feb 2019 21:47:31 -0800 Subject: [PATCH 20/26] fix action Python type support --- ...idl_generator_py_generate_interfaces.cmake | 1 + rosidl_generator_py/resource/_action.py.em | 10 +++--- .../_action_pkg_typesupport_entry_point.c.em | 36 +++++++++++++++++++ .../_idl_pkg_typesupport_entry_point.c.em | 9 +++++ 4 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 rosidl_generator_py/resource/_action_pkg_typesupport_entry_point.c.em diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake index 495f9a19..7adbfff2 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -91,6 +91,7 @@ endforeach() set(target_dependencies "${rosidl_generator_py_BIN}" ${rosidl_generator_py_GENERATOR_FILES} + "${rosidl_generator_py_TEMPLATE_DIR}/_action_pkg_typesupport_entry_point.c.em" "${rosidl_generator_py_TEMPLATE_DIR}/_action.py.em" "${rosidl_generator_py_TEMPLATE_DIR}/_idl_pkg_typesupport_entry_point.c.em" "${rosidl_generator_py_TEMPLATE_DIR}/_idl_support.c.em" diff --git a/rosidl_generator_py/resource/_action.py.em b/rosidl_generator_py/resource/_action.py.em index 19cba4dd..fe3caff0 100644 --- a/rosidl_generator_py/resource/_action.py.em +++ b/rosidl_generator_py/resource/_action.py.em @@ -51,14 +51,14 @@ class Metaclass_@(action.structure_type.name)(type): 'Failed to import needed modules for type support:\n' + traceback.format_exc()) else: - cls._TYPE_SUPPORT = module.type_support_srv__@('__'.join(action.structure_type.namespaces[1:]))_@(action_name) + cls._TYPE_SUPPORT = module.type_support_action__@('__'.join(action.structure_type.namespaces[1:]))_@(action_name) from action_msgs.msg import _goal_status_array - if _goal_status_array.Metaclass._TYPE_SUPPORT is None: - _goal_status_array.Metaclass.__import_type_support__() + if _goal_status_array.Metaclass_GoalStatusArray._TYPE_SUPPORT is None: + _goal_status_array.Metaclass_GoalStatusArray.__import_type_support__() from action_msgs.srv import _cancel_goal - if _cancel_goal.Metaclass._TYPE_SUPPORT is None: - _cancel_goal.Metaclass.__import_type_support__() + if _cancel_goal.Metaclass_CancelGoal._TYPE_SUPPORT is None: + _cancel_goal.Metaclass_CancelGoal.__import_type_support__() from @('.'.join(action.structure_type.namespaces)) import @(module_name) if @(module_name).Metaclass_@(action.send_goal_service.structure_type.name)._TYPE_SUPPORT is None: diff --git a/rosidl_generator_py/resource/_action_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_action_pkg_typesupport_entry_point.c.em new file mode 100644 index 00000000..b0e5d6ae --- /dev/null +++ b/rosidl_generator_py/resource/_action_pkg_typesupport_entry_point.c.em @@ -0,0 +1,36 @@ +@# Included from rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em +@ +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +type_name = convert_camel_case_to_lower_case_underscore(action.structure_type.name) +function_name = 'type_support' +}@ + +@{ +register_function = '_register_action_type__' + '__'.join(action.structure_type.namespaces[1:] + [type_name]) +register_functions.append(register_function) +}@ +int8_t +@(register_function)(PyObject * pymodule) +{ + int8_t err; + PyObject * pyobject_@(function_name) = NULL; + pyobject_@(function_name) = PyCapsule_New( + (void *)ROSIDL_TYPESUPPORT_INTERFACE__ACTION_SYMBOL_NAME(rosidl_typesupport_c, @(', '.join(action.structure_type.namespaces + [action.structure_type.name])))(), + NULL, NULL); + if (!pyobject_@(function_name)) { + // previously added objects will be removed when the module is destroyed + return -1; + } + err = PyModule_AddObject( + pymodule, + "@(function_name)_action__@('__'.join(action.structure_type.namespaces[1:] + [type_name]))", + pyobject_@(function_name)); + if (err) { + // the created capsule needs to be decremented + Py_XDECREF(pyobject_@(function_name)); + // previously added objects will be removed when the module is destroyed + return err; + } + return 0; +} diff --git a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em index 84f4a2f3..123bf82b 100644 --- a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em @@ -128,6 +128,15 @@ TEMPLATE( include_directives=include_directives, register_functions=register_functions) }@ + +@{ +TEMPLATE( + '_action_pkg_typesupport_entry_point.c.em', + package_name=package_name, idl_type=action.structure_type, + action=action, typesupport_impl=typesupport_impl, + include_directives=include_directives, + register_functions=register_functions) +}@ @[end for]@ PyMODINIT_FUNC From d760bf08af99b5c05e04f046a9c9e9b7616decdf Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Sat, 16 Feb 2019 22:21:54 -0800 Subject: [PATCH 21/26] fix action type imports --- rosidl_generator_py/resource/_msg.py.em | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index a9c9ecd0..2d961c8a 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -5,6 +5,9 @@ from rosidl_cmake 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 from rosidl_generator_py.generate_py_impl import value_to_py +from rosidl_parser.definition import ACTION_FEEDBACK_SUFFIX +from rosidl_parser.definition import ACTION_GOAL_SUFFIX +from rosidl_parser.definition import ACTION_RESULT_SUFFIX from rosidl_parser.definition import Array from rosidl_parser.definition import BasicType from rosidl_parser.definition import BaseString @@ -55,9 +58,6 @@ suffix = '__'.join(message.structure.type.namespaces[1:]) + '__' + convert_camel cls._TYPE_SUPPORT = module.type_support_msg__@(suffix) cls._DESTROY_ROS_MESSAGE = module.destroy_ros_message_msg__@(suffix) @{ -from rosidl_parser.definition import ACTION_FEEDBACK_SUFFIX -from rosidl_parser.definition import ACTION_GOAL_SUFFIX -from rosidl_parser.definition import ACTION_RESULT_SUFFIX importable_typesupports = set() for member in message.structure.members: type_ = member.type @@ -190,8 +190,15 @@ if isinstance(type_, NestedType): '@(member.name)', @(message.structure.type.name).@(member.name.upper())__DEFAULT) @[ else]@ @[ if isinstance(type_, NamespacedType) and not isinstance(member.type, Sequence)]@ -@# import @('.'.join(type_.namespaces + [type_.name])) +@[ 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) +@[ else]@ from @('.'.join(type_.namespaces)) import @(type_.name) +@[ end if]@ @[ end if]@ @[ if isinstance(member.type, Array)]@ @[ if isinstance(type_, BasicType) and type_.type == 'octet']@ @@ -264,8 +271,15 @@ if member.name in dict(inspect.getmembers(builtins)).keys(): def @(member.name)(self, value): if __debug__: @[ if isinstance(type_, NamespacedType)]@ -@# import @('.'.join(type_.namespaces + [type_.name])) +@[ 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) +@[ else]@ from @('.'.join(type_.namespaces)) import @(type_.name) +@[ end if]@ @[ end if]@ @[ if isinstance(member.type, NestedType)]@ from collections.abc import Sequence From 42adce8677d29eb620830d2145d2db7d1a790945 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Tue, 19 Feb 2019 12:59:35 -0800 Subject: [PATCH 22/26] keep legacy slot types for now --- rosidl_generator_py/resource/_msg.py.em | 2 +- rosidl_generator_py/test/test_interfaces.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rosidl_generator_py/resource/_msg.py.em b/rosidl_generator_py/resource/_msg.py.em index 2d961c8a..bbc5c7c3 100644 --- a/rosidl_generator_py/resource/_msg.py.em +++ b/rosidl_generator_py/resource/_msg.py.em @@ -160,7 +160,7 @@ string@ <@(type_.maximum_size)>@ @[ end if]@ @[ elif isinstance(type_, NamespacedType)]@ -@('::'.join(type_.namespaces + [type_.name]))@ +@('/'.join([type_.namespaces[0], type_.name]))@ @[ end if]@ @# the suffix for nested types @[ if isinstance(member.type, Sequence)]@ diff --git a/rosidl_generator_py/test/test_interfaces.py b/rosidl_generator_py/test/test_interfaces.py index 4ef4b859..16b8403e 100644 --- a/rosidl_generator_py/test/test_interfaces.py +++ b/rosidl_generator_py/test/test_interfaces.py @@ -267,10 +267,10 @@ def test_slot_attributes(): nested_slots = getattr(a, '__slots__') assert len(nested_slot_types_dict) == len(nested_slots) expected_nested_slot_types_dict = { - 'primitives': 'rosidl_generator_py::msg::Primitives', - 'two_primitives': 'rosidl_generator_py::msg::Primitives[2]', - 'up_to_three_primitives': 'sequence', - 'unbounded_primitives': 'sequence', + '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) From 2c5367d3181c069385dfa65f21381af7dfceedab Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Fri, 22 Feb 2019 12:25:12 -0800 Subject: [PATCH 23/26] move template calls --- .../_action_pkg_typesupport_entry_point.c.em | 54 +++++++++++++++++++ .../_idl_pkg_typesupport_entry_point.c.em | 54 ------------------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/rosidl_generator_py/resource/_action_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_action_pkg_typesupport_entry_point.c.em index b0e5d6ae..44d7e301 100644 --- a/rosidl_generator_py/resource/_action_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_action_pkg_typesupport_entry_point.c.em @@ -1,5 +1,59 @@ @# Included from rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em @ +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, idl_type=action.structure_type, + message=action.goal, typesupport_impl=typesupport_impl, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, idl_type=action.structure_type, + message=action.result, typesupport_impl=typesupport_impl, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, idl_type=action.structure_type, + message=action.feedback, typesupport_impl=typesupport_impl, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_srv_pkg_typesupport_entry_point.c.em', + package_name=package_name, idl_type=action.structure_type, + service=action.send_goal_service, typesupport_impl=typesupport_impl, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_srv_pkg_typesupport_entry_point.c.em', + package_name=package_name, idl_type=action.structure_type, + service=action.get_result_service, typesupport_impl=typesupport_impl, + include_directives=include_directives, + register_functions=register_functions) +}@ + +@{ +TEMPLATE( + '_msg_pkg_typesupport_entry_point.c.em', + package_name=package_name, idl_type=action.structure_type, + message=action.feedback_message, typesupport_impl=typesupport_impl, + include_directives=include_directives, + register_functions=register_functions) +}@ + @{ from rosidl_cmake import convert_camel_case_to_lower_case_underscore type_name = convert_camel_case_to_lower_case_underscore(action.structure_type.name) diff --git a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em index 123bf82b..9807270c 100644 --- a/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em +++ b/rosidl_generator_py/resource/_idl_pkg_typesupport_entry_point.c.em @@ -75,60 +75,6 @@ from rosidl_parser.definition import Action }@ @[for action in content.get_elements_of_type(Action)]@ -@{ -TEMPLATE( - '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, idl_type=action.structure_type, - message=action.goal, typesupport_impl=typesupport_impl, - include_directives=include_directives, - register_functions=register_functions) -}@ - -@{ -TEMPLATE( - '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, idl_type=action.structure_type, - message=action.result, typesupport_impl=typesupport_impl, - include_directives=include_directives, - register_functions=register_functions) -}@ - -@{ -TEMPLATE( - '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, idl_type=action.structure_type, - message=action.feedback, typesupport_impl=typesupport_impl, - include_directives=include_directives, - register_functions=register_functions) -}@ - -@{ -TEMPLATE( - '_srv_pkg_typesupport_entry_point.c.em', - package_name=package_name, idl_type=action.structure_type, - service=action.send_goal_service, typesupport_impl=typesupport_impl, - include_directives=include_directives, - register_functions=register_functions) -}@ - -@{ -TEMPLATE( - '_srv_pkg_typesupport_entry_point.c.em', - package_name=package_name, idl_type=action.structure_type, - service=action.get_result_service, typesupport_impl=typesupport_impl, - include_directives=include_directives, - register_functions=register_functions) -}@ - -@{ -TEMPLATE( - '_msg_pkg_typesupport_entry_point.c.em', - package_name=package_name, idl_type=action.structure_type, - message=action.feedback_message, typesupport_impl=typesupport_impl, - include_directives=include_directives, - register_functions=register_functions) -}@ - @{ TEMPLATE( '_action_pkg_typesupport_entry_point.c.em', From 2b38b79375212bedb783a63a38417176c2f59bab Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Fri, 22 Feb 2019 12:35:04 -0800 Subject: [PATCH 24/26] add comment --- .../cmake/rosidl_generator_py_generate_interfaces.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake index 7adbfff2..97b10fe7 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -56,6 +56,8 @@ endforeach() file(MAKE_DIRECTORY "${_output_path}") file(WRITE "${_output_path}/__init__.py" "") +# collect relative paths of directories containing to-be-installed Python modules +# add __init__.py files where necessary set(_generated_py_dirs "") foreach(_generated_py_file ${_generated_py_files}) get_filename_component(_parent_folder "${_generated_py_file}" DIRECTORY) From 2d2eba1d8232f29ad764c2914dbc8108f1283b0a Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Wed, 27 Feb 2019 09:17:57 -0800 Subject: [PATCH 25/26] deterministic order --- rosidl_generator_py/resource/_msg_support.c.em | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rosidl_generator_py/resource/_msg_support.c.em b/rosidl_generator_py/resource/_msg_support.c.em index 23262261..ac639655 100644 --- a/rosidl_generator_py/resource/_msg_support.c.em +++ b/rosidl_generator_py/resource/_msg_support.c.em @@ -93,7 +93,7 @@ if isinstance(member.type, NestedType) and isinstance(member.type.basetype, Name @[end for]@ @[if nested_types]@ // Nested array functions includes -@[ for type_ in nested_types]@ +@[ for type_ in sorted(nested_types)]@ #include "@('/'.join(type_[:-1]))/@(convert_camel_case_to_lower_case_underscore(type_[-1]))__functions.h" @[ end for]@ // end nested array functions include From b6fe934935d39264f8dbac787bd4d5c9219188de Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Thu, 28 Feb 2019 08:52:13 -0800 Subject: [PATCH 26/26] readd explicit dependency on absolute paths of idl files --- .../cmake/rosidl_generator_py_generate_interfaces.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake index 97b10fe7..eb1b6bec 100644 --- a/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake +++ b/rosidl_generator_py/cmake/rosidl_generator_py_generate_interfaces.cmake @@ -41,8 +41,7 @@ foreach(_typesupport_impl ${_typesupport_impls}) set(_generated_extension_${_typesupport_impl}_files "") endforeach() -foreach(_idl_tuple ${rosidl_generate_interfaces_IDL_TUPLES}) - string(REGEX REPLACE ":([^:]*)$" "/\\1" _abs_idl_file "${_idl_tuple}") +foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) get_filename_component(_parent_folder "${_parent_folder}" NAME) get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) @@ -103,6 +102,7 @@ set(target_dependencies "${rosidl_generator_py_TEMPLATE_DIR}/_msg.py.em" "${rosidl_generator_py_TEMPLATE_DIR}/_srv_pkg_typesupport_entry_point.c.em" "${rosidl_generator_py_TEMPLATE_DIR}/_srv.py.em" + ${rosidl_generate_interfaces_ABS_IDL_FILES} ${_dependency_files}) foreach(dep ${target_dependencies}) if(NOT EXISTS "${dep}")